diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fb4370 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +.idea/ +.sass-cache/ +tmp/ +node_modules/ +/build/ +updater/postzip/test +updater/postzip/cmake-build-*/ +updater/postzip/.idea +updater/postzip/TeaClient-linux.tar.gz + +#For the main JS file +*.js.map +*.js + +.deploy_secret + +**/*.d.ts +! +!modules/renderer/imports/.copy_*.d.ts + +package-lock.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d82ef4c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,14 @@ +[submodule "native/codec/libraries/opus"] + path = native/codec/libraries/opus + url = https://github.com/xiph/opus.git +[submodule "native/codec/libraries/speex"] + path = native/codec/libraries/speex + url = https://github.com/xiph/speex.git +[submodule "native/codec/libraries/celt"] + path = native/codec/libraries/celt + url = https://github.com/WolverinDEV/celt-0.11.0.git +[submodule "DbConnector"] + branch = stable +[submodule "github"] + path = github + url = https://github.com/TeaSpeak/TeaClient diff --git a/bugs b/bugs new file mode 100644 index 0000000..b3d0e8b --- /dev/null +++ b/bugs @@ -0,0 +1,27 @@ +Linux: + Updater: + After updater has extracted the file set the executable flag again for the TeaClient binary + + +Windows: + Updater: + Updater popups console which says that there are invalid arguments! Fix this! + Improve access to the update-install.exe (May request admin permissions) + + +General: + Audio replay with TS3 is a bit buggy! + + +Tasks designer: + TeaCup steam animated + Client redesign dark [+ Chat system] + Redesign loading animation (Web) + + + +Notice: +electron-package-manager must be at 8.7.2 (Node 6 support)! + + +FIXME: Test the new voice resampler! \ No newline at end of file diff --git a/build_declarations.sh b/build_declarations.sh new file mode 100755 index 0000000..1406afa --- /dev/null +++ b/build_declarations.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash + +BASEDIR=$(dirname "$0") +cd "${BASEDIR}" + +file_paths=( + "$(pwd ~)/../../Web-Client/shared/declarations" + "$(pwd ~)/TeaSpeak/Web-Client/shared/declarations" + "$(pwd ~)/../../TeaSpeak/Web-Client/shared/declarations" + "app/dummy-declarations" + #TODO Windows path +) +files=( + "exports_app.d.ts;imports_shared.d.ts" + "exports_loader_app.d.ts;imports_shared_loader.d.ts" +# "exports_loader.d.ts;imports_shared_loader.d.ts" +) + +support_rel_linking=$(ln --help 2>&1 | grep -e "--relative" >/dev/null && echo "1" || echo "0") +support_rel_linking=0 + +path_target="./modules/renderer/imports" +{ + mkdir -p "${path_target}" + + for path in "${file_paths[@]}" + do + path_found=1 + for file_mapping in "${files[@]}" + do + file_mapping=($(echo ${file_mapping} | tr ";" " ")) + file=${file_mapping[0]} + + if [[ ! -f "${path}/${file}" ]]; then + path_found=0 + echo "path test ${path} failed to file ${file}" + break + fi + done + [[ path_found -eq 1 ]] || continue + + for file in "${files[@]}" + do + file_mapping=($(echo ${file} | tr ";" "\n")) + src_file=${file_mapping[0]} + dst_file=${file_mapping[1]} + + if [[ -e "${path_target}/${dst_file}" ]] || [[ -L "${path_target}/${dst_file}" ]]; then + rm "${path_target}/${dst_file}" + fi + + + if [[ ${support_rel_linking} -ne 0 ]]; then + ln -rs "${path}/${src_file}" "${path_target}/${dst_file}" + else + _source=$(realpath "${path}/${src_file}") + _current_dir=$(pwd) + cd ${path_target} + [[ $? -ne 0 ]] && { + echo "Failed to enter target directory" + exit 1; + } + ln -s "${_source}" "${dst_file}" + cd ${_current_dir} + fi + echo "Linking \"${path_target}/${dst_file}\" to \"${path}/${src_file}\"" + + cp "${path}/${src_file}" "${path_target}/.copy_${dst_file}" + echo "Create copy \"${path}/${src_file}\" to \"${path_target}/.copy_${dst_file}\"" + done + break + done +} + +if [[ ${path_found} -eq 0 ]]; then + echo "Could not import a link to shared imports. Trying copied import." + + for file in "${files[@]}" + do + file_mapping=($(echo ${file} | tr ";" "\n")) + dst_file=${file_mapping[1]} + + if [[ -e "${path_target}/${dst_file}" ]] || [[ -L "${path_target}/${dst_file}" ]]; then + echo "Hmm target file already exists even thou it hasn't been found yet... Deleting it!" + rm "${path_target}/${dst_file}" + fi + + if [[ ! -e "${path_target}/.copy_${dst_file}" ]]; then + echo "Missing copy of file ${dst_file} because we cant find any valid link!" + exit 1 + fi + + if [[ ${support_rel_linking} -ne 0 ]]; then + ln -rs "${path_target}/.copy_${dst_file}" "${path_target}/${dst_file}" + else + _source=$(realpath "${path_target}/.copy_${dst_file}") + _current_dir=$(pwd) + cd ${path_target} + [[ $? -ne 0 ]] && { + echo "Failed to enter target directory" + exit 1; + } + ln -s "${_source}" "${dst_file}" + cd ${_current_dir} + fi + echo "Linking \"${path_target}/${dst_file}\" to \"${path_target}/.copy_${dst_file}\"" + done + path_found=1 +fi + +if [[ path_found -eq 0 ]]; then + echo "Failed to find UI imports" + echo "Add your path to 'file_paths' and build the declarations first" + exit 1 +fi + +exit 0 \ No newline at end of file diff --git a/github b/github new file mode 160000 index 0000000..14645dc --- /dev/null +++ b/github @@ -0,0 +1 @@ +Subproject commit 14645dca78396c915ad4ad122d532f24fdfd2969 diff --git a/installer/WinInstall.ejs b/installer/WinInstall.ejs new file mode 100644 index 0000000..1794631 --- /dev/null +++ b/installer/WinInstall.ejs @@ -0,0 +1,44 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{0F43B730-DF59-4A23-82AD-E895E72BE4AF} +AppName=TeaSpeak Client +AppVersion=<%= version %> +AppPublisher=TeaSpeak +AppPublisherURL=https://www.teaspeak.com/ +AppSupportURL=https://www.forum.teaspeak.com/ +AppUpdatesURL=https://www.teaspeak.com/ +DefaultDirName={pf}\TeaSpeak +OutputBaseFilename=<%= executable_name %> +OutputDir=<%= dest_dir %> +SetupIconFile=<%= icon_file %> +Compression=lzma +SolidCompression=yes +DisableDirPage=no +DisableWelcomePage=no + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 + +[Files] +Source: "<%= source_dir %>"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs + + +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{commonprograms}\TeaSpeak"; Filename: "{app}\TeaClient.exe" +Name: "{commondesktop}\TeaSpeak"; Filename: "{app}\TeaClient.exe"; Tasks: desktopicon +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\TeaSpeak"; Filename: "{app}\TeaClient.exe"; Tasks: quicklaunchicon + +[Run] +Filename: "{app}\TeaClient.exe"; Description: "{cm:LaunchProgram,TeaSpeak}"; Flags: nowait postinstall skipifsilent + diff --git a/installer/build.ts b/installer/build.ts new file mode 100644 index 0000000..c8849b9 --- /dev/null +++ b/installer/build.ts @@ -0,0 +1,399 @@ +import {Options} from "electron-packager"; +import * as packager from "electron-packager" +const pkg = require('../package.json'); +const dev_dependencies = Object.keys(pkg.devDependencies); + +import * as fs from "fs-extra"; +import * as path_helper from "path"; +import {parse_version} from "../modules/shared/version"; +import * as util from "util"; +import * as child_process from "child_process"; +import * as os from "os"; +import * as asar from "asar"; +import * as querystring from "querystring"; +import request = require("request"); +import * as deployer from "./deploy"; + +let options: Options = {} as any; +let version = parse_version(pkg.version); +version.timestamp = Date.now(); + +options.dir = '.'; +options.name = "TeaClient"; +options.appVersion = pkg.version; +options.appCopyright = "© 2018-2019 Markus Hadenfeldt All Rights Reserved"; +options.out = "build/"; + +if(!pkg.dependencies['electron']) { + console.error("Missing electron version"); + process.exit(1); +} + +options["version-string"] = { + 'CompanyName': 'TeaSpeak', + 'LegalCopyright': '© 2018-2019 Markus Hadenfeldt All Rights Reserved', + 'FileDescription' : 'TeaSpeak-Client', + 'OriginalFilename' : 'TeaClient.exe', + 'FileVersion' : pkg.version, + 'ProductVersion' : pkg.version, + 'ProductName' : 'TeaSpeak-Client', + 'InternalName' : 'TeaClient.exe' +}; +options.electronVersion = pkg.dependencies['electron']; +options.protocols = [{name: "TeaSpeak - Connect", schemes: ["teaserver"]}]; +options.overwrite = true; +options.derefSymlinks = true; +options.buildVersion = version.toString(true); + +options.asar = { + unpackDir: "teaclient-unpacked" +}; + + +interface ProjectEntry { + type: ProjectEntryType; +} + +interface ProjectFile extends ProjectEntry { + path: string; + name: string | RegExp; + + //target_name?: string | ((file: string) => string); +} + +interface ProjectDirectory extends ProjectEntry { + + path: string | RegExp; + children?: boolean; + files?: RegExp; +} + +enum ProjectEntryType { + FILE, + DIRECTORY +} + +const project_files: ProjectEntry[] = []; +{ /* general required files*/ + project_files.push({ + type: ProjectEntryType.FILE, + path: "/", + name: "package.json" + } as ProjectFile); + project_files.push({ + type: ProjectEntryType.FILE, + path: "/", + name: "main.js" + } as ProjectFile); + + project_files.push({ + type: ProjectEntryType.DIRECTORY, + path: "/node_modules", + children: true, + files: /\.(js|css|html|node|json)$/ + } as ProjectDirectory); + + project_files.push({ + type: ProjectEntryType.DIRECTORY, + path: "/node_modules/electron", + children: true, + files: /.*/ + } as ProjectDirectory); +} + +/* TeaClient modules */ +project_files.push({ + type: ProjectEntryType.DIRECTORY, + path: "/modules", + children: true, + files: /.*\.(js|css|html|png|svg)$/ +} as ProjectDirectory); + +/* resource files */ +project_files.push({ + type: ProjectEntryType.DIRECTORY, + path: "/resources" +} as ProjectDirectory); + + +if (process.argv[2] == "linux") { + options.arch = "x64"; + options.platform = "linux"; + options.icon = "resources/logo.svg"; +} else if (process.argv[2] == "win32") { + options.arch = "x64"; + options.platform = "win32"; + options.icon = "resources/logo.ico"; +} else { + console.error("Invalid system"); + process.exit(1); +} + +const path_validator = (path: string) => { + path = path.replace(/\\/g,"/"); + + const IGNORE = true; + const APPEND = false; + + const ppath = path_helper.parse(path); + const is_directory = ppath.ext == '' && fs.statSync(path_helper.join('.', ppath.dir, ppath.name)).isDirectory(); + const directory = (is_directory ? path_helper.join(ppath.dir, ppath.name) : ppath.dir).replace(/\\/g,"/"); + + //console.log("Is directory %o => %s", is_directory, directory); + //console.dir(ppath); + + for(const entry of project_files) { + if(entry.type == ProjectEntryType.DIRECTORY) { + const dir_entry = entry; + + if(typeof(dir_entry.path) === 'string') { + //ppath.dir == dir_entry.path + //console.log("'" + dir_entry.path + "' | '" + directory + "'"); + if(dir_entry.path.startsWith(directory)) { + if(is_directory) + return APPEND; + } + if(directory == dir_entry.path) { + //console.log("Math: " + ppath.base + " to " + dir_entry.files); + if(dir_entry.files) + return ppath.base.match(dir_entry.files) ? APPEND : IGNORE; + return APPEND; + } + if(directory.startsWith(dir_entry.path)) { + if(dir_entry.children) { + if(is_directory) + return APPEND; + + const sub_path = directory.substr(dir_entry.path.length); + //console.log("Sub path: " + sub_path + ". Test: " + (path_helper.join(sub_path, ppath.base) + " against " + dir_entry.files); + + if(dir_entry.files) + return path_helper.join(sub_path, ppath.base).match(dir_entry.files) ? APPEND : IGNORE; + return APPEND; + } + //TODO test for regex + } + } else { + //TODO + } + } else if(entry.type == ProjectEntryType.FILE) { + const file_entry = entry; + if(file_entry.path.startsWith(directory) && is_directory) + return APPEND; + + if(directory == file_entry.path) { + if(typeof(file_entry.name) === 'string' && ppath.base == file_entry.name) + return APPEND; + else if (ppath.base.match(file_entry.name)) + return APPEND; + } + } + } + + return true; +}; + +options.ignore = path => { + if(path.length == 0) return false; //Dont ignore root paths + + const ignore_path = path_validator(path); + if(!ignore_path) { + console.log(" + " + path); + } + return ignore_path; +}; + +async function copy_striped(source: string, target: string, symbol_directory: string) { + const exec = (command, options) => new Promise<{ stdout: Buffer | string, stderr: Buffer | string}>((resolve, reject) => child_process.exec(command, options, (error, out, err) => error ? reject(error) : resolve({stdout: out, stderr: err}))); + + if(process.argv[2] == "win32") { + await fs.copy(source, target); + return; + } + if(process.argv[2] != "linux") throw "invalid target type"; + + await fs.copy(source, target); + + { + const symbols_command = await exec("dump_syms " + target, { + maxBuffer: 1024 * 1024 * 512 + }); + if(symbols_command.stderr.length != 0) { + console.error("Failed to create sys dump: %o", symbols_command.stderr.toString()); + throw "symbol create failed"; + } + + const symbols = symbols_command.stdout.toString(); + const header = symbols.substr(0, symbols.indexOf('\n')); + const binary_name = path_helper.basename(target); + const dump_id = header.split(" ")[3]; + if(binary_name != header.split(" ")[4]) + throw "binary name missmatch"; + + const dump_dir = path_helper.join(symbol_directory, binary_name, dump_id); + const dump_file = path_helper.join(dump_dir, binary_name + ".sym"); + if(!(await fs.pathExists(dump_dir))) + await fs.mkdirp(dump_dir); + await fs.ensureDir(dump_dir); + + console.log("Writing file to %s", dump_file); + await fs.writeFile(dump_file, symbols); + console.log("Created dump file for binary %s (%s).", binary_name, dump_id); + } + + { + console.log("Striping file"); + + //TODO: Keep node module names! + const strip_command = await exec("strip -s " + target, { + maxBuffer: 1024 * 1024 * 512 + }); + if(strip_command.stderr.length != 0) { + console.error("Failed to strip binary: %o", strip_command.stderr.toString()); + throw "strip failed"; + } + + const nm_command = await exec("nm " + target, { + maxBuffer: 1024 * 1024 * 512 + }); + console.log("File stripped. Symbols left: \n%s", nm_command.stderr.toString().trim() || nm_command.stdout.toString().trim()); + } +} +async function create_native_addons(target_directory: string, symbol_directory: string) { + let node_source = "native/build/" + os.platform() + "_" + os.arch() + "/"; + console.log("Native addon path: %s", node_source); + await fs.ensureDir(target_directory); + for(const file of await fs.readdir(node_source)) { + if(!file.endsWith(".node")) { + console.warn("Discovered non node file within node file out dir"); + continue; + } + + await copy_striped(path_helper.join(node_source, file), path_helper.join(target_directory, file), symbol_directory); + } +} + +interface UIVersion { + channel: string; + version: string; + git_hash: string; + timestamp: number; + + required_client?: string; + filename?: string; +} + +async function create_default_ui_pack(target_directory: string) { + const remote_url = "https://clientapi.teaspeak.de/"; + const channel = "release"; + + const file = path_helper.join(target_directory, "default_ui.tar.gz"); + console.log("Creating default UI pack. Downloading from %s (channel: %s)", remote_url, channel); + await fs.ensureDir(target_directory); + + let ui_info: UIVersion; + await new Promise((resolve, reject) => { + request.get(remote_url + "api.php?" + querystring.stringify({ + type: "ui-download", + channel: channel, + version: "latest" + }), { + timeout: 5000 + }).on('response', function(response) { + if(response.statusCode != 200) + reject("Failed to download UI files (Status code " + response.statusCode + ")"); + + ui_info = { + channel: channel, + version: response.headers["x-ui-version"] as string, + git_hash: response.headers["x-ui-git-ref"] as string, + required_client: response.headers["x-ui-required_client"] as string, + timestamp: parseInt(response.headers["x-ui-timestamp"] as string), + filename: path_helper.basename(file) + } + }).on('error', error => { + reject("Failed to download UI files: " + error); + }).pipe(fs.createWriteStream(file)).on('finish', resolve); + }); + + if(!ui_info) + throw "failed to generate ui info!"; + + await fs.writeJson(path_helper.join(target_directory, "default_ui_info.json"), ui_info); + console.log("UI-Pack downloaded!"); +} + +let path; +new Promise((resolve, reject) => packager(options, (err, appPaths) => err ? reject(err) : resolve(appPaths))).then(async app_paths => { + console.log("Copying changelog file!"); + /* We dont have promisify in our build system */ + await fs.copy(path_helper.join(options.dir, "github", "ChangeLog.txt"), path_helper.join(app_paths[0], "ChangeLog.txt")); + return app_paths; +}).then(async app_paths => { + await create_native_addons(path_helper.join(app_paths[0], "resources", "natives"), "build/symbols"); + return app_paths; +}).then(async app_paths => { + await create_default_ui_pack(path_helper.join(app_paths[0], "resources", "ui")); + return app_paths; +}).then(async appPaths => { + ///native/build/linux_amd64 + path = appPaths[0]; + if(process.argv[2] == "linux") { + await copy_striped(options.dir + "/native/build/exe/update-installer", path + "/update-installer", "build/symbols"); + } else if (process.argv[2] == "win32") { + await copy_striped(options.dir + "/native/build/exe/update-installer.exe", path + "/update-installer.exe", "build/symbols"); + } + await fs.writeJson(path + "/app_version.json", { + version: version.toString(true), + timestamp: version.timestamp + }); + return appPaths; +}).then(async app_path => { + console.log("Fixing versions file"); + let version = await fs.readFile(path_helper.join(app_path[0], "version"), 'UTF-8'); + if(!version.startsWith("v")) + version = "v" + version; + await fs.writeFile(path_helper.join(app_path[0], "version"), version); + return app_path; +}).then(async () => { + if(process.argv[2] == "win32") { + console.log("Installing local PDB files"); + + const symbol_binary_path = "native/build/" + os.platform() + "_" + os.arch() + "/"; + const symbol_pdb_path = "native/build/symbols/"; + const symbol_server_path = path_helper.join(__dirname, "..", "native", "build", "symbol-server"); + + const files = []; + for(const file of await fs.readdir(symbol_binary_path)) { + console.error(file); + if(!file.endsWith(".node")) + continue; + let file_name = path_helper.basename(file); + if(file_name.endsWith(".node")) + file_name = file_name.substr(0, file_name.length - 5); + const binary_path = path_helper.join(symbol_binary_path, file); + const pdb_path = path_helper.join(symbol_pdb_path, file_name + ".pdb"); + if(!fs.existsSync(pdb_path)) { + console.warn("Missing PDB file for binary %s", file); + continue; + } + files.push({ + binary: binary_path, + pdb: pdb_path + }); + } + + console.log("Gathered %d files", files.length); + await deployer.deploy_win_dbg_files(files, version, symbol_server_path); + console.log("PDB files deployed"); + } +}).then(() => { + console.log("Package created"); + process.exit(0); +}).catch(error => { + console.error(error); + console.error("Failed to create package!"); + process.exit(1); +}); + +export {} \ No newline at end of file diff --git a/installer/deploy/crash_dumps.ts b/installer/deploy/crash_dumps.ts new file mode 100644 index 0000000..ffbaeae --- /dev/null +++ b/installer/deploy/crash_dumps.ts @@ -0,0 +1,143 @@ +import * as fs from "fs"; +import * as path from "path"; +import * as _node_ssh from "node-ssh"; +import * as ssh2 from "ssh2"; +import * as util from "util"; +import * as crypto from "crypto"; + +declare namespace node_ssh { + export type PutFilesOptions = { + sftp?: Object, + sftpOptions?: Object, + concurrency?: number, + } + export type PutDirectoryOptions = { + sftp?: Object, + sftpOptions?: Object, + concurrency?: number, + recursive?: boolean, + tick?: ((localPath: string, remotePath: string, error?: Error) => void), + validate?: ((localPath: string) => boolean), + } + export type ExecOptions = { + cwd?: string, + options?: Object // passed to ssh2.exec + stdin?: string, + stream?: 'stdout' | 'stderr' | 'both', + onStdout?: ((chunk: Buffer) => void), + onStderr?: ((chunk: Buffer) => void), + } + + export class Instance { + connect(config: ssh2.ConnectConfig): Promise + requestSFTP(): Promise + requestShell(): Promise + mkdir(path: string, method: 'sftp' | 'exec', givenSftp?: Object): Promise + exec(command: string, parameters: Array, options: ExecOptions): Promise + execCommand(command: string, options?: { cwd: string, stdin: string }): Promise<{ stdout: string, options?: Object, stderr: string, signal?: string, code: number }> + putFile(localFile: string, remoteFile: string, sftp?: Object, opts?: Object): Promise + getFile(localFile: string, remoteFile: string, sftp?: Object, opts?: Object): Promise + putFiles(files: Array<{ local: string, remote: string }>, options: PutFilesOptions): Promise + putDirectory(localDirectory: string, remoteDirectory: string, options: PutDirectoryOptions): Promise + dispose(): void + } +} + +let instance: node_ssh.Instance; +export async function setup() { + if(instance) + throw "already initiaized"; + instance = new _node_ssh(); + try { + await instance.connect({ + host: 'deploy.teaspeak.de', + username: 'TeaSpeak-Jenkins-Client', + privateKey: path.join(__dirname, "ssh_key") + }) + } catch(error) { + try { instance.dispose(); } finally { instance = undefined; } + console.error("Failed to connect: %o", error); + throw "failed to connect"; + } +} +async function update_remote_file(local_path: string, remote_path: string) { + if(!instance) + throw "Invalid instance"; + + let sftp: ssh2.SFTPWrapper; + try { + let sha512_remote, sha512_local; + try { + const sha512_remote_result = await instance.execCommand('sha512sum ' + remote_path); + if(sha512_remote_result.code != 0) + sha512_remote = undefined; /* file does not exists! */ + else { + const result = sha512_remote_result.stdout.toString(); + sha512_remote = result.split(" ")[0]; + //console.log("File %s has a remote sha512: %o", remote_path, sha512_remote); + } + } catch(error) { + console.log("Failed to calculate remote sha521 for file %s: %o", remote_path, error); + return; + } + + if(sha512_remote) { /* if the remote hasn't the file then we've def a "new" version */ + const hash_processor = crypto.createHash('sha512'); + const local_stream = fs.createReadStream(local_path); + + await new Promise((resolve, reject) => { + local_stream.on('error', reject); + local_stream.on('data', chunk => hash_processor.update(chunk)); + local_stream.on('end', resolve); + }); + sha512_local = hash_processor.digest('hex'); + local_stream.close(); + } + + if(sha512_remote) { + if(sha512_remote == sha512_local) { + console.log("File %s (%s) is already up to date.", path.basename(local_path), local_path); + return; + } else { + console.log("Updating file %s (%s) at %s. Local sum: %s Remote sum: %s", path.basename(local_path), local_path, remote_path, sha512_local, sha512_remote); + } + } else { + console.log("Uploading file %s (%s) to %s.", path.basename(local_path), local_path, remote_path); + } + + + try { + await instance.putFile(local_path, remote_path); + } catch(error) { + console.error("Failed to upload file %s (%s): %s", path.basename(local_path), local_path, error); + throw "Upload failed"; + } + } finally { + if(sftp) + sftp.end(); + } +} + +export async function deploy_crash_dumps(local_path: string, remote_path: string) { + console.log("Uploading crash dumps from %s to %s", local_path, remote_path); + + const do_dir = async (local_path, remote_path) => { + for(const file of await util.promisify(fs.readdir)(local_path)) { + const local_file = path.join(local_path, file); + const remote_file = remote_path + "/" + file; + + if((await util.promisify(fs.stat)(local_file)).isDirectory()) + await do_dir(local_file, remote_file); + else + await update_remote_file(local_file, remote_file); + } + }; + + await do_dir(local_path, remote_path); +} + +const test = async () => { + await setup(); + await deploy_crash_dumps(path.join(__dirname, "../../build/symbols/"), "symbols"); +}; +test(); \ No newline at end of file diff --git a/installer/deploy/generate_keys.md b/installer/deploy/generate_keys.md new file mode 100644 index 0000000..9e40433 --- /dev/null +++ b/installer/deploy/generate_keys.md @@ -0,0 +1,3 @@ +```$bash +ssh-keygen -t rsa -b 4096 -f ssh_key -N '' +``` \ No newline at end of file diff --git a/installer/deploy/index.ts b/installer/deploy/index.ts new file mode 100644 index 0000000..4230420 --- /dev/null +++ b/installer/deploy/index.ts @@ -0,0 +1,239 @@ +import * as fs from "fs"; +import * as path from "path"; +import * as _node_ssh from "node-ssh"; +import * as ssh2 from "ssh2"; +import * as stream from "stream"; +import * as child_process from "child_process"; +import * as util from "util"; +import {FileEntry} from "ssh2-streams"; + +declare namespace node_ssh { + export type PutFilesOptions = { + sftp?: Object, + sftpOptions?: Object, + concurrency?: number, + } + export type PutDirectoryOptions = { + sftp?: Object, + sftpOptions?: Object, + concurrency?: number, + recursive?: boolean, + tick?: ((localPath: string, remotePath: string, error?: Error) => void), + validate?: ((localPath: string) => boolean), + } + export type ExecOptions = { + cwd?: string, + options?: Object // passed to ssh2.exec + stdin?: string, + stream?: 'stdout' | 'stderr' | 'both', + onStdout?: ((chunk: Buffer) => void), + onStderr?: ((chunk: Buffer) => void), + } + + export class Instance { + connect(config: ssh2.ConnectConfig): Promise + requestSFTP(): Promise + requestShell(): Promise + mkdir(path: string, method: 'sftp' | 'exec', givenSftp?: Object): Promise + exec(command: string, parameters: Array, options: ExecOptions): Promise + execCommand(command: string, options?: { cwd: string, stdin: string }): Promise<{ stdout: string, options?: Object, stderr: string, signal?: string, code: number }> + putFile(localFile: string, remoteFile: string, sftp?: Object, opts?: Object): Promise + getFile(localFile: string, remoteFile: string, sftp?: Object, opts?: Object): Promise + putFiles(files: Array<{ local: string, remote: string }>, options: PutFilesOptions): Promise + putDirectory(localDirectory: string, remoteDirectory: string, options: PutDirectoryOptions): Promise + dispose(): void + } +} + +let instance: node_ssh.Instance; +export async function setup() { + if(instance) + throw "already initiaized"; + instance = new _node_ssh(); + try { + await instance.connect({ + host: 'deploy.teaspeak.de', + username: 'TeaSpeak-Jenkins-Client', + privateKey: path.join(__dirname, "ssh_key") + }) + } catch(error) { + try { instance.dispose(); } finally { instance = undefined; } + console.error("Failed to connect: %o", error); + throw "failed to connect"; + } +} + +function read_stream_full(stream: stream.Readable) : Promise { + return new Promise((resolve, reject) => { + const buffers = []; + stream.on('data', buffer => buffers.push(buffer)); + stream.on('end', () => resolve(Buffer.concat(buffers))); + stream.on('error', error => reject(error)); + }); +} + +export type PlatformSpecs = { + system: 'linux' | 'windows' | 'osx'; + arch: 'amd64' | 'x86'; + type: 'indev' | 'debug' | 'optimized' | 'stable'; +} + +export type Version = { + major: number; + minor: number; + patch: number; + type?: 'indev' | 'beta'; +} + +///_/ +function platform_path(platform: PlatformSpecs) { + return platform.system + "/" + platform.arch + "_" + platform.type + "/"; +} + +function version_string(version: Version) { + return version.major + "." + version.minor + "." + version.patch + (version.type ? "-" + version.type : ""); +} + +export async function latest_version(platform: PlatformSpecs) { + const path = "versions/" + platform_path(platform); + if(!instance) + throw "Invalid instance"; + const sftp = await instance.requestSFTP(); + try { + if(!sftp) + throw "failed to request sftp"; + + try { + const data_stream = sftp.createReadStream(path + "latest"); + const data = await read_stream_full(data_stream); + return data.toString(); + } catch(error) { + if(error instanceof Error && error.message == "No such file") + return undefined; + + console.log("Failed to receive last version: %o", error); + return undefined; + } + } finally { + if(sftp) + sftp.end(); + } +} + +export async function generate_build_index(platform: PlatformSpecs, version: Version) : Promise { + const path = "versions/" + platform_path(platform); + const version_str = version_string(version); + if(!instance) + throw "Invalid instance"; + const sftp = await instance.requestSFTP(); + try { + if(!sftp) + throw "failed to request sftp"; + + try { + const files = await new Promise((resolve, reject) => sftp.readdir(path, (error, result) => error ? reject(error) : resolve(result))); + const version_files = files.filter(e => e.filename.startsWith(version_str)); + if(version_files.length == 0) + return 0; + let index = 1; + while(version_files.find(e => e.filename.toLowerCase() === version_str + "-" + index)) index++; + return index; + } catch(error) { + if(error instanceof Error && error.message == "No such file") + return 0; + + console.log("Failed to receive versions list: %o", error); + return undefined; + } + } finally { + if(sftp) + sftp.end(); + } +} + +export type WinDbgFile = { + binary: string, + pdb: string; +}; +export async function deploy_win_dbg_files(files: WinDbgFile[], version: Version, path?: string) : Promise { + //symstore add /r /f .\*.node /s \\deploy.teaspeak.de\symbols /t "TeaClient-Windows-amd64" /v "x.y.z" + //symstore add /r /f .\*.* /s \\deploy.teaspeak.de\symbols /t "TeaClient-Windows-amd64" /v "1.0.0" + const server_path = typeof(path) === "string" && path ? path : "\\\\deploy.teaspeak.de\\symbols\\symbols"; + const vstring = version_string(version); + const exec = util.promisify(child_process.exec); + for(const file of files) { + console.log("Deploying %s to %s", file, server_path); + let current_file; + try { + { + const result = await exec("symstore add /r /f " + file.binary + " /s " + server_path + " /t \"TeaClient-Windows-amd64\" /v \"" + vstring + "\""); + if(result.stdout) + console.log("Stdout: %s", result.stdout); + if(result.stderr) + console.log("Stderr: %s", result.stderr); + } + { + const result = await exec("symstore add /r /f " + file.pdb + " /s " + server_path + " /t \"TeaClient-Windows-amd64\" /v \"" + vstring + "\""); + if(result.stdout) + console.log("Stdout: %s", result.stdout); + if(result.stderr) + console.log("Stderr: %s", result.stderr); + } + } catch(error) { + if('killed' in error && 'code' in error) { + const perror: { + killed: boolean, + code: number, + signal: any, + cmd: string, + stdout: string, + stderr: string + } = error; + console.error("Failed to deploy %s file %s:", current_file, file); + console.log(" Code: %d", perror.code); + { + console.error(" Stdout: "); + for(const element of perror.stdout.split("\n")) + console.error(" %s", element); + } + { + console.error(" Stderr: "); + for(const element of perror.stderr.split("\n")) + console.error(" %s", element); + } + } else + console.error("Failed to deploy %s file %s: %o", current_file, file, error); + throw "deploy failed"; + } + } +} + +const test = async () => { + await setup(); + console.log(await latest_version({ + arch: 'amd64', + system: 'linux', + type: 'optimized' + })); + console.log(await generate_build_index({ + arch: 'amd64', + system: 'linux', + type: 'optimized' + }, { + type: 'beta', + patch: 19, + minor: 3, + major: 1 + })); + /* + console.log(await deploy_pdb_files( + [path.join(__dirname, "..", "..", "native", "build", "symbols", "teaclient_crash_handler.pdb")], { + type: 'beta', + patch: 19, + minor: 3, + major: 1 + } + )) + */ +}; +test(); \ No newline at end of file diff --git a/installer/deploy/setup_symbol_device.bat b/installer/deploy/setup_symbol_device.bat new file mode 100644 index 0000000..87bc31d --- /dev/null +++ b/installer/deploy/setup_symbol_device.bat @@ -0,0 +1,24 @@ +@echo off + +set drive=T: + + +net use z: /dele > nul +if %ERRORLEVEL% neq 0 ( + if %ERRORLEVEL% neq 2 ( + echo Failed to unmount old drive [%drive%\]: %errorlevel%. + exit /b %errorlevel% + ) else ( + echo Drive [%drive%\] hasn't been mapped. Mapping device! + ) +) else ( + echo Unmounted old device. Mapping new device! +) +rem /persistent:yes +net use z: \\deploy.teaspeak.de\symbols T4j7CTADvCMev4Kr /user:deploy.teaspeak.de\TeaSpeak-Jenkins-Client +if %errorlevel% neq 0 ( + echo Failed to mount drive [%drive%\]: %errorlevel% + exit /b %errorlevel% +) else ( + echo New device has been mapped successfully! +) diff --git a/installer/deploy/ssh_key b/installer/deploy/ssh_key new file mode 100644 index 0000000..593fcb5 --- /dev/null +++ b/installer/deploy/ssh_key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAnr2tvPgMv9uLdFFHCV6sX9uUZyK57cQNHLSVK/OGjdilf95q +RMjI8AkYxM0nc9ljnVNPuhSYWSASTCeCPaBS/VkvUn3krEJQw1Z9GPOWbZo0vLbE +LzhZ8uyCgdOZSuWJpHui4Tchz10pxcKACi5wL4MFaouoJUcGX1MgFJ1Dcd/BxuVj +1hKrOYLBJy1cDuocmP4aTu8mgtzluRMieTjH1fRq7SAbJDx5RmzsEy5S6+6XDuLq +uidXbsoM3GEYhcIHjtBTcbKVsOLmelqR/byGUSFP0tmOLcq85nGuOf0Uccb1DuKA +RDZ53OfsGus2/Gbb0z9nipOtEkP6abgvhas3VNWI+JQ+YhLnwfBPy7hNytQFVN5q +Q0+HaQ1SXdp+Ze3moKPqCHXrlbCvk8FpQoGhzEIteP/xq6DPeHfHZ/T7mH6T8JzF +H3HfGuAfaDMk6f1dg5jHs1L+vaWtWI3SZohj/LeN31TQsPJJbQ9ltK2Eu1hsy9mY +BAXv39yR+os1gpsx5imIQfVMFQ5Fg8W2lNyXjn2S/zWfY76G0vEDOomE4BhMjd2b +Tn2ZzpAba9bPfgmyv6Kjo4mDXv+qVddHzsivKaV3u7bTAYZMpekcEDs7wLPHKC6+ +Ca4Z0jXXEtwAeqW/wqop3Hi5gNruj4+FEWsRvC/431AxXnmyo1WEenx27o0CAwEA +AQKCAgBvKjfsGO2cwhuj5nNPzXv7WSNRIpGAP4ZLLu80K0N0PF6R8GkNKGsHJeex +klXpnDhVaY1wq5GRAJOvvw9HJupXP0iThVRJidtTIFNU0OjsckwyR++VfeoH47b1 +QgCc4agFhwummlxUAlMJic7u0lx/+UomtgyXpmiBAw55QTSFH4RtTCEhPkuoZ7fq +Pqq0SyChx3kXBAU9KYK6m/rNV4UigRsMWiqHss3fEtI0EIHDdX9VznVAzeI91MMy +5dAtg5aVXbDB86U+jXeIAbsxLQAG+sQSzYXy7YJiAwRW2bOihgkBVn8qxdeLauL+ +avBDy6hwBHv3ILnYC8DmnjSxcBi7do/MNIEm5DEs90Lt8Oyh033e+riw7NpLyzY0 +ZFJ/ScfLAzq/UIooCSGIIbpdPs7c8oER6kPj4X5Gv1unh3u9A0ZGGcrDtxS/f/eo +/05ohAFwb31v4KM4eCvHqoaSqKVypFplrslObqxgPQsR/Ecw+gezBAqYmJnbMVRU +8RjNnPGbLulG4HnXxA2dLpqOEU7/FJN7bN8U7rdCqcm/WDbBlVUhNm7jjzDr2OFU +exJMRZvXfRgdqgk59+RPizanRQIMs7GULCtVcJGWlSUfdo2KIuhfFJ/LVIcgm7oo +dFTZVGMOc2KqoRfBnZz6yr74HcexHSlmQZSfIoQhbiiDNexOIQKCAQEA0UMDYrum +FVzkisI0QSdq3h/9KFexYnp4ZYYP83FaZl2js7PAYIIcRcXxVb/i9AJx38FmPH9s +1uMb/PyLGdHGF/qvYrjYqZLZ64eKVlnQGWcU5eOQ9560l8Je5FUfR9IwC3LTG+3R +3QByPANOn19D0GunCJ7cTmwdoedTGPeUxyK7ZTodXn3YHBikLX9atroiRkMe+h4U +fg8R2WV8Hul1PPcVqQ3Lz2aNm1mjfVe+nOghcNrmcI0t03BdXCCTcz3NLTJxwAeC +4TcXlENUo78OcxsZj4hq84xhauN3npT7sa/5JGcC7c7N+EULh/CTH/CK+zsFUYfD +IHC88Vu9fnXcVQKCAQEAwjIHcVkru0apkF65f1AVIyEQJ2sWpndHslAAfSMxEUbL +sMOii5QH5MKA8LRAGpDEoZY2XZrrOpuvnvxKIJt7Ijj4wfYF8ffYTyI0oK7gsR6v +nvY7i+n18pzHZFJLKq5Z9n4zgEi2YBj802v0GfQyCjk3+8we7Man/Uz4jYZr8nxZ +YPy+viBLP5nGp4R7y6nef93prfTL6iApXyr3MdFDMnJBGmiKNGW9UrpKFyFkwvE4 +7sdHUXj2JW/AM8P7CeNA3x2GQ1l0qS8QJ3R0X9GzTeq5tuIKUH2mDrPiBXisRG6k +IYwKb0l8iv7sTLyfMv60T5uUCrS8hompHDtWsh0BWQKCAQBMSOSsEoIaGZIK738D +HW586SZtlYJJxyGqyPN5qKHu3UX3FZkU1XmfCejPfLMshtOiYSt29HDl6Ubjs+C1 +md5gEXfsQjxhnPIqRW/tyLHvAMACijHnwwhMpoPXMxzDHuF62vIQpWKy8R2zuPTp +bl4XVZc/skHXqNwokF6fpGmtKoEsBsJ8Ft44Z9c56spUAIjMGl3pihuoVLAKE0/r +KOofPme8CBZ7VgRbVJMf92O6aXj/Xh1RfHXvNXAjTJDUGvx39IK5IUPZ/C5xUxZA +1z5aQc/Qnkd2338H60JJIkCa5u6pEZBkxtYZInpwpQfNRfA0Y7CtpxM/+Tk3t1ze +A/M9AoIBABmp7Ovg4fOk+gG3UwJtPe3fj7f14g9r0hDRm87t2K000vRwVknl7Ukh +H1MwLwyTtzi3lkW2lIGxU3tKUi2O/q3eI5nWfqCkpXSHy7a0hcNCj+kNF399EuDW +MU+jxIVGd2Mo+HtqoJeAleEG8kJ/0CEjwK9JIYkfE9JY2rwxWJC6OEGmBTsxH2Cv +XN6ElquqrlntpNU1dcFiMLWAAx0VT7EaAlqQGDumeme1cNcvtZZBtMlxko5E0xrN +cvQkYUfEPa1+xGCgMNeu/Y6JSFvlZbHVZGez5bMPd+OXiDY65WFB0fURAcwFRS1F +VUsq3ksp+ABRSjZD/mo1RSETAnkVdjkCggEBAJwC6yt1x9yIAh9RL6AKN2VUAopJ +Ot2vnAp6dHMEwkKQY3hseAJx7YkAb5KaTpEZ50VhXOxe5lOz+4eagXL2CelZG1xN +jDTjIsReQflGn+jwYT1w35u+CPnDCizlA82cLaR5dlaOc/Np3hKWzvc6sAXzjmxN +05+YfB70gbz/u4GE+KFiylArQfJ+2WRxoyUpy3YmbOq7LhadV7GOzYb2ufYgv1cs +US58bqWNx9NXSnJQ1uPDUaaSSfUvGJVJHd602h5m3PLxGIzBFrSsgwx9r6qLXPZ3 +P6XiwAuMOqqEbFfBtJnCxUta9hNoAg4Vo8NV89c92uSFSEJ4xjlKHwOu0U8= +-----END RSA PRIVATE KEY----- diff --git a/installer/deploy/ssh_key.pub b/installer/deploy/ssh_key.pub new file mode 100644 index 0000000..929031c --- /dev/null +++ b/installer/deploy/ssh_key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCeva28+Ay/24t0UUcJXqxf25RnIrntxA0ctJUr84aN2KV/3mpEyMjwCRjEzSdz2WOdU0+6FJhZIBJMJ4I9oFL9WS9SfeSsQlDDVn0Y85ZtmjS8tsQvOFny7IKB05lK5Ymke6LhNyHPXSnFwoAKLnAvgwVqi6glRwZfUyAUnUNx38HG5WPWEqs5gsEnLVwO6hyY/hpO7yaC3OW5EyJ5OMfV9GrtIBskPHlGbOwTLlLr7pcO4uq6J1duygzcYRiFwgeO0FNxspWw4uZ6WpH9vIZRIU/S2Y4tyrzmca45/RRxxvUO4oBENnnc5+wa6zb8ZtvTP2eKk60SQ/ppuC+FqzdU1Yj4lD5iEufB8E/LuE3K1AVU3mpDT4dpDVJd2n5l7eago+oIdeuVsK+TwWlCgaHMQi14//GroM94d8dn9PuYfpPwnMUfcd8a4B9oMyTp/V2DmMezUv69pa1YjdJmiGP8t43fVNCw8kltD2W0rYS7WGzL2ZgEBe/f3JH6izWCmzHmKYhB9UwVDkWDxbaU3JeOfZL/NZ9jvobS8QM6iYTgGEyN3ZtOfZnOkBtr1s9+CbK/oqOjiYNe/6pV10fOyK8ppXe7ttMBhkyl6RwQOzvAs8coLr4JrhnSNdcS3AB6pb/CqinceLmA2u6Pj4URaxG8L/jfUDFeebKjVYR6fHbujQ== wolverindev@WolverinDEV diff --git a/installer/package.ts b/installer/package.ts new file mode 100644 index 0000000..ada188f --- /dev/null +++ b/installer/package.ts @@ -0,0 +1,179 @@ +import * as fs from "fs-extra"; +import * as tar from "tar-stream"; +import * as zlib from "zlib"; +import * as path from "path"; +import * as asar from "asar"; + +import {Pack} from "tar-stream"; +import * as request from "request"; +import {Version} from "../modules/shared/version"; + +async function append_dir(parent: string, path: string, pack: Pack, excludes: (string | RegExp)[]) { + const entries = await fs.readdir(parent + "/" + path); + for(let entry of entries) { + console.log(entry); + const stat = await fs.stat(parent + "/" + path + "/" + entry); + if(stat.isDirectory()) { + console.log("Add sub: %s", entry); + await append_dir(parent, path + "/" + entry, pack, excludes); + } else { + let exclude = false; + for(const pattern of excludes) { + if((path + "/" + entry).match(pattern)) { + console.log("Excluding file %s", path + "/" + entry); + exclude = true; + break; + } + } + if(exclude) continue; + + let pentry = pack.entry({ + name: path + "/" + entry, + size: stat.size, + mode: stat.mode + }, error => { + if(error) throw error; + }); + + if(!pentry) throw "Failed to create new file"; + + const pipe = fs.createReadStream(parent + "/" + path + "/" + entry).pipe(pentry); + + await new Promise((resolve, reject) => { + pipe.on('finish', resolve); + pipe.on('error', reject); + }); + pentry.end(); + } + } +} + +export async function pack_update(source: string, dest: string) : Promise { + await fs.mkdirs(path.dirname(dest)); + const target = fs.createWriteStream(dest); + const pack = tar.pack(); + const compress = zlib.createGzip(); + + pack.pipe(compress).pipe(target); + + await append_dir(source, ".", pack, [/.\/app_versions\/.*/]); ///.\/postzip($|.exe)/, + pack.finalize(); + + await new Promise((resolve, reject) => { + target.on('close', resolve); + target.on('error', reject); + }); + + return dest; +} + +export async function pack_info(src: string) : Promise { + const appAsarPath = path.join(src, 'resources/app.asar'); + const appPackageJSONPath = path.join(src, 'resources/app/package.json'); + + if(await fs.pathExists(appAsarPath)) + return JSON.parse(asar.extractFile(appAsarPath, "package.json")); + else + return await fs.readJson(appPackageJSONPath); +} + +interface InfoEntry { + platform: string; + arch: string; + update: string; + install: string; +} + +export async function write_info(file: string, platform: string, arch: string, update_file: string, install_file: string) { + let infos: InfoEntry[] = fs.existsSync(file) ? await fs.readJson(file) as InfoEntry[] : []; + for(const entry of infos.slice()) { + if(entry.platform == platform && entry.arch == arch) + infos.splice(infos.indexOf(entry),1); + } + infos.push({ + "platform": platform, + "arch": arch, + "update": update_file, + "install": install_file + }); + await fs.writeJson(file, infos); +} + +interface VersionFile { + release: VersionEntry[]; + beta: VersionEntry[]; +} + +interface VersionEntry { + platform: string; + arch: string; + version: Version; +} +export async function write_version(file: string, platform: string, arch: string, channel: string, version: Version) { + let versions: VersionFile = fs.existsSync(file) ? await fs.readJson(file) as VersionFile : {} as any; + + versions[channel] = versions[channel] || []; + let channel_data = versions[channel]; + + for(const entry of channel_data.slice()) { + if(entry.platform == platform && entry.arch == arch) + channel_data.splice(channel_data.indexOf(entry), 1); + } + + channel_data.push({ + platform: platform, + arch: arch, + version: version + }); + await fs.writeJson(file, versions); +} +export async function deploy(platform: string, arch: string, channel: string, version: Version, update_file: string, install_file: string, install_suffix: string) { + await new Promise((resolve, reject) => { + const url = (process.env["teaclient_deploy_url"] || "http://clientapi.teaspeak.de/") + "api.php"; + console.log("Requesting " + url); + console.log("Uploading update file " + update_file); + console.log("Uploading install file " + install_file); + console.log("Secret (env key: teaclient_deploy_secret): " + process.env["teaclient_deploy_secret"]); + if(!process.env["teaclient_deploy_secret"]) throw "Missing secret!"; + + + request.post(url, { + formData: { + type: "deploy-build", + secret: process.env["teaclient_deploy_secret"], + + platform: platform, + arch: arch, + version: JSON.stringify(version), + channel: channel, + + update: fs.createReadStream(update_file), + update_suffix: "tar.gz", + + installer: fs.createReadStream(install_file), + installer_suffix: install_suffix + } + }, (error, response, body) => { + if(error) { + console.error("Failed to upload:"); + console.error(error); + throw "Failed to upload: " + error; + } + console.log("Response code: " + (response ? response.statusCode : 0)); + let info; + if(response && response.statusCode == 413) { + info = {msg: "Files too large! Increase limits!"}; + } else { + try { + info = JSON.parse(body); + } catch (error) { + info = {}; + console.dir(body); + } + } + console.dir(info); + if(!info["success"]) throw info["msg"] || "Could not deploy files!"; + resolve(); + }); + }) +} \ No newline at end of file diff --git a/installer/package_linux.ts b/installer/package_linux.ts new file mode 100644 index 0000000..a1bd7eb --- /dev/null +++ b/installer/package_linux.ts @@ -0,0 +1,78 @@ +const installer = require("electron-installer-debian"); +import * as packager from "./package"; +import {parse_version, Version} from "../modules/shared/version"; + +const package_path = "build/TeaClient-linux-x64/"; +const filename_update = "TeaClient-linux-x64.tar.gz"; + +let options = { + src: package_path, + dest: undefined, + dest_file: undefined, + arch: 'amd64', + + rename: (directory, name) => { + console.log("Destination directory: " + directory); + console.log("Destination name : " + name); + options.dest_file = directory + "/" + name; + return directory + "/" + name; + }, + options: { + name: "TeaClient", + productName: "TeaClient", + genericName: "TeaSpeak - Client", + description: "TeaClient by TeaSpeak", + version: undefined, + homepage: "https://teaspeak.de", + maintainer: "WolverinDEV ", + + icon: 'resources/logo.svg', + categories: [ + "Utility" + ], + bin: 'TeaClient' + } +}; + +if(process.argv.length < 3) { + console.error("Missing build channel!"); + process.exit(1); +} + +let version: Version; +const alive = setInterval(() => {}, 1000); +packager.pack_info(package_path).then(package_info => { + options.options.version = (version = parse_version(package_info["version"])).toString(); + options.dest = "build/output/" + process.argv[2] + "/" + options.options.version + "/"; + console.log('Creating package for version ' + options.options.version + ' (this may take a while)'); + + //return Promise.resolve(); + return installer(options); +}).then(() => { + if(!options.dest_file) + options.dest_file = options.dest + "TeaClient_" + options.options.version + "_amd64.deb"; + + console.log(`Successfully created package at ${options.dest} (${options.dest_file})`); + return packager.pack_update(options.src, options.dest + "/" + filename_update); +}).then(() => { + return packager.write_info(options.dest + "info.json", "linux", "x64", filename_update, options.dest_file) +}).then(() => { + return packager.write_version("build/output/version.json", "linux", "x64", process.argv[2], version); +}).then(() => { + console.log("Deploying symbol files"); + //FIXME! +}).then(() => { + //Fixup in case of skip of the packaging + + console.log("Deploying build"); + return packager.deploy("linux", "x64", process.argv[2], version, options.dest + filename_update, options.dest_file, "deb"); +}).then(() => { + console.log("Build version (" + options.options.version + ") created!"); + clearInterval(alive); +}) +.catch(err => { + console.error("Failed to pack package!"); + console.error(err, err.stack); + process.exit(1) +}); + diff --git a/installer/package_windows.ts b/installer/package_windows.ts new file mode 100644 index 0000000..5c827ae --- /dev/null +++ b/installer/package_windows.ts @@ -0,0 +1,88 @@ +import * as packager from "./package"; +import * as deployer from "./deploy"; +import {parse_version, Version} from "../modules/shared/version"; + +const fs = require("fs-extra"); +const path = require("path"); +const util = require('util'); +const cproc = require('child_process'); +const proc = require('process'); +const ejs = require('ejs'); +const exec = util.promisify(cproc.exec); +const ejs_render = util.promisify(ejs.renderFile); + +const filename_update = "TeaClient-windows-x64.tar.gz"; +const filename_installer = "TeaClient-windows-x64.exe"; +const package_path = "build/TeaClient-win32-x64/"; +const symbol_pdb_path = "native/build/symbols/"; +const symbol_binary_path = package_path + "/resources/natives/"; +let dest_path = undefined; +let info; +let version: Version; +async function make_template() : Promise { + const content = await ejs_render("installer/WinInstall.ejs", { + source_dir: path.resolve(package_path) + "/*", + dest_dir: path.resolve(dest_path), + icon_file: path.resolve("resources/logo.ico"), + version: info["version"], + executable_name: filename_installer.substr(0, filename_installer.length - 4) //Remove the .exe + }, {}); + + await fs.mkdirs(dest_path); + fs.writeFileSync(dest_path + "/" + "installer.iss", content); + return dest_path + "/" + "installer.iss"; +} + +async function make_installer(path: string) { + console.log("Compiling path %s", path); + const { stdout, stderr } = await exec("\"C:\\Program Files (x86)\\Inno Setup 5\\iscc.exe\" " + path, {maxBuffer: 1024 * 1024 * 1024}); //FIXME relative path? +} +if(process.argv.length < 3) { + console.error("Missing build channel!"); + process.exit(1); +} + +packager.pack_info(package_path).then(async _info => { + info = _info; + version = parse_version(_info["version"]); + dest_path = "build/output/" + process.argv[2] + "/" + version.toString() + "/"; + await packager.pack_update(package_path, dest_path + "TeaClient-windows-x64.tar.gz"); +}).then(async () => { + await packager.write_info(dest_path + "info.json", "win32", "x64", filename_update, filename_installer) +}).then(async () => { + await packager.write_version("build/output/version.json", "win32", "x64", process.argv[2], version); +}).then(async () => await make_template()) +.then(async path => await make_installer(path)) +.then(async () => { + console.log("Deploying PDB files"); + const files = []; + for(const file of await fs.readdir(symbol_binary_path)) { + if(!file.endsWith(".node")) + continue; + let file_name = path.basename(file); + if(file_name.endsWith(".node")) + file_name = file_name.substr(0, file_name.length - 5); + const binary_path = path.join(symbol_binary_path, file); + const pdb_path = path.join(symbol_pdb_path, file_name + ".pdb"); + if(!fs.existsSync(pdb_path)) { + console.warn("Missing PDB file for binary %s", file); + continue; + } + files.push({ + binary: binary_path, + pdb: pdb_path + }); + } + await deployer.deploy_win_dbg_files(files, version); + console.log("PDB files deployed"); +}) +.then(async () => { + console.log("Deploying build"); + await packager.deploy("win32", "x64", process.argv[2], version, dest_path + filename_update, dest_path + filename_installer, "exe"); +}).then(() => { + console.log("Succeed"); + proc.exit(0); +}).catch(error => { + console.log(error); + proc.exit(1); +}); diff --git a/installer/tsconfig_linux.json b/installer/tsconfig_linux.json new file mode 100644 index 0000000..87dbbc8 --- /dev/null +++ b/installer/tsconfig_linux.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "sourceMap": true, + "moduleResolution": "node" + }, + "include": [ + "./deploy/", + "build.ts", + "package.ts", + "package_linux.ts" + ] +} \ No newline at end of file diff --git a/installer/tsconfig_windows.json b/installer/tsconfig_windows.json new file mode 100644 index 0000000..4001168 --- /dev/null +++ b/installer/tsconfig_windows.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "sourceMap": true, + "moduleResolution": "node" + }, + "include": [ + "./deploy/", + "build.ts", + "package.ts", + "package_windows.ts" + ] +} diff --git a/jenkins/create_build.sh b/jenkins/create_build.sh new file mode 100755 index 0000000..5b159a4 --- /dev/null +++ b/jenkins/create_build.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash + +cd "$(dirname $0)/../" + +project_name="__build_teaclient" +source ../scripts/build_helper.sh + +function install_npm() { + begin_task "${project_name}_update" "Installing NPM" + npm install --save-dev + check_err_exit ${project_name} "Failed to install nodejs files!" + npm run install-platform + check_err_exit ${project_name} "Failed to install platform depend nodejs files!" + + npm update + check_err_exit ${project_name} "Failed to update nodejs files!" + end_task "${project_name}_update" "NPM installed" +} + +function compile_scripts() { + begin_task "${project_name}_tsc_sass" "Compiling TypeScript & SASS" + ./build_declarations.sh + check_err_exit ${project_name} "Failed to build shared ui import declarations!" + + npm run compile-tsc -- -p modules/tsconfig_main.json + check_err_exit ${project_name} "Failed to compile typescript main files!" + npm run compile-tsc -- -p modules/tsconfig_renderer.json + check_err_exit ${project_name} "Failed to compile typescript renderer files!" + + if [[ ${build_os_type} == "win32" ]]; then + npm run compile-tsc -- -p installer/tsconfig_windows.json + check_err_exit ${project_name} "Failed to compile typescript installer files!" + else + npm run compile-tsc -- -p installer/tsconfig_linux.json + check_err_exit ${project_name} "Failed to compile typescript installer files!" + fi + + npm run compile-sass + check_err_exit ${project_name} "Failed to compile sass files!" + end_task "${project_name}_tsc_sass" "TypeScript & SASS compiled" + echo "" +} + +function compile_native() { + begin_task "${project_name}_native" "Compiling native extensions" + + local build_path="native/out/${build_os_type}_${build_os_arch}/" + [[ -d ${build_path} ]] && rm -r ${build_path} + mkdir -p ${build_path} + check_err_exit ${project_name} "Failed to create build directory!" + + cd ${build_path} + check_err_exit ${project_name} "Failed to enter build directory!" + + local _arguments="" + [[ ! -z "$tearoot_cmake_module" ]] && _arguments="${_arguments} -DCMAKE_MODULE_PATH=\"$tearoot_cmake_module\"" + [[ ! -z "$tearoot_cmake_config" ]] && _arguments="${_arguments} -DCMAKE_PLATFORM_INCLUDE=\"$tearoot_cmake_config\"" + [[ ! -z "$traroot_library" ]] && _arguments="${_arguments} -DLIBRARY_PATH=\"$traroot_library\"" + + local _generator="" + [[ ${build_os_type} == "win32" ]] && _generator='-G"Visual Studio 15 2017 Win64"' + + _command="cmake ../../ ${_generator} -DCMAKE_BUILD_TYPE=RelWithDebInfo ${_arguments}" + echo "Executing cmake command $_command" + + eval ${_command} + check_err_exit ${project_name} "Failed create build targets!" + + cmake --build `pwd` --target update_installer -- ${CMAKE_MAKE_OPTIONS} + check_err_exit ${project_name} "Failed build teaclient update installer!" + + cmake --build `pwd` --target teaclient_connection -- ${CMAKE_MAKE_OPTIONS} + check_err_exit ${project_name} "Failed build teaclient connection!" + + cmake --build `pwd` --target teaclient_crash_handler -- ${CMAKE_MAKE_OPTIONS} + check_err_exit ${project_name} "Failed build teaclient crash handler!" + + cmake --build `pwd` --target teaclient_ppt -- ${CMAKE_MAKE_OPTIONS} + check_err_exit ${project_name} "Failed build teaclient ppt!" + + cmake --build `pwd` --target teaclient_dns -- ${CMAKE_MAKE_OPTIONS} + check_err_exit ${project_name} "Failed to build teaclient dns!" + + end_task "${project_name}_native" "Native extensions compiled" +} + +function package_client() { + begin_task "${project_name}_package" "Packaging client" + if [[ ${build_os_type} == "win32" ]]; then + npm run build-windows-64 + check_err_exit ${project_name} "Failed to package client!" + else + npm run build-linux-64 + check_err_exit ${project_name} "Failed to package client!" + fi + end_task "${project_name}_package" "Client package created" +} + +function deploy_client() { + begin_task "${project_name}_package" "Deploying client" + [[ -z ${teaclient_deploy_secret} ]] && { + echo "Missing deploy secret. Dont deploy client!" + return 0 + } + [[ -z ${teaclient_deploy_channel} ]] && { + echo "Missing deploy channel. Dont deploy client!" + return 0 + } + + if [[ ${build_os_type} == "win32" ]]; then + npm run package-windows-64 ${teaclient_deploy_channel} + check_err_exit ${project_name} "Failed to deploying client!" + else + npm run package-linux-64 ${teaclient_deploy_channel} + check_err_exit ${project_name} "Failed to deploying client!" + fi + end_task "${project_name}_package" "Client successfully deployed!" +} + +#install_npm +#compile_scripts +#compile_native +#package_client +deploy_client diff --git a/libraries.txt b/libraries.txt new file mode 100644 index 0000000..3a2daa6 --- /dev/null +++ b/libraries.txt @@ -0,0 +1,11 @@ +https://git.assembla.com/portaudio.git +https://github.com/WolverinDEV/libfvad + + +git clone https://git.code.sf.net/p/soxr/code soxr +mkdir -p out/linux_x64 +cd out/linux_x674 + +cmake ../../ -DWITH_OPENMP=OFF -DBUILD_TESTS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_FLAGS="-fPIC" +make -j 12 +sudo make install \ No newline at end of file diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..c0cf6c6 --- /dev/null +++ b/main.ts @@ -0,0 +1,31 @@ +import * as electron from "electron"; +import * as os from "os"; + +{ + const app_path = electron.app.getAppPath(); + console.log("Native module path: %s", app_path + "/native/build/" + os.platform() + "_" + os.arch() + "/"); +} + +import * as crash_handler from "./modules/crash_handler"; + +const is_electron_run = process.argv[0].endsWith("electron") || process.argv[0].endsWith("electron.exe"); +const process_arguments = is_electron_run ? process.argv.slice(2) : process.argv.slice(1); +if(process_arguments.length > 0 && process_arguments[0] === "crash-handler") { + /* crash handler callback */ + crash_handler.handle_crash_callback(process_arguments.slice(1)); +} else { + if(process_arguments.length > 0 && process_arguments[0] == "--main-crash-handler") + crash_handler.initialize_handler("main", is_electron_run); + /* app execute */ + { + const versions = process.versions; + console.log("Versions:"); + console.log(" TeaSpeak Client: " + electron.app.getVersion()); + + for (const key of Object.keys(versions)) + console.log(" %s: %s", key, versions[key]); + } + + const tea_client = require("./modules/core/main.js"); + tea_client.execute(); +} \ No newline at end of file diff --git a/modules/core/app-updater/changelog/index.ts b/modules/core/app-updater/changelog/index.ts new file mode 100644 index 0000000..45a7a9b --- /dev/null +++ b/modules/core/app-updater/changelog/index.ts @@ -0,0 +1,42 @@ +import {BrowserWindow} from "electron"; +import * as electron from "electron"; +import * as path from "path"; + +let changelog_window: BrowserWindow; +export function open() { + if(changelog_window) { + changelog_window.focus(); + return; + } + + changelog_window = new BrowserWindow({ + show: false + }); + + changelog_window.setMenu(null); + + let file = ""; + { + const app_path = electron.app.getAppPath(); + if(app_path.endsWith(".asar")) + file = path.join(path.dirname(app_path), "..", "ChangeLog.txt"); + else + file = path.join(app_path, "github", "ChangeLog.txt"); /* We've the source master :D */ + } + + changelog_window.loadFile(file); + changelog_window.setTitle("TeaClient ChangeLog"); + changelog_window.on('ready-to-show', () => { + changelog_window.show(); + }); + changelog_window.on('close', () => { + changelog_window = undefined; + }); +} + +export function close() { + if(changelog_window) { + changelog_window.close(); + changelog_window = undefined; + } +} \ No newline at end of file diff --git a/modules/core/app-updater/index.ts b/modules/core/app-updater/index.ts new file mode 100644 index 0000000..6c93388 --- /dev/null +++ b/modules/core/app-updater/index.ts @@ -0,0 +1,863 @@ +import * as querystring from "querystring"; +import * as request from "request"; +import {app, dialog, ipcMain} from "electron"; +import * as fs from "fs-extra"; +import * as ofs from "original-fs"; +import * as os from "os"; +import * as tar from "tar-stream"; +import * as path from "path"; +import * as zlib from "zlib"; +import * as child_process from "child_process"; +import * as progress from "request-progress"; +import * as util from "util"; + +import {parse_version, Version} from "../../shared/version"; + +import Timer = NodeJS.Timer; +import MessageBoxOptions = Electron.MessageBoxOptions; +import {Headers} from "tar-stream"; +import {Arguments, process_args} from "../../shared/process-arguments"; +import * as electron from "electron"; +import {PassThrough} from "stream"; +import * as _main_windows from "../main_window"; +import ErrnoException = NodeJS.ErrnoException; +import {EPERM} from "constants"; +import * as winmgr from "../window"; + +const is_debug = false; +export function server_url() : string { + const default_path = is_debug ? "http://localhost/home/TeaSpeak/TeaSpeak/Web-Client/client-api/environment/" : "http://clientapi.teaspeak.de/"; + return process_args.has_value(...Arguments.SERVER_URL) ? process_args.value(...Arguments.SERVER_URL) : default_path; +} + +export interface UpdateVersion { + channel: string; + platform: string, + arch: string; + version: Version; +} + +export interface UpdateData { + versions: UpdateVersion[]; + updater_version: UpdateVersion; +} + +let version_cache: UpdateData = undefined; +export async function load_data(allow_cached: boolean = true) : Promise { + if(version_cache && allow_cached) return Promise.resolve(version_cache); + + return new Promise((resolve, reject) => { + const request_url = server_url() + "/api.php?" + querystring.stringify({ + type: "update-info" + }); + console.log("request: %s", request_url); + request.get(request_url, { + timeout: 2000 + }, (error, response, body) => { + if(!response || response.statusCode != 200) { + let info; + try { + info = JSON.parse(body) || {msg: error}; + } catch(e) { + info = {msg: "!-- failed to parse json --!"}; + } + setImmediate(reject, "Invalid status code (" + (response || {statusCode: -1}).statusCode + " | " + (info || {msg: "undefined"}).msg + ")"); + return; + } + const data = JSON.parse(body); + if(!data) { + setImmediate(reject, "Invalid response"); + return; + } + if(!data["success"]) { + setImmediate(reject, "Action failed (" + data["msg"] + ")"); + return; + } + + let resp: UpdateData = {} as any; + resp.versions = []; + for(const channel of Object.keys(data)) { + if(channel == "success") continue; + + for(const entry of data[channel]) { + let version: UpdateVersion = {} as any; + version.channel = channel; + version.arch = entry["arch"]; + version.platform = entry["platform"]; + version.version = new Version(entry["version"]["major"], entry["version"]["minor"], entry["version"]["patch"], entry["version"]["build"], entry["version"]["timestamp"]); + if(version.channel == 'updater') + resp.updater_version = version; + else + resp.versions.push(version); + } + } + resolve(resp); + }); + }); +} + +export async function newest_version(current_version: Version, channel?: string) : Promise { + if(!app.getAppPath().endsWith(".asar")) { + throw "You cant run an update when you're executing the source code!"; + } + const data = await load_data(); + let had_data = false; + for(const version of data.versions) { + if(version.arch == os.arch() && version.platform == os.platform()) { + if(!channel || version.channel == channel) { + if(!current_version || version.version.newer_than(current_version)) + return version; + else + had_data = true; + } + } + } + + if(!had_data) + throw "Missing data"; + return undefined; +} + +export async function extract_updater(update_file: string) { + if(!fs.existsSync(update_file)) throw "Missing update file!"; + + + let parent_path = app.getAppPath(); + if(parent_path.endsWith(".asar")) { + parent_path = path.join(parent_path, "..", ".."); + parent_path = fs.realpathSync(parent_path); + } + + let post_path; + if(os.platform() == "linux") + post_path = parent_path + "/update-installer"; + else + post_path = parent_path + "/update-installer.exe"; + + const source = fs.createReadStream(update_file); + const extract = tar.extract(); + await new Promise(resolve => { + let updater_found = false; + source.on('end', () => { + if(!updater_found) { + console.error("Failed to extract the updater (Updater hasn't been found!)"); + resolve(); //FIXME use reject! + } + resolve(); + }); + + extract.on('entry', (header: Headers, stream, callback) => { + stream.on('end', callback); + console.log("Got entry " + header.name); + + if(header.name == "./update-installer" || header.name == "./update-installer.exe") { + console.log("Found updater! (" + header.size + ")"); + console.log("Extracting to %s", post_path); + const s = fs.createWriteStream(post_path); + stream.pipe(s).on('finish', event => { + console.log("Updater extracted and written!"); + updater_found = true; + resolve(); + }); + } else { + stream.resume(); //Drain the stream + } + }); + + + source.pipe(extract); + }); +} + +export async function update_updater() : Promise { + //TODO here + return Promise.resolve(); +} + +function data_directory() : string { + return electron.app.getPath('userData'); +} + +function get_update_file(channel: string, version: Version) : string { + let _path = fs.realpathSync(data_directory()); + + const name = channel + "_" + version.major + "_" + version.minor + "_" + version.patch + "_" + version.build + ".tar"; + return path.join(_path, "app_versions", name); +} + +export interface ProgressState { + percent: number, // Overall percent (between 0 to 1) + speed: number, // The download speed in bytes/sec + size: { + total: number, // The total payload size in bytes + transferred: number// The transferred payload size in bytes + }, + time: { + elapsed: number,// The total elapsed seconds since the start (3 decimals) + remaining: number // The remaining seconds to finish (3 decimals) + } +} + +export async function download_version(channel: string, version: Version, status?: (state: ProgressState) => any) : Promise { + const target_path = get_update_file(channel, version); + console.log("Downloading version %s to %s", version.toString(false), target_path); + if(fs.existsSync(target_path)) { + /* TODO test if this file is valid and can be used */ + try { + await fs.remove(target_path); + } catch(error) { + throw "Failed to remove old file: " + error; + } + } + + try { + await fs.mkdirp(path.dirname(target_path)); + } catch(error) { + throw "Failed to make target directory: " + path.dirname(target_path); + } + + const url = server_url() + "/api.php?" + querystring.stringify({ + type: "update-download", + platform: os.platform(), + arch: os.arch(), + version: version.toString(), + channel: channel + }); + console.log("Downloading update from %s. (%s)", server_url(), url); + return new Promise((resolve, reject) => { + let fired = false; + let stream = progress(request.get(url, { + timeout: 2000 + }, (error, response, body) => { + if(!response || response.statusCode != 200) { + let info; + try { + info = JSON.parse(body) + } catch(e) { + info = {"msg": "!-- failed to parse json --!"}; + } + if(!fired && (fired = true)) + setImmediate(reject, "Invalid status code (" + (response || {statusCode: -1}).statusCode + "|" + (info || {"msg": "undefined"}).msg + ")"); + return; + } + })).on('progress', _state => status ? status(_state) : {}).on('error', error => { + console.warn("Encountered error within download pipe. Ignoring error: %o", error); + }).on('end', function () { + console.log("Update downloaded successfully. Waiting for write stream to finish."); + if(status) + status({ + percent: 1, + speed: 0, + size: { total: 0, transferred: 0}, + time: { elapsed: 0, remaining: 0} + }) + }); + + console.log("Decompressing update package while streaming!"); + stream = stream.pipe(zlib.createGunzip()); + stream.pipe(fs.createWriteStream(target_path, { + autoClose: true + })).on('finish', () => { + console.log("Write stream has finished. Download successfully."); + if(!fired && (fired = true)) + setImmediate(resolve, target_path); + }).on('error', error => { + console.log("Write stream encountered an error while downloading update. Error: %o", error); + if(!fired && (fired = true)) + setImmediate(reject,"failed to write"); + }); + }); +} + +if(typeof(String.prototype.trim) === "undefined") +{ + String.prototype.trim = function() + { + return String(this).replace(/^\s+|\s+$/g, ''); + }; +} + +export async function test_file_accessibility(update_file: string) : Promise { + if(os.platform() === "win32") + return []; /* within windows the update installer request admin privileges if required */ + + const original_fs = require('original-fs'); + if(!fs.existsSync(update_file)) + throw "Missing update file (" + update_file + ")"; + + let parent_path = app.getAppPath(); + if(parent_path.endsWith(".asar")) { + parent_path = path.join(parent_path, "..", ".."); + parent_path = fs.realpathSync(parent_path); + } + + const test_access = async (file: string, mode: number) => { + return await new Promise(resolve => original_fs.access(file, mode, resolve)); + }; + + let code = await test_access(update_file, original_fs.constants.R_OK); + if(code) + throw "Failed test read for update file. (" + update_file + " results in " + code.code + ")"; + + const fstream = original_fs.createReadStream(update_file); + const tar_stream = tar.extract(); + + const errors: string[] = []; + const tester = async (header: Headers) => { + const entry_path = path.normalize(path.join(parent_path, header.name)); + if(header.type == "file") { + if(original_fs.existsSync(entry_path)) { + code = await test_access(entry_path, original_fs.constants.W_OK); + if(code) + errors.push("Failed to acquire write permissions for file " + entry_path + " (Code " + code.code + ")"); + } else { + let directory = path.dirname(entry_path); + while(directory.length != 0 && !original_fs.existsSync(directory)) + directory = path.normalize(path.join(directory, "..")); + + code = await test_access(directory, original_fs.constants.W_OK); + if(code) errors.push("Failed to acquire write permissions for directory " + entry_path + " (Code " + code.code + ". Target directory " + directory + ")"); + } + } else if(header.type == "directory") { + let directory = path.dirname(entry_path); + while(directory.length != 0 && !original_fs.existsSync(directory)) + directory = path.normalize(path.join(directory, "..")); + + code = await test_access(directory, original_fs.constants.W_OK); + if(code) errors.push("Failed to acquire write permissions for directory " + entry_path + " (Code " + code.code + ". Target directory " + directory + ")"); + } + }; + + tar_stream.on('entry', (header: Headers, stream, next) => { + tester(header).catch(error => { + console.log("Emit out of tar_stream.on('entry' ...)"); + tar_stream.emit('error', error); + }).then(() => { + stream.on('end', next); + stream.resume(); + }); + }); + + fstream.pipe(tar_stream); + try { + await new Promise((resolve, reject) => { + tar_stream.on('finish', resolve); + tar_stream.on('error', error => { reject(error); }); + }); + } catch(error) { + throw "Failed to list files within tar: " + error; + } + + return errors; +} + +namespace install_config { + export interface LockFile { + filename: string; + timeout: number; + "error-id": string; + } + export interface MoveFile { + source: string; + target: string; + "error-id": string; + } + export interface ConfigFile { + version: number; + + backup: boolean; + "backup-directory": string; + + "callback_file": string; + "callback_argument_fail": string; + "callback_argument_success": string; + + moves: MoveFile[]; + locks: LockFile[]; + } +} + +async function build_install_config(source_root: string, target_root: string) : Promise { + console.log("Building update install config for target directory: %s. Update source: %o", target_root, source_root); + const result: install_config.ConfigFile = { } as any; + + result.version = 1; + + result.backup = true; + + { + const data = path.parse(source_root); + result["backup-directory"] = path.join(data.dir, data.name + "_backup"); + } + + result.callback_file = app.getPath("exe"); + result.callback_argument_fail = "--no-single-instance --update-failed-new="; + result.callback_argument_success = "--no-single-instance --update-succeed-new="; + + result.moves = []; + result.locks = [ + { + "error-id": "main-exe-lock", + filename: app.getPath("exe"), + timeout: 5000 + } + ]; + + const ignore_list = [ + "update-installer.exe", "update-installer" + ]; + + const dir_walker = async (relative_path: string) => { + const source_directory = path.join(source_root, relative_path); + const target_directory = path.join(target_root, relative_path); + + let files: string[]; + try { + files = await util.promisify(ofs.readdir)(source_directory); + } catch(error) { + console.warn("Failed to iterate over source directory \"%s\": %o", source_directory, error); + return; + } + + for(const file of files) { + let _exclude = false; + for(const exclude of ignore_list) { + if(exclude == file) { + console.debug("Ignoring file to update (%s/%s)", relative_path, file); + _exclude = true; + break; + } + } + if(_exclude) + continue; + + const source_file = path.join(source_directory, file); + const target_file = path.join(target_directory, file); + + //TODO check if file content has changed else ignore? + + const info = await util.promisify(ofs.stat)(source_file); + if(info.isDirectory()) { + await dir_walker(path.join(relative_path, file)); + } else { + /* TODO: ensure its a file! */ + result.moves.push({ + "error-id": "move-file-" + result.moves.length, + source: source_file, + target: target_file + }); + } + } + }; + + await dir_walker("."); + return result; +} + +export async function execute_update(update_file: string, restart_callback: (callback: () => void) => any) : Promise { + let application_path = app.getAppPath(); + if(application_path.endsWith(".asar")) { + console.log("App path points to ASAR file (Going up to root directory)"); + application_path = await fs.realpath(path.join(application_path, "..", "..")); + } else if(await fs.pathExists(application_path) && (await fs.stat(application_path)).isFile()) + application_path = path.dirname(application_path); + + console.log("Located target app path: %s", application_path); + console.log("Using update file: %s", update_file); + + const temp_directory = path.join(app.getPath("temp"), "teaclient_update_" + Math.random().toString(36).substring(7)); + { + console.log("Preparing update source directory at %s", temp_directory); + try { + await fs.mkdirp(temp_directory) + } catch(error) { + console.error("failed to create update source directory: %o", error); + throw "failed to create update source directory"; + } + + const source = fs.createReadStream(update_file); + const extract = tar.extract(); + + extract.on('entry', (header: Headers, stream: PassThrough, callback) => { + const extract = async (header: Headers, stream: PassThrough) => { + const target_file = path.join(temp_directory, header.name); + console.debug("Extracting entry %s of type %s to %s", header.name, header.type, target_file); + + if(header.type == "directory") { + await fs.mkdirp(target_file); + } else if(header.type == "file") { + { + const directory = path.parse(target_file).dir; + console.debug("Testing for directory: %s", directory); + if(!(await util.promisify(ofs.exists)(directory)) || !(await util.promisify(ofs.stat)(directory)).isDirectory()) { + console.log("Creating directory %s", directory); + try { + await fs.mkdirp(directory); + } catch(error) { + console.warn("failed to create directory for file %s", header.type); + } + } + + } + const write_stream = ofs.createWriteStream(target_file); + try { + await new Promise((resolve, reject) => { + stream.pipe(write_stream) + .on('error', reject) + .on('finish', resolve); + }); + return; /* success */ + } catch(error) { + console.error("Failed to extract update file %s: %o", header.name, error); + } + } else { + console.debug("Skipping this unknown file type"); + } + stream.resume(); /* drain the stream */ + }; + extract(header, stream).catch(error => { + console.log("Ignoring file %s due to an error: %o", header.name, error); + }).then(() => { + callback(); + }); + }); + + + source.pipe(extract); + try { + await new Promise((resolve, reject) => { + extract.on('finish', resolve); + extract.on('error', reject); + }); + } catch(error) { + console.error("Failed to unpack update: %o", error); + throw "update unpacking failed"; + } + } + /* the "new" environment should now be available at 'temp_directory' */ + console.log("Update unpacked successfully. Building update extractor file."); + + let install_config; + try { + install_config = await build_install_config(temp_directory, application_path); + } catch(error) { + console.error("Failed to build update installer config: %o", error); + throw "failed to build update installer config"; + } + + const log_file = path.join(temp_directory, "update-log.txt"); + const config_file = path.join(temp_directory, "update_install.json"); + console.log("Writing config to %s", config_file); + try { + await fs.writeJSON(config_file, install_config); + } catch(error) { + console.error("Failed to write update install config file: %s", error); + throw "failed to write update install config file"; + } + + const update_installer = path.join(application_path, "update-installer" + (os.platform() === "win32" ? ".exe" : "")); + if(!(await fs.pathExists(update_installer))) { + console.error("Missing update installer! Supposed to be at %s", update_installer); + throw "Missing update installer!"; + } else { + console.log("Using update installer located at %s", update_installer); + } + + if(os.platform() == "linux") { + console.log("Executing update install on linux"); + + //We have to unpack it later + const rest_callback = () => { + console.log("Executing command %s with args %o", update_installer, [log_file, config_file]); + try { + let result = child_process.spawnSync(update_installer, [log_file, config_file]); + if(result.status != 0) { + console.error("Failed to execute update installer! Return code: %d", result.status); + dialog.showMessageBox({ + buttons: ["update now", "remind me later"], + title: "Update available", + message: + "Failed to execute update installer\n" + + "Installer exited with code " + result.status + } as MessageBoxOptions); + } + } catch(error) { + console.error("Failed to execute update installer (%o)", error); + if("errno" in error) { + const errno = error as ErrnoException; + if(errno.errno == EPERM) { + dialog.showMessageBox({ + buttons: ["quit"], + title: "Update execute failed", + message: "Failed to execute update installer. (No permissions)\nPlease execute the client with admin privileges!" + } as MessageBoxOptions); + return; + } + dialog.showMessageBox({ + buttons: ["quit"], + title: "Update execute failed", + message: "Failed to execute update installer.\nError: " + errno.message + } as MessageBoxOptions); + return; + } + dialog.showMessageBox({ + buttons: ["quit"], + title: "Update execute failed", + message: "Failed to execute update installer.\nLookup console for more detail" + } as MessageBoxOptions); + return; + } + + if(electron.app.hasSingleInstanceLock()) + electron.app.releaseSingleInstanceLock(); + + const ids = child_process.execSync("pgrep TeaClient").toString().split(os.EOL).map(e => e.trim()).reverse().join(" "); + console.log("Executing %s", "kill -9 " + ids); + child_process.execSync("kill -9 " + ids); + }; + restart_callback(rest_callback); + } else { + console.log("Executing update install on windows"); + + //We have to unpack it later + const rest_callback = () => { + let pipe = child_process.spawn(update_installer, [log_file, config_file], { + detached: true, + cwd: application_path, + stdio: 'ignore', + }); + pipe.unref(); + app.quit(); + }; + restart_callback(rest_callback); + } +} + +export async function current_version() : Promise { + if(process_args.has_value(Arguments.UPDATER_LOCAL_VERSION)) + return parse_version(process_args.value(Arguments.UPDATER_LOCAL_VERSION)); + + let parent_path = app.getAppPath(); + if(parent_path.endsWith(".asar")) { + parent_path = path.join(parent_path, "..", ".."); + parent_path = fs.realpathSync(parent_path); + } + try { + const info = await fs.readJson(path.join(parent_path, "app_version.json")); + let result = parse_version(info["version"]); + result.timestamp = info["timestamp"]; + return result; + } catch (error) { + console.log("Got no version!"); + return new Version(0, 0, 0, 0, 0); + } +} + +async function minawait(object: Promise, time: number) : Promise { + const begin = Date.now(); + const r = await object; + const end = Date.now(); + if(end - begin < time) + await new Promise(resolve => setTimeout(resolve, time + begin - end)); + return r; +} + +export let update_restart_pending = false; +export async function execute_graphical(channel: string, ask_install: boolean) : Promise { + const electron = require('electron'); + + const ui_debug = process_args.has_flag(Arguments.UPDATER_UI_DEBUG); + const window = new electron.BrowserWindow({ + show: false, + width: ui_debug ? 1200 : 600, + height: ui_debug ? 800 : 400, + + webPreferences: { + devTools: true, + nodeIntegration: true, + javascript: true + } + }); + + window.loadFile(path.join(path.dirname(module.filename), "ui", "index.html")); + if(ui_debug) { + window.webContents.openDevTools(); + } + await new Promise(resolve => window.on('ready-to-show', resolve)); + window.show(); + await winmgr.apply_bounds('update-installer', window); + winmgr.track_bounds('update-installer', window); + + const current_vers = await current_version(); + console.log("Current version: " + current_vers.toString(true)); + + console.log("Showed"); + const set_text = text => window.webContents.send('status-update-text', text); + const set_error = text => window.webContents.send('status-error', text); + const set_progress = progress => window.webContents.send('status-update', progress); + const await_exit = () => { return new Promise(resolve => window.on('closed', resolve))}; + const await_version_confirm = version => { + const id = "version-accept-" + Date.now(); + window.webContents.send('status-confirm-update', id, current_vers, version); + return new Promise((resolve, reject) => { + window.on('closed', () => resolve(false)); + ipcMain.once(id, (event, result) => { + console.log("Got response %o", result); + resolve(result); + }); + }); + }; + const await_confirm_execute = () => { + const id = "status-confirm-execute-" + Date.now(); + window.webContents.send('status-confirm-execute', id); + return new Promise((resolve, reject) => { + window.on('closed', () => resolve(false)); + ipcMain.once(id, (event, result) => { + console.log("Got response %o", result); + resolve(result); + }); + }); + }; + + set_text("Loading data"); + let version: UpdateVersion; + try { + version = await minawait(newest_version(process_args.has_flag(Arguments.UPDATER_ENFORCE) ? undefined : current_vers, channel), 3000); + } catch (error) { + set_error("Failed to get newest information:
" + error); + await await_exit(); + return false; + } + console.log("Got version %o", version); + + if(!version) { + set_error("You're already on the newest version!"); + await await_exit(); + return false; + } + + if(ask_install) { + try { + const test = await await_version_confirm(version.version); + if(!test) { + window.close(); + return false; + } + } catch (error) { + console.dir(error); + window.close(); + return false; + } + } + + set_text("Updating to version " + version.version.toString() + "
Downloading...."); + let update_path: string; + try { + update_path = await download_version(version.channel, version.version, status => { setImmediate(set_progress, status.percent); }); + } catch (error) { + set_error("Failed to download version:
" + error); + console.error(error); + await await_exit(); + return false; + } + + try { + const inaccessible = await test_file_accessibility(update_path); + if(inaccessible.length > 0) { + console.log("Failed to access the following files:"); + for(const fail of inaccessible) + console.log(" - " + fail); + + if(os.platform() == "linux") { + set_error("Failed to access target files.
Please execute this app with administrator (sudo) privileges.
Use the following command:

" + + "sudo " + path.normalize(app.getAppPath()) + " --update-execute=\"" + path.normalize(update_path) + "\"

"); + await await_exit(); + return false; + } else if(os.platform() == "win32") { + /* the updater asks for admin rights anyway :/ */ + } + } + } catch(error) { + set_error("Failed to access target files.
You may need to execute the TeaClient as Administrator!
Error: " + error); + await await_exit(); + return false; + } + + if(!await await_confirm_execute()) { + window.close(); + return false; + } + + set_text("Extracting update installer...
Please wait"); + try { + await extract_updater(update_path); + } catch(error) { + console.error("Failed to update the updater! (%o)", error); + set_error("Failed to update the update installer.\nUpdate failed!"); + await await_exit(); + return false; + } + set_text("Executing update...
Please wait"); + + try { + await execute_update(update_path, callback => { + _main_windows.set_prevent_instant_close(true); + update_restart_pending = true; + window.close(); + callback(); + }); + } catch (error) { + dialog.showErrorBox("Update error", "Failed to execute update!\n" + error); + return false; + } + return true; +} + +export let update_question_open = false; +async function check_update(channel: string) { + let version: UpdateVersion; + try { + version = await newest_version(await current_version(), channel); + } catch(error) { + console.warn("failed check for newer versions!"); + console.error(error); + return; + } + if(version) { + update_question_open = true; + dialog.showMessageBox({ + buttons: ["update now", "remind me later"], + title: "TeaClient: Update available", + message: + "There is an update available!\n" + + "Should we update now?\n" + + "\n" + + "Current version: " + (await current_version()).toString() + "\n" + + "Target version: " + version.version.toString() + } as MessageBoxOptions).then(result => { + if(result.response == 0) { + execute_graphical(channel, false).then(() => { + update_question_open = false; + }); + } else { + update_question_open = false; + } + }); + } +} + +let update_task: Timer; +export function start_auto_update_check() { + if(update_task) return; + update_task = setInterval(check_update, 2 * 60 * 60 * 1000); + setImmediate(check_update); +} + +export function stop_auto_update_check() { + clearInterval(update_task); + update_task = undefined; +} + +export async function selected_channel() : Promise { + return process_args.has_value(Arguments.UPDATER_CHANNEL) ? process_args.value(Arguments.UPDATER_CHANNEL) : "release"; +} \ No newline at end of file diff --git a/modules/core/app-updater/ui/index.css b/modules/core/app-updater/ui/index.css new file mode 100644 index 0000000..2124e03 --- /dev/null +++ b/modules/core/app-updater/ui/index.css @@ -0,0 +1,9 @@ +.page { + display: none; +} + +.info { + display: block; +} + +/*# sourceMappingURL=index.css.map */ diff --git a/modules/core/app-updater/ui/index.css.map b/modules/core/app-updater/ui/index.css.map new file mode 100644 index 0000000..3f2d110 --- /dev/null +++ b/modules/core/app-updater/ui/index.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":"AAAA;EACC;;;AAGD;EACC","file":"index.css"} \ No newline at end of file diff --git a/modules/core/app-updater/ui/index.html b/modules/core/app-updater/ui/index.html new file mode 100644 index 0000000..b44ee63 --- /dev/null +++ b/modules/core/app-updater/ui/index.html @@ -0,0 +1,36 @@ + + + + + Updating app + + + + + + +
+
Downloading update. Please wait!
+ +
+
+
+
+
+ Download succeeded.
+ Update installation requires client restart!
+ Please ensure that all instances are closed!
+ If not this app would kill them!
+ +
+
+ Update available.
+ Current version:
+ Target version:
+ + +
+ + \ No newline at end of file diff --git a/modules/core/app-updater/ui/index.scss b/modules/core/app-updater/ui/index.scss new file mode 100644 index 0000000..6229a24 --- /dev/null +++ b/modules/core/app-updater/ui/index.scss @@ -0,0 +1,7 @@ +.page { + display: none; +} + +.info { + display: block; +} \ No newline at end of file diff --git a/modules/core/app-updater/ui/index.ts b/modules/core/app-updater/ui/index.ts new file mode 100644 index 0000000..b5ffe6e --- /dev/null +++ b/modules/core/app-updater/ui/index.ts @@ -0,0 +1,51 @@ +import * as electron from "electron"; +import * as $ from "jquery"; +import {Version} from "../../../shared/version"; + +electron.ipcRenderer.on('status-update', (event, progress) => { + if(!$(".info").is(":visible")) { + $(".page").hide(); + $(".info").show() + } + $(".progress").attr("value", progress * 100); +}); + +electron.ipcRenderer.on('status-update-text', (event, text) => { + if(!$(".info").is(":visible")) { + $(".page").hide(); + $(".info").show() + } + $(".state").html(text); +}); + +electron.ipcRenderer.on('status-error', (event, text) => { + console.log("Got error %s", text); + $(".page").hide(); + $(".error").show().html(text); +}); +electron.ipcRenderer.on('status-confirm-execute', (event, callback_name) => { + $(".page").hide(); + $(".confirm-restart").show(); + $(".button-execute").on('click', event => electron.ipcRenderer.send(callback_name, true)) +}); +electron.ipcRenderer.on('status-confirm-update', (event, callback_name, current: Version, version: Version) => { + console.dir(callback_name); + console.dir(version); + + $(".page").hide(); + $(".config-update").show(); + + $(".target-version").text(version.major + "." + version.minor + "." + version.patch + (version.build > 0 ? " (" + version.build + ")" : "")); + $(".current-version").text(current.major + "." + current.minor + "." + current.patch + (current.build > 0 ? " (" + current.build + ")" : "")); + + $(".button-update").on('click', event => electron.ipcRenderer.send(callback_name, true)); + $(".button-cancel").on('click', event => electron.ipcRenderer.send(callback_name, false)); +}); + +/* + const set_text = text => window.webContents.send('status-update-text', text); + const set_error = text => window.webContents.send('status-error', text); + const set_confirm_restart = () => window.webContents.send('status-confirm-restart'); + const set_progress = progress => window.webContents.send('status-update', progress); + const await_exit = () => { return new Promise(resolve => window.on('closed', resolve))}; + */ \ No newline at end of file diff --git a/modules/core/main.ts b/modules/core/main.ts new file mode 100644 index 0000000..e04595c --- /dev/null +++ b/modules/core/main.ts @@ -0,0 +1,209 @@ +// Quit when all windows are closed. +import * as electron from "electron"; +import * as app_updater from "./app-updater"; + +import { app } from "electron"; +import MessageBoxOptions = electron.MessageBoxOptions; + +import {process_args, parse_arguments, Arguments} from "../shared/process-arguments"; +import {open as open_changelog} from "./app-updater/changelog"; +import * as crash_handler from "../crash_handler"; +import {open_preview} from "./url-preview"; + +async function execute_app() { + /* legacy, will be removed soon */ + if(process_args.has_value("update-failed")) { + const result = await electron.dialog.showMessageBox({ + type: "error", + message: "Failed to execute update:\n" + process_args.value("update-failed"), + title: "Update failed!", + buttons: ["retry", "ignore"] + } as MessageBoxOptions); + if(result.response == 0) + if(await app_updater.execute_graphical(await app_updater.selected_channel(), false)) + return; + } else if(process_args.has_value("update-succeed")) { + const result = await electron.dialog.showMessageBox({ + type: "info", + message: "Update successfully installed!\nShould we launch TeaClient?", + title: "Update succeeded!", + buttons: ["yes", "no"] + } as MessageBoxOptions); + if(result.response != 0) { + electron.app.exit(0); + return; //Not really required here! + } + } + + + + if(process_args.has_value("update-execute")) { + console.log("Executing update " + process_args.value("update-execute")); + await app_updater.execute_update(process_args.value("update-execute"), callback => { + console.log("Update preconfig successful. Extracting update. (The client should start automatically)"); + app.quit(); + setImmediate(callback); + }); + return; + } else if(process_args.has_value("update-failed-new") || process_args.has_value("update-succeed-new")) { + const success = process_args.has_value("update-succeed-new"); + let data: { + parse_success: boolean; + log_file?: string; + error_id?: string; + error_message?: string; + } = { + parse_success: false + }; + try { + let encoded_data = Buffer.from(process_args.value("update-failed-new") || process_args.value("update-succeed-new"), "base64").toString(); + for(const part of encoded_data.split(";")) { + const index = part.indexOf(':'); + if(index == -1) + data[part] = true; + else { + data[part.substr(0, index)] = Buffer.from(part.substr(index + 1), "base64").toString(); + } + } + data.parse_success = true; + } catch($) { + console.error($); + } + console.log("Update success: %o. Update data: %o", success, data); + + let title = ""; + let type = ""; + let message = ""; + + const buttons: ({ + key: string, + callback: () => Promise + })[] = []; + + if(success) { + open_changelog(); + + type = "info"; + title = "Update succeeded!"; + + message = "Update has been successfully installed!\nWhat do you want to do next?"; + + buttons.push({ + key: "Launch client", + callback: async () => false + }); + if(data.parse_success && data.log_file) { + buttons.push({ + key: "Open update log", + callback: async () => { + electron.shell.openItem(data.log_file); + return true; + } + }); + } + } else { + type = "error"; + title = "Update failed!"; + + message = "Failed to install update."; + if(data.parse_success) { + message += "\n\n"; + message += "Error ID: " + (data.error_id || "undefined") + "\n"; + message += "Error Message: " + (data.error_message || "undefined") + "\n"; + message += "Installer log: " + (data.log_file || "undefined"); + } else { + message += "\nUnknown error! Lookup the console for more details."; + } + + buttons.push({ + key: "Ignore", + callback: async () => false + }); + buttons.push({ + key: "Retry update", + callback: async () => { + await app_updater.execute_graphical(await app_updater.selected_channel(), false); + return true; + } + }); + if(data.parse_success && data.log_file) { + buttons.push({ + key: "Open update log", + callback: async () => { + electron.shell.openItem(data.log_file); + return true; + } + }); + } + } + buttons.push({ + key: "Close", + callback: async () => true + }); + + const result = await electron.dialog.showMessageBox({ + type: type, + message: message, + title: title, + buttons: buttons.map(e => e.key) + } as MessageBoxOptions); + if(buttons[result.response].callback) { + if(await buttons[result.response].callback()) + return; + } + } + + try { + { + const version = await app_updater.current_version(); + global["app_version_client"] = version.toString(); + } + const main = require("./main_window"); + main.execute(); + + app_updater.start_auto_update_check(); + } catch (error) { + console.dir(error); + const result = electron.dialog.showMessageBox({ + type: "error", + message: "Failed to execute app main!\n" + error, + title: "Main execution failed!", + buttons: ["close"] + } as MessageBoxOptions); + electron.app.exit(1); + } +} + +function main() { + process.on('uncaughtException', err => { + console.error(err, 'Uncaught Exception thrown'); + console.dir(err); + process.exit(1); + }); + + /* + if(false) { + SegfaultHandler = require('segfault-handler'); + + SegfaultHandler.registerHandler("crash.log"); // With no argument, SegfaultHandler will generate a generic log file name + } + + const SegfaultHandler = require('segfault-handler'); + SegfaultHandler.registerHandler("crash.log"); // With no argument, SegfaultHandler will generate a generic log file name + */ + if(app) { //We're executed! + parse_arguments(); + if(process_args.has_value(Arguments.DISABLE_HARDWARE_ACCELERATION)) + app.disableHardwareAcceleration(); + if(process_args.has_value(Arguments.DUMMY_CRASH_MAIN)) + crash_handler.handler.crash(); + if(!process_args.has_value(Arguments.DEBUG) && !process_args.has_value(Arguments.NO_SINGLE_INSTANCE)) { + if(!app.requestSingleInstanceLock()) { + console.log("Another instance is already running. Closing this instance"); + app.exit(0); + } + } + app.on('ready', execute_app); + } +} +export const execute = main; \ No newline at end of file diff --git a/modules/core/main_window.ts b/modules/core/main_window.ts new file mode 100644 index 0000000..f102877 --- /dev/null +++ b/modules/core/main_window.ts @@ -0,0 +1,206 @@ +import {BrowserWindow, Menu, MenuItem, MessageBoxOptions, app, dialog} from "electron"; +import * as electron from "electron"; +import * as winmgr from "./window"; +import * as path from "path"; + +export let prevent_instant_close: boolean = true; +export function set_prevent_instant_close(flag: boolean) { + prevent_instant_close = flag; +} + +export let is_debug: boolean; +export let allow_dev_tools: boolean; + +import {Arguments, parse_arguments, process_args} from "../shared/process-arguments"; +import * as updater from "./app-updater"; +import * as loader from "./ui-loader"; +import * as crash_handler from "../crash_handler"; + +// Keep a global reference of the window object, if you don't, the window will +// be closed automatically when the JavaScript object is garbage collected. +export let main_window: BrowserWindow = null; + +function spawn_main_window(entry_point: string) { + // Create the browser window. + console.log("Spawning main window"); + main_window = new BrowserWindow({ + width: 800, + height: 600, + + minHeight: 600, + minWidth: 600, + + show: false, + webPreferences: { + webSecurity: false, + nodeIntegrationInWorker: true, + nodeIntegration: true + }, + icon: path.join(__dirname, "..", "..", "resources", "logo.ico") + }); + + main_window.webContents.on('devtools-closed', event => { + console.log("Dev tools destroyed!"); + }); + + main_window.on('closed', () => { + require("./url-preview").close(); + main_window = null; + prevent_instant_close = false; + }); + + + main_window.loadFile(loader.ui.preloading_page(entry_point)); + + main_window.once('ready-to-show', () => { + main_window.show(); + winmgr.apply_bounds('main-window', main_window).then(() => { + winmgr.track_bounds('main-window', main_window); + + main_window.focus(); + loader.ui.cleanup(); + if(allow_dev_tools && !main_window.webContents.isDevToolsOpened()) + main_window.webContents.openDevTools(); + prevent_instant_close = false; /* just to ensure that the client could be unloaded */ + }); + }); + + main_window.webContents.on('new-window', (event, url_str, frameName, disposition, options, additionalFeatures) => { + event.preventDefault(); + try { + let url: URL; + try { + url = new URL(url_str); + } catch(error) { + throw "failed to parse URL"; + } + + { + let protocol = url.protocol.endsWith(":") ? url.protocol.substring(0, url.protocol.length - 1) : url.protocol; + if(protocol !== "https" && protocol !== "http") { + throw "invalid protocol (" + protocol + "). HTTP(S) are only supported!"; + } + } + + console.log("Got new window " + frameName); + const url_preview = require("./url-preview"); + url_preview.open_preview(url_str); + } catch(error) { + console.error("Failed to open preview window for URL %s: %o", url_str, error); + dialog.showErrorBox("Failed to open preview", "Failed to open preview URL: " + url_str + "\nError: " + error); + } + }); + + main_window.webContents.on('crashed', event => { + console.error("UI thread crashed! Closing app!"); + if(!process_args.has_flag(Arguments.DEBUG)) { + main_window.close(); + prevent_instant_close = false; + } + }); +} + +function handle_error(message: string) { + console.log("Caught loading error: %s", message); + //"A critical error happened while loading TeaClient!", "A critical error happened while loading TeaClient!
" + message + dialog.showMessageBox({ + type: "error", + buttons: ["exit"], + title: "A critical error happened while loading TeaClient!", + message: message + }); + loader.ui.cancel(); +} + +function init_listener() { + app.on('quit', () => { + console.debug("Finalizing crash handler"); + crash_handler.finalize_handler(); + console.log("RUNNING quit!"); + loader.cleanup(); + console.log("RUNNING quit 2!"); + loader.ui.cleanup(); + console.log("RUNNING quit done!"); + }); + + app.on('window-all-closed', () => { + console.log("RUNNING all win closed!"); + // On macOS it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + if(!prevent_instant_close) { + console.log("All windows have been closed, closing app."); + app.quit(); + } else { + console.log("All windows have been closed, but we dont want to quit instantly. Waiting 10 seconds if something happens"); + setTimeout(() => { + if(BrowserWindow.getAllWindows().length == 0) { + console.log("All windows have been closed for over an minute. Exiting app!"); + app.quit(); + } + }, 10 * 1000); + } + } + }); + + app.on('activate', () => { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (main_window === null) { + //spawn_loading_screen(); + //createWindow() + } + }); + + + app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { + console.log("Allowing untrusted certificate for %o", url); + event.preventDefault(); + callback(true); + }); +} + +export function execute() { + console.log("Main app executed!"); + + parse_arguments(); + is_debug = process_args.has_flag(...Arguments.DEBUG); + allow_dev_tools = process_args.has_flag(...Arguments.DEV_TOOLS); + if(is_debug) { + console.log("Enabled debug!"); + console.log("Arguments: %o", process_args); + } + + Menu.setApplicationMenu(null); + init_listener(); + + console.log("Setting up render backend"); + require("./render-backend"); + + console.log("Spawn loading screen"); + loader.ui.execute_loader().then(async (entry_point: string) => { + /* test if the updater may have an update found */ + let awaiting_update_set = false; + while(updater.update_question_open) { + if(!awaiting_update_set) { + awaiting_update_set = true; + loader.ui.show_await_update(); + console.log("Awaiting update stuff to be finished"); + } + await new Promise(resolve => setTimeout(resolve, 100)); + } + + if(updater.update_restart_pending) + return undefined; + + return entry_point; + }).then((entry_point: string) => { + loader.ui.cleanup(); /* close the window */ + + if(entry_point) //has not been canceled + spawn_main_window(entry_point); + else { + console.warn("Missing entry point!"); + } + }).catch(handle_error); +} diff --git a/modules/core/render-backend/index.ts b/modules/core/render-backend/index.ts new file mode 100644 index 0000000..c44c6cf --- /dev/null +++ b/modules/core/render-backend/index.ts @@ -0,0 +1,22 @@ +import "./menu"; + +import * as electron from "electron"; +import ipcMain = electron.ipcMain; +import BrowserWindow = electron.BrowserWindow; + +import {open as open_changelog} from "../app-updater/changelog"; +import * as updater from "../app-updater"; + +ipcMain.on('basic-action', (event, action, ...args: any[]) => { + const window = BrowserWindow.fromWebContents(event.sender); + + if(action === "open-changelog") { + open_changelog(); + } else if(action === "check-native-update") { + updater.selected_channel().then(channel => updater.execute_graphical(channel, true)); + } else if(action === "open-dev-tools") { + window.webContents.openDevTools(); + } else if(action === "reload-window") { + window.reload(); + } +}); diff --git a/modules/core/render-backend/menu.ts b/modules/core/render-backend/menu.ts new file mode 100644 index 0000000..407aa32 --- /dev/null +++ b/modules/core/render-backend/menu.ts @@ -0,0 +1,34 @@ +import * as electron from "electron"; +import ipcMain = electron.ipcMain; +import BrowserWindow = electron.BrowserWindow; + +ipcMain.on('top-menu', (event, menu_template: electron.MenuItemConstructorOptions[]) => { + const window = BrowserWindow.fromWebContents(event.sender); + + const process_template = (item: electron.MenuItemConstructorOptions) => { + if(typeof(item.icon) === "string" && item.icon.startsWith("data:")) + item.icon = electron.nativeImage.createFromDataURL(item.icon); + + item.click = () => window.webContents.send('top-menu', item.id); + for(const i of item.submenu as electron.MenuItemConstructorOptions[] || []) { + process_template(i); + } + }; + + for(const m of menu_template) + process_template(m); + + try { + const menu = new electron.Menu(); + for(const m of menu_template) { + try { + menu.append(new electron.MenuItem(m)); + } catch(error) { + console.error("Failed to build menu entry: %o\nSource: %o", error, m); + } + } + window.setMenu(menu_template.length == 0 ? undefined : menu); + } catch(error) { + console.error("Failed to set window menu: %o", error); + } +}); \ No newline at end of file diff --git a/modules/core/ui-loader/graphical.ts b/modules/core/ui-loader/graphical.ts new file mode 100644 index 0000000..58bf834 --- /dev/null +++ b/modules/core/ui-loader/graphical.ts @@ -0,0 +1,147 @@ +import * as electron from "electron"; +import * as path from "path"; +import {screen} from "electron"; + +import {Arguments, process_args} from "../../shared/process-arguments"; +import * as loader from "./loader"; +import * as updater from "../app-updater"; +import * as winmgr from "../window"; +import {main_window} from "../main_window"; + +export namespace ui { + let gui: electron.BrowserWindow; + let promise: Promise; + let resolve: any; + let reject: any; + + export function running() : boolean { + return promise !== undefined; + } + + export function cancel() : boolean { + if(resolve) + resolve(); + + cleanup(); + return true; + } + + export function cleanup() { + if(gui) { + promise = undefined; + resolve = undefined; + + gui.destroy(); + gui = undefined; + + reject = error => { + if(error) + console.error("Received error from loader after it had been closed... Error: %o", error); + }; + } + } + + async function load_files() { + const channel = await updater.selected_channel(); + try { + const entry_point = await loader.load_files(channel, (status, index) => { + if(gui) { + gui.webContents.send('progress-update', index); + } + }); + + const resolved = () => { + resolve(entry_point); + + promise = undefined; + resolve = undefined; + reject = error => { + if(error) + console.error("Received error from loader after it had been closed... Error: %o", error); + }; + }; + if(!process_args.has_flag(...Arguments.DISABLE_ANIMATION)) + setTimeout(resolved, 250); + else + setImmediate(resolved); + } catch (error) { + throw error; + } + } + + export function show_await_update() { + if(gui) + gui.webContents.send('await-update'); + } + + function spawn_gui() { + console.log("Spawn window!"); + let dev_tools = false; + + const WINDOW_WIDTH = 340 + (dev_tools ? 1000 : 0); + const WINDOW_HEIGHT = 400 + (process.platform == "win32" ? 40 : 0); + + let bounds = screen.getPrimaryDisplay().bounds; + let x = bounds.x + (bounds.width - WINDOW_WIDTH) / 2; + let y = bounds.y + (bounds.height - WINDOW_HEIGHT) / 2; + console.log("Bounds: %o; Move loader window to %ox%o", bounds, x, y); + + gui = new electron.BrowserWindow({ + width: WINDOW_WIDTH, + height: WINDOW_HEIGHT, + frame: dev_tools, + resizable: dev_tools, + show: false, + autoHideMenuBar: true, + + webPreferences: { + webSecurity: false, + nodeIntegrationInWorker: false, + nodeIntegration: true + } + }); + gui.setMenu(null); + gui.loadFile(path.join(path.dirname(module.filename), "ui", "loading_screen.html")); + gui.on('closed', () => { + if(resolve) + resolve(); + gui = undefined; + cleanup(); + }); + + gui.on('ready-to-show', () => { + gui.show(); + gui.setPosition(x, y); + winmgr.apply_bounds('ui-load-window', gui, undefined, { apply_size: false }).then(() => { + winmgr.track_bounds('ui-load-window', gui); + + const call_loader = () => load_files().catch(reject); + if(!process_args.has_flag(...Arguments.DISABLE_ANIMATION)) + setTimeout(call_loader, 1000); + else + setImmediate(call_loader); + + if(dev_tools) + gui.webContents.openDevTools(); + }); + }); + + } + + export async function execute_loader() : Promise { + return promise = new Promise((_resolve, _reject) => { + resolve = _resolve; + reject = _reject || (error => { + console.error("Failed to load UI files! Error: %o", error) + }); + + spawn_gui(); + }); + } + + export function preloading_page(entry_point: string) : string { + global["browser-root"] = entry_point; /* setup entry point */ + + return path.join(path.dirname(module.filename), "ui", "preload_page.html"); + } +} \ No newline at end of file diff --git a/modules/core/ui-loader/index.ts b/modules/core/ui-loader/index.ts new file mode 100644 index 0000000..4d9dbab --- /dev/null +++ b/modules/core/ui-loader/index.ts @@ -0,0 +1,2 @@ +export * from "./loader.js"; +export * from "./graphical.js"; \ No newline at end of file diff --git a/modules/core/ui-loader/loader.ts b/modules/core/ui-loader/loader.ts new file mode 100644 index 0000000..22cf4ce --- /dev/null +++ b/modules/core/ui-loader/loader.ts @@ -0,0 +1,515 @@ +import {is_debug} from "../main_window"; + +const request = require('request'); +const querystring = require('querystring'); +const fs = require('fs-extra'); +const os = require('os'); +const UUID = require('pure-uuid'); +import * as path from "path"; +import * as zlib from "zlib"; +import * as tar from "tar-stream"; +import {Arguments, process_args} from "../../shared/process-arguments"; +import {parse_version} from "../../shared/version"; + +import * as electron from "electron"; +import MessageBoxOptions = Electron.MessageBoxOptions; +import {current_version, execute_graphical} from "../app-updater"; + +const TIMEOUT = 10000; +let local_path = undefined; + +interface RemoteURL { + (): string; + cached?: string; +} +const remote_url: RemoteURL = () => { + if(remote_url.cached) + return remote_url.cached; + const default_path = is_debug ? "http://localhost/home/TeaSpeak/Web-Client/client-api/environment/" : "https://clientapi.teaspeak.de/"; + return remote_url.cached = (process_args.has_value(...Arguments.SERVER_URL) ? process_args.value(...Arguments.SERVER_URL) : default_path); +}; + +function data_directory() : string { + return electron.app.getPath('userData'); +} + +function cache_directory() : string { + return path.join(data_directory(), "cache", "ui"); +} + +function working_directory() : string { + return path.join(data_directory(), "tmp", "ui"); +} + +export interface VersionedFile { + name: string, + hash: string, + path: string, + type: string, + + local_url: () => Promise +} + +function generate_tmp() : Promise { + if(local_path) return Promise.resolve(local_path); + + const id = new UUID(4).format(); + const directory = path.join(os.tmpdir(), "TeaClient-" + id) + "/"; + + return fs.mkdirs(directory).then(() => { + local_path = directory; + global["browser-root"] = local_path; + console.log("Local browser path: %s", local_path); + return Promise.resolve(local_path); + }); +} + +function get_raw_app_files() : Promise { + return generate_tmp().then(path => new Promise((resolve, reject) => { + const url = remote_url() + "api.php?" + querystring.stringify({ + type: "files", + }); + console.debug("Requesting file list from %s", url); + request.get(url, { + timeout: TIMEOUT + }, (error, response, body: string) => { + response = response || {statusCode: -1}; + + if(error) { reject(error); return; } + if(response.statusCode != 200) { setImmediate(reject, "invalid status code " + response.statusCode + " for " + url); return; } + if(response.headers["info-version"] != 1) { setImmediate(reject, "Invalid response version (" + response.headers["info-version"] + "). Update your app manually!"); return; } + if(!body) { + setImmediate(reject, "invalid body. (Missing)"); + return; + } + let result: VersionedFile[] = []; + + body.split("\n").forEach(entry => { + if(entry.length == 0) return; + + let info = entry.split("\t"); + if(info[0] == "type") return; + + result.push({ + type: info[0], + hash: info[1], + path: info[2], + name: info[3] + } as VersionedFile); + }); + setImmediate(resolve, result); + }); + }) + ); +} + +function download_raw_app_files() : Promise { + return get_raw_app_files().then(response => { + for(let file of response) { + const full_path = path.join(local_path, file.path, file.name); + file.local_url = () => fs.mkdirs(path.dirname(full_path)).then(() => new Promise((resolve, reject) => { + const write_stream = fs.createWriteStream(full_path); + request.get(remote_url() + "api.php?" + querystring.stringify({ + type: "file", + path: file.path, + name: file.name + }), { + timeout: TIMEOUT + }).on('response', function(response) { + if(response.statusCode != 200) { + setImmediate(reject, "invalid status code " + response.statusCode + " for file " + file.name + " (" + file.path + ")"); + return; + } + }).on('complete', event => { + }).on('error', error => { + setImmediate(reject, error); + }).pipe(write_stream) + .on('finish', event => { + setImmediate(resolve, file.path + "/" + file.name); + }); + })); + } + return Promise.resolve(response); + }).catch(error => { + console.log("Failed to get file list: %o", error); + return Promise.reject("Failed to get file list (" + error + ")"); + }) +} + +interface LocalUICache { + fetch_history?: FetchStatus; + versions?: LocalUICacheEntry[]; + + remote_index?: UIVersion[] | UIVersion; + remote_index_channel?: string; /* only set if the last status was a channel only*/ + + local_index?: UIVersion; +} + +interface FetchStatus { + timestamp: number; + /** + * 0 = success + * 1 = connect fail + * 2 = internal fail + */ + status: number; +} + +interface LocalUICacheEntry { + version: UIVersion; + download_timestamp: number; + tar_file: string; + checksum: string; /* SHA512 */ +} + +export interface UIVersion { + channel: string; + version: string; + git_hash: string; + timestamp: number; + + required_client?: string; + filename?: string; + + client_shipped?: boolean; +} + +function ui_file_path(version: UIVersion) : string { + if(version.client_shipped) { + const app_path = electron.app.getAppPath(); + if(!app_path.endsWith(".asar")) + return undefined; + + return path.join(path.join(path.dirname(app_path), "ui"), version.filename); + } + + const file_name = "ui_" + version.channel + "_" + version.version + "_" + version.git_hash + "_" + version.timestamp + ".tar.gz"; + return path.join(cache_directory(), file_name); +} + +let _ui_load_cache: LocalUICache; +async function ui_load_cache() : Promise { + if(_ui_load_cache) return _ui_load_cache; + + const file = path.join(cache_directory(), "data.json"); + if(!fs.existsSync(file)) return {} as LocalUICache; + + console.log("Loading UI cache file %s", file); + _ui_load_cache = await fs.readJson(file) as LocalUICache; + return _ui_load_cache; +} + +async function client_shipped_ui() : Promise { + const app_path = electron.app.getAppPath(); + if(!app_path.endsWith(".asar")) + return undefined; + + const base_path = path.join(path.dirname(app_path), "ui"); + console.debug("Looking for client shipped UI pack at %s", base_path); + if(!(await fs.pathExists(base_path))) + return undefined; + + const info: { + channel: string, + version: string, + git_hash: string, + required_client: string, + timestamp: number, + filename: string + } = await fs.readJson(path.join(base_path, "default_ui_info.json")) as any; + + return { + channel: info.channel, + client_shipped: true, + + filename: info.filename, + git_hash: info.git_hash, + required_client: info.required_client, + timestamp: info.timestamp, + version: info.version, + } +} + +async function ui_save_cache(cache: LocalUICache) { + const file = path.join(cache_directory(), "data.json"); + if(!fs.existsSync(path.dirname(file))) + await fs.mkdirs(path.dirname(file)); + await fs.writeJson(file, cache); +} + +async function get_ui_pack(channel?: string) : Promise { + return await new Promise((resolve, reject) => { + const url = remote_url() + "api.php?" + querystring.stringify({ + type: "ui-info" + }); + request.get(url, { + timeout: TIMEOUT + }, (error, response, body: string) => { + try { + response = response || {statusCode: -1}; + + if(error) { throw error; } + if(response.statusCode != 200) { throw "invalid status code " + response.statusCode + " for " + url; } + if(!body) throw "invalid response body"; + + let result: UIVersion[] = []; + + const json = JSON.parse(body) || {success: false, msg: "invalid body"}; + if(!json["success"]) throw "Failed to get ui info: " + json["msg"]; + + for(const entry of json["versions"]) { + if(!channel || entry["channel"] == channel) + result.push({ + channel: entry["channel"], + version: entry["version"], + git_hash: entry["git-ref"], + timestamp: entry["timestamp"], + required_client: entry["required_client"] + }); + } + + if(result.length == 0 && channel) result.push(undefined); + const res = channel ? result[0] : result; + ui_load_cache().then(async cache => { + cache.fetch_history = cache.fetch_history || {} as any; + cache.fetch_history.timestamp = Date.now(); + cache.fetch_history.status = 0; + cache.remote_index = res as any; + cache.remote_index_channel = channel; + await ui_save_cache(cache); + }).catch(error => { + console.warn("Failed to save UI cache info: %o", error); + resolve(res); + }).then(err => resolve(res)); + } catch(error) { + reject(error); + } + }); + }) +} + +async function download_ui_pack(version: UIVersion) : Promise { + const directory = cache_directory(); + const file = ui_file_path(version); + await fs.mkdirs(directory); + + await new Promise((resolve, reject) => { + request.get(remote_url() + "api.php?" + querystring.stringify({ + type: "ui-download", + "git-ref": version.git_hash, + version: version.version, + timestamp: version.timestamp, + channel: version.channel + }), { + timeout: TIMEOUT + }).on('response', function(response) { + if(response.statusCode != 200) { reject("Failed to download UI files (Status code " + response.statusCode + ")"); } + }).on('error', error => { + reject("Failed to download UI files: " + error); + }).pipe(fs.createWriteStream(file)).on('finish', () => { + ui_load_cache().then(cache => { + cache.versions.push({ + checksum: "undefined", + tar_file: file, + download_timestamp: Date.now(), + version: version + }); + return ui_save_cache(cache); + }).catch(error => resolve()).then(() => resolve()); + + }); + }); +} + +function ui_pack_exists(version: UIVersion) : boolean { + return fs.existsSync(ui_file_path(version)); +} + +async function unpack_cached(version: UIVersion) : Promise { + const file = ui_file_path(version); + if(!fs.existsSync(file)) throw "missing file"; + + const target_dir = path.join(working_directory(), version.channel + "_" + version.timestamp); + if(fs.existsSync(target_dir)) fs.removeSync(target_dir); + + await fs.mkdirs(target_dir); + + const gunzip = zlib.createGunzip(); + const extract = tar.extract(); + const fpipe = fs.createReadStream(file); + + extract.on('entry', function(header: tar.Headers, stream, next) { + if(header.type == 'file') { + const target_file = path.join(target_dir, header.name); + if(!fs.existsSync(path.dirname(target_file))) fs.mkdirsSync(path.dirname(target_file)); + + stream.on('end', () => setImmediate(next)); + const wfpipe = fs.createWriteStream(target_file); + stream.pipe(wfpipe); + } else if(header.type == 'directory') { + if(fs.existsSync(path.join(target_dir, header.name))) + setImmediate(next); + fs.mkdirs(path.join(target_dir, header.name)).catch(error => { + console.warn("Failed to create unpacking fir " + path.join(target_dir, header.name)); + console.error(error); + }).then(() => setImmediate(next)); + } else { + console.warn("Invalid ui tar ball entry type (" + header.type + ")"); + return; + } + }); + + const finish_promise = new Promise(resolve => { + extract.on('finish', resolve); + extract.on('error', event => { + if(!event) return; + throw event; + }); + }); + + fpipe.pipe(gunzip).pipe(extract); + await finish_promise; + + return target_dir; +} + +export async function cleanup() { + if(await fs.pathExists(local_path)) + await fs.remove(local_path); +} + +export async function load_files(channel: string, static_cb: (message: string, index: number) => any) : Promise { + const type = parseInt(process_args.has_value(Arguments.UPDATER_UI_LOAD_TYPE) ? process_args.value(Arguments.UPDATER_UI_LOAD_TYPE) : "-1"); + if(type == 0 || !is_debug) { + console.log("Loading ui package"); + + static_cb("Fetching info", 0); + const cache = await ui_load_cache(); + console.log("Local cache: %o", cache); + + let ui_info: UIVersion; + try { + ui_info = await get_ui_pack(channel) as UIVersion; + } catch(error) { + if(error instanceof Error) + console.error("Failed to fetch ui info: %s. Using cached info!", error.message); + else + console.error("Failed to fetch ui info: %o. Using cached info!", error); + } + if(!ui_info) { + if(cache && !process_args.has_flag(Arguments.UPDATER_UI_NO_CACHE)) { + if(Array.isArray(cache.remote_index)) { + for(const index of cache.remote_index) { + if(index && index.channel == "release") { + ui_info = index; + break; + } + } + } else { + //TODO: test channel? + ui_info = cache.remote_index; + } + } + if(ui_info) { + console.debug("Found local UI pack."); + } else { + //Test for the client shipped ui pack + try { + console.info("Looking for client shipped UI pack."); + ui_info = await client_shipped_ui(); + if(!ui_info) + throw "failed to load info"; + console.info("Using client shipped UI pack because we've no active internet connection.") + } catch(error) { + console.warn("Failed to load client shipped UI pack: %o", error); + throw "Failed to load UI pack from cache!\nPlease ensure a valid internet connection."; + } + } + } + + static_cb("Searching cache for file", .33); + console.log("Loading UI from data: %o. Target path: %s", ui_info, ui_file_path(ui_info)); + if(ui_info.required_client && !process_args.has_flag(Arguments.DEBUG)) { + const ui_vers = parse_version(ui_info.required_client); + const current_vers = await current_version(); + console.log("Checking required client version (Required: %s, Version: %s)", ui_vers.toString(true), current_vers.toString(true)); + if(ui_vers.newer_than(current_vers) && !current_vers.in_dev()) { + const local_available = cache && cache.local_index ? ui_pack_exists(cache.local_index) : undefined; + + const result = await electron.dialog.showMessageBox({ + type: "question", + message: + "Local client is outdated.\n" + + "Newer UI packs (>= " + ui_info.version + ") require client " + ui_info.required_client + "\n" + + "Do you want to upgrade?", + title: "Client outdated!", + buttons: ["yes", local_available ? "ignore and use last possible (" + cache.local_index.version + ")" : "close client"] + } as MessageBoxOptions); + if(result.response == 0) { + await execute_graphical(channel, true); + throw "client outdated"; + } else { + if(!local_available) { + electron.app.exit(1); + return; + } + + ui_info = cache.local_index; + } + } + } + + if(!ui_pack_exists(ui_info)) { + console.log("Ui version does not locally exists. Downloading new one"); + static_cb("Downloading files", .34); + await download_ui_pack(ui_info); + console.log("Download completed!"); + } + + console.log("Unpacking cached ui info"); + static_cb("Unpacking files", .66); + const target_path = await unpack_cached(ui_info); + cache.local_index = ui_info; + await ui_save_cache(cache); + + console.log("Unpacked. Target path: %s", target_path); + static_cb("UI loaded", 1); + + return path.join(target_path, "index.html"); + } else { + console.log("Loading file by file"); + + static_cb("Fetching files", 0); + let files; + try { + files = await download_raw_app_files() + } catch (error) { + throw "Failed to get file list: " + error; + } + console.log("Get raw files:"); + let futures: Promise[] = []; + let finish_count = 0; + static_cb("Downloading files", 0); + + for(const file of files) { + console.log("Start downloading %s (%s)", file.name, file.path); + + const start = Date.now(); + futures.push(file.local_url().then(data => { + finish_count++; + console.log("Downloaded %s (%s) (%ims)", file.name, file.path, Date.now() - start); + static_cb("Downloading files", finish_count / files.length); + })); + + //await new Promise(resolve => setTimeout(resolve, 1000)); + } + + try { + await Promise.all(futures); + } catch (error) { + throw "Failed to download files: " + error; + } + return await generate_tmp() + "index.html"; /* entry point */ + } +} \ No newline at end of file diff --git a/modules/core/ui-loader/ui/img/logo.svg b/modules/core/ui-loader/ui/img/logo.svg new file mode 100644 index 0000000..77dc7a5 --- /dev/null +++ b/modules/core/ui-loader/ui/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/core/ui-loader/ui/img/smoke.png b/modules/core/ui-loader/ui/img/smoke.png new file mode 100644 index 0000000..6a254c8 Binary files /dev/null and b/modules/core/ui-loader/ui/img/smoke.png differ diff --git a/modules/core/ui-loader/ui/loader.ts b/modules/core/ui-loader/ui/loader.ts new file mode 100644 index 0000000..796a9f0 --- /dev/null +++ b/modules/core/ui-loader/ui/loader.ts @@ -0,0 +1,21 @@ +const icp = require("electron").ipcRenderer; + +interface Window { + $: JQuery; +} +(window as any).$ = require("jquery"); + +icp.on('progress-update', (event, count) => { + console.log("Process update to %f", count); + + $(".container-bar .bar").css("width", (count * 100) + "%"); +}); + +icp.on('await-update', (event) => { + console.log("Received update notification"); + + $(".container-bar .bar").css("width", "100%"); + $("#loading-text").html("Awaiting client update response
(User input required)"); +}); + +export {} \ No newline at end of file diff --git a/modules/core/ui-loader/ui/loading_screen.html b/modules/core/ui-loader/ui/loading_screen.html new file mode 100644 index 0000000..7ab97ca --- /dev/null +++ b/modules/core/ui-loader/ui/loading_screen.html @@ -0,0 +1,98 @@ + + + + + TeaClient + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core/ui-loader/ui/preload_page.html b/modules/core/ui-loader/ui/preload_page.html new file mode 100644 index 0000000..bd2be1b --- /dev/null +++ b/modules/core/ui-loader/ui/preload_page.html @@ -0,0 +1,25 @@ + + + + + TeaClient - loading files + + + An unknown error happened!
+ Please report this! + + \ No newline at end of file diff --git a/modules/core/url-preview/html/index.css b/modules/core/url-preview/html/index.css new file mode 100644 index 0000000..5bc86f2 --- /dev/null +++ b/modules/core/url-preview/html/index.css @@ -0,0 +1,86 @@ +#nav-body-ctrls { + background-color: #2a2a2a; + padding: 20px; + font-family: arial +} + +#nav-body-tabs { + background: linear-gradient(#2a2a2a 75%, #404040); + height: 36px; + font-family: arial +} + +#nav-body-views { + flex: 1 +} + +.nav-icons { + fill: #fcfcfc !important +} + +.nav-icons:hover { + fill: #c2c2c2 !important +} + +#nav-ctrls-back, #nav-ctrls-forward, #nav-ctrls-reload { + height: 30px; + width: 30px; + margin-right: 10px +} + +#nav-ctrls-url { + box-shadow: 0 0; + border: 0; + border-radius: 2px; + height: 30px !important; + margin-left: 8px; + font-size: 11pt; + outline: none; + padding-left: 10px; + color: #b7b7b7; + background-color: #404040 +} + +#nav-ctrls-url:focus { + color: #fcfcfc; + box-shadow: 0 0 5px #3d3d3d; +} + +#nav-tabs-add { + margin: 5px +} + +.nav-tabs-tab { + border-radius: 2px; + height: 35px +} + +.nav-tabs-tab.active { + background: #404040 +} + +.nav-tabs-favicon { + margin: 6px +} + +.nav-tabs-title { + padding-left: 5px; + font-style: normal; + font-weight: 700; + color: #fcfcfc +} + +.nav-tabs-title:hover { + color: #c2c2c2 +} + +.nav-tabs-close { + width: 20px; + height: 20px; + margin: 6px; + margin-left: 2px +} + +.nav-tabs-close:hover { + fill: #dc143c !important +} \ No newline at end of file diff --git a/modules/core/url-preview/html/index.html b/modules/core/url-preview/html/index.html new file mode 100644 index 0000000..4f3bafa --- /dev/null +++ b/modules/core/url-preview/html/index.html @@ -0,0 +1,34 @@ + + + + TeaClient - URL preview + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core/url-preview/html/index.ts b/modules/core/url-preview/html/index.ts new file mode 100644 index 0000000..453a147 --- /dev/null +++ b/modules/core/url-preview/html/index.ts @@ -0,0 +1,78 @@ +import * as electron from "electron"; +import * as path from "path"; + +interface Options { + showBackButton: boolean, + showForwardButton: boolean, + showReloadButton: boolean, + showUrlBar: boolean, + showAddTabButton: boolean, + closableTabs: boolean, + verticalTabs: boolean, + defaultFavicons: boolean, + newTabCallback: (url: string, options: any) => any, + changeTabCallback: () => any, + newTabParams: any +} + +interface NewTabOptions { + id: string, + node: boolean, + readonlyUrl: boolean, + contextMenu: boolean, + webviewAttributes: any, + icon: "clean" | "default" | string, + title: "default", + close: boolean +} + +const enav = new (require('electron-navigation'))({ + closableTabs: true, + showAddTabButton: false, + defaultFavicons: true, + + changeTabCallback: new_tab => { + if(new_tab === undefined) + window.close(); + } +} as Options); + +/* Required here: https://github.com/simply-coded/electron-navigation/blob/master/index.js#L364 */ +enav.executeJavaScript = () => {}; /* just to suppress an error cause by the API */ + +let _id_counter = 0; +const execute_preview = (url: string) => { + const id = "preview_" + (++_id_counter); + const tab: HTMLElement & { executeJavaScript(js: string) : Promise } = enav.newTab(url, { + id: id, + contextMenu: false, + readonlyUrl: true, + icon: "default", + webviewAttributes: { + 'preload': path.join(__dirname, "inject.js") + } + } as NewTabOptions); + + /* we only want to preload our script once */ + const show_preview = () => { + tab.removeEventListener("dom-ready", show_preview); + tab.removeAttribute("preload"); + + tab.executeJavaScript('__teaclient_preview_notice()').catch((error) => console.log("Failed to show TeaClient overlay! Error: %o", error)); + }; + + tab.addEventListener("dom-ready", show_preview); + + tab.addEventListener('did-fail-load', (res: any) => { + console.error("Side load failed: %o", res); + if (res.errorCode != -3) { + res.target.executeJavaScript('__teaclient_preview_error("' + res.errorCode + '", "' + encodeURIComponent(res.errorDescription) + '", "' + encodeURIComponent(res.validatedURL) + '")').catch(error => { + console.warn("Failed to show error page: %o", error); + }); + } + }); + + tab.addEventListener('close', () => enav.closeTab(id)); +}; + +electron.ipcRenderer.on('preview', (event, url) => execute_preview(url)); \ No newline at end of file diff --git a/modules/core/url-preview/html/inject.ts b/modules/core/url-preview/html/inject.ts new file mode 100644 index 0000000..804b677 --- /dev/null +++ b/modules/core/url-preview/html/inject.ts @@ -0,0 +1,118 @@ +declare let __teaclient_preview_notice: () => any; +declare let __teaclient_preview_error; + +const electron = require("electron"); +const log_prefix = "[TeaSpeak::Preview] "; + +const html_overlay = +"
" + + "
" + + "
You're in TeaWeb website preview mode. Click here to open the website in the browser
" + + "
" + + "
" + + "" + + "✖" + + "" + + "
" + +"
"; + +let _close_overlay: () => void; +let _inject_overlay = () => { + const element = document.createElement("div"); + element.id = "TeaClient-Overlay-Container"; + document.body.append(element); + element.innerHTML = html_overlay; + + { + _close_overlay = () => { + console.trace(log_prefix + "Closing preview notice"); + element.remove(); + }; + + const buttons = element.getElementsByClassName("button-close"); + if(buttons.length < 1) { + console.warn(log_prefix + "Failed to find close button for preview notice!"); + } else { + for(const button of buttons) { + (button).onclick = _close_overlay; + } + } + } + { + const buttons = element.getElementsByClassName("button-open"); + if(buttons.length < 1) { + console.warn(log_prefix + "Failed to find open button for preview notice!"); + } else { + for(const element of buttons) { + (element).onclick = event => { + console.info(log_prefix + "Opening URL with default browser"); + electron.remote.shell.openExternal(location.href, { + activate: true + }).catch(error => { + console.warn(log_prefix + "Failed to open URL in browser window: %o", error); + }).then(() => { + window.close(); + }); + }; + } + } + } +}; + +/* Put this into the global scope. But we dont leek some nodejs stuff! */ +console.log(log_prefix + "Script loaded waiting to be called!"); +__teaclient_preview_notice = () => { + if(_inject_overlay) { + console.log(log_prefix + "TeaClient overlay called. Showing overlay."); + _inject_overlay(); + } else { + console.warn(log_prefix + "TeaClient overlay called, but overlay method undefined. May an load error occured?"); + } +}; + +const html_error = (error_code, error_desc, url) => +"
" + + "

Oops, this page failed to load correctly.

" + + "

ERROR [ " + error_code + ", " + error_desc + " ]

" + + '

' + + '

Try this

' + + '
  • Check your spelling - "' + url + '".

  • ' + + '
  • Refresh the page.

  • ' + + '
  • Perform a search instead.

  • ' + +"
    "; + +__teaclient_preview_error = (error_code, error_desc, url) => { + document.body.innerHTML = html_error(decodeURIComponent(error_code), decodeURIComponent(error_desc), decodeURIComponent(url)); + _inject_overlay = undefined; + if(_close_overlay) _close_overlay(); +}; \ No newline at end of file diff --git a/modules/core/url-preview/index.ts b/modules/core/url-preview/index.ts new file mode 100644 index 0000000..408ab4b --- /dev/null +++ b/modules/core/url-preview/index.ts @@ -0,0 +1,105 @@ +import * as electron from "electron"; +import * as path from "path"; +import * as winmgr from "../window"; + +let global_window: electron.BrowserWindow; +let global_window_promise: Promise; + +export async function close() { + while(global_window_promise) { + try { + await global_window_promise; + break; + } catch(error) {} /* error will be already logged */ + } + if(global_window) { + global_window.close(); + global_window = undefined; + global_window_promise = undefined; + } +} + +export async function open_preview(url: string) { + while(global_window_promise) { + try { + await global_window_promise; + break; + } catch(error) {} /* error will be already logged */ + } + if(!global_window) { + global_window_promise = (async () => { + global_window = new electron.BrowserWindow({ + webPreferences: { + nodeIntegration: true, + webviewTag: true + }, + center: true, + show: false, + }); + global_window.setMenuBarVisibility(false); + global_window.setMenu(null); + global_window.loadFile(path.join(__dirname, "html", "index.html")).then(() => { + //global_window.webContents.openDevTools(); + }); + global_window.on('close', event => { + global_window = undefined; + }); + + try { + await winmgr.apply_bounds('url-preview', global_window); + winmgr.track_bounds('url-preview', global_window); + + await new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject("timeout"), 5000); + global_window.on('ready-to-show', () => { + clearTimeout(timeout); + resolve(); + }); + }); + } catch(error) { + console.warn("Failed to initialize preview window. Dont show preview! Error: %o", error); + throw "failed to initialize"; + } + + global_window.show(); + })(); + try { + await global_window_promise; + } catch(error) { + console.log("Failed to create preview window! Error: %o", error); + try { + global_window.close(); + } finally { + global_window = undefined; + } + global_window_promise = undefined; + return; + } + } + + console.log("Opening URL '%s' as preview.", url); + global_window.webContents.send('preview', url); + if(!global_window.isFocused()) + global_window.focus(); +} + +electron.ipcMain.on('preview-action', (event, args) => { + const sender: electron.WebContents = event.sender; + if(!args || !args.action) { + console.warn("Received preview action without a valid action type!"); + return; + } + + if(args.action === "open-url") { + console.log("Opening " +args.url); + electron.shell.openExternal(args.url, { + activate: true + }); + + const browser = electron.BrowserWindow.fromWebContents(sender); + if(!browser) + console.warn("Failed to find browser handle"); + else + browser.close(); + } +}); \ No newline at end of file diff --git a/modules/core/window.ts b/modules/core/window.ts new file mode 100644 index 0000000..471eccd --- /dev/null +++ b/modules/core/window.ts @@ -0,0 +1,109 @@ +import * as electron from "electron"; +import * as fs from "fs-extra"; +import * as path from "path"; + +/* We read/write to this file every time again because this file could be used by multible processes */ +const data_file: string = path.join(electron.app.getPath('userData'), "window-bounds.json"); + +import BrowserWindow = Electron.BrowserWindow; +import Rectangle = Electron.Rectangle; + +let _changed_data: {[key: string]:Rectangle} = {}; +let _changed_saver: NodeJS.Timer; + +export async function save_changes() { + clearTimeout(_changed_saver); + + try { + const data = (await fs.pathExists(data_file) ? await fs.readJson(data_file) : {}) || {}; + Object.assign(data, _changed_data); + + await fs.ensureFile(data_file); + await fs.writeJson(data_file, data); + path_exists = true; + + _changed_data = {}; + } catch(error) { + console.warn("Failed to save window bounds: %o", error); + } + console.log("Window bounds have been successfully saved!"); +} + +let path_exists = undefined; +export async function get_last_bounds(key: string) : Promise { + try { + if(typeof(path_exists) === "undefined" ? !(path_exists = await fs.pathExists(data_file)) : !path_exists) + throw "skip!"; + + const data = await fs.readJson(data_file) || {}; + if(data[key]) + return data[key]; + } catch(error) { + if(error !== "skip!") + console.warn("Failed to load window bounds for %s: %o", key, error); + } + + return { + height: undefined, + width: undefined, + x: undefined, + y: undefined + } +} + +export function track_bounds(key: string, window: BrowserWindow) { + const events = ['move', 'moved', 'resize']; + + const update_bounds = () => { + _changed_data[key] = window.getBounds(); + + clearTimeout(_changed_saver); + _changed_saver = setTimeout(save_changes, 1000); + }; + + for(const event of events) + window.on(event as any, update_bounds); + + window.on('closed', () => { + for(const event of events) + window.removeListener(event as any, update_bounds); + }) +} + +export async function apply_bounds(key: string, window: BrowserWindow, bounds?: Rectangle, options?: { apply_size?: boolean; apply_position?: boolean }) { + const screen = electron.screen; + + if(!bounds) + bounds = await get_last_bounds(key); + + if(!options) + options = {}; + + const original_bounds = window.getBounds(); + + if(typeof(options.apply_size) !== "boolean" || options.apply_size) { + let height = bounds.height > 0 ? bounds.height : original_bounds.height; + let width = bounds.width > 0 ? bounds.width : original_bounds.width; + + if(height != original_bounds.height || width != original_bounds.width) + window.setSize(width, height, true); + } + if(typeof(options.apply_position) !== "boolean" || options.apply_position) { + let x = typeof(bounds.x) === "number" ? bounds.x : original_bounds.x; + let y = typeof(bounds.y) === "number" ? bounds.y : original_bounds.y; + + if(x != original_bounds.x || y != original_bounds.y) { + const display = screen.getDisplayNearestPoint({ x: x, y: y }); + if(display) { + const bounds = display.workArea || display.bounds; + let flag_invalid = false; + flag_invalid = flag_invalid || bounds.x > x || (bounds.x + bounds.width) < x; + flag_invalid = flag_invalid || bounds.y > x || (bounds.y + bounds.height) < y; + if(!flag_invalid) { + window.setPosition(x, y, true); + console.log("Updating position for %s", key); + } + } + } + } +} \ No newline at end of file diff --git a/modules/crash_handler/index.ts b/modules/crash_handler/index.ts new file mode 100644 index 0000000..7d67d7a --- /dev/null +++ b/modules/crash_handler/index.ts @@ -0,0 +1,103 @@ +import {app, BrowserWindow, remote} from "electron"; +import * as path from "path"; +import * as electron from "electron"; +import * as os from "os"; + +export function handle_crash_callback(args: string[]) { + const parameter = {}; + for(const argument of args) { + const colon_index = argument.indexOf('='); + if(colon_index == -1) { + console.warn("Crash callback contains invalid argument! (%s)", argument); + continue; + } + + parameter[argument.substr(0, colon_index)] = argument.substr(colon_index + 1); + } + console.log("Received crash dump callback. Arguments: %o", parameter); + + let error = undefined; + let crash_file = undefined; + + if(parameter["success"] == true) { + /* okey we have an crash dump */ + crash_file = parameter["dump_path"]; + if(typeof(crash_file) === "string") { + try { + crash_file = Buffer.from(crash_file, 'base64').toString(); + } catch(error) { + console.warn("Failed to decode dump path: %o", error); + crash_file = undefined; + error = "failed to decode dump path!"; + } + } + } else if(typeof(parameter["error"]) === "string") { + try { + error = Buffer.from(crash_file, 'base64').toString(); + } catch(error) { + console.warn("Failed to decode error: %o", error); + error = "failed to decode error"; + } + } else { + error = "missing parameters"; + } + + app.on('ready', () => { + const crash_window = new BrowserWindow({ + show: false, + width: 1000, + height: 300 + (os.platform() === "win32" ? 50 : 0), + + webPreferences: { + devTools: true, + nodeIntegration: true, + javascript: true + } + }); + crash_window.setMenu(null); + crash_window.loadFile(path.join(path.dirname(module.filename), "ui", "index.html")); + crash_window.on('ready-to-show', () => { + if(error) + crash_window.webContents.send('dump-error', error); + else if(!crash_file) + crash_window.webContents.send('dump-error', "Missing crash file"); + else + crash_window.webContents.send('dump-url', crash_file); + crash_window.show(); + }); + app.on('window-all-closed', () => { + process.exit(0); + }); + + crash_window.focus(); + }); +} + +module.paths.push(...(() => { + const app_path = (remote || electron).app.getAppPath(); + const result = []; + result.push(app_path + "/native/build/" + os.platform() + "_" + os.arch() + "/"); + if(app_path.endsWith(".asar")) + result.push(path.join(path.dirname(app_path), "natives")); + return result; +})()); + +export const handler = require( "teaclient_crash_handler"); + +export function initialize_handler(component_name: string, requires_file: boolean) { + const start_path = requires_file ? (" " + path.join(__dirname, "..", "..")) : ""; + const success_arguments = process.argv[0] + start_path + " crash-handler success=1 dump_path=%crash_path%"; + const error_arguments = process.argv[0] + start_path + " crash-handler success=0 error=%error_message%"; + + console.log("Setting up crash handler. Success callback: %s; Error callback: %s", success_arguments, error_arguments); + handler.setup_crash_handler( + component_name, + path.join((remote || electron).app.getPath('userData'), "crash_dumps"), + success_arguments, + error_arguments + ); +} + +export function finalize_handler() { + handler.finalize(); +} \ No newline at end of file diff --git a/modules/crash_handler/ui/crash_logo.svg b/modules/crash_handler/ui/crash_logo.svg new file mode 100644 index 0000000..77dc7a5 --- /dev/null +++ b/modules/crash_handler/ui/crash_logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/crash_handler/ui/index.css b/modules/crash_handler/ui/index.css new file mode 100644 index 0000000..6558a75 --- /dev/null +++ b/modules/crash_handler/ui/index.css @@ -0,0 +1,42 @@ +body { + background-color: grey; + min-width: 750px; + display: flex; + flex-direction: row; + justify-content: center; +} + +.container .container-header { + display: flex; + flex-direction: row; + justify-content: center; + width: fit-content; +} +.container .container-header > * { + flex-shrink: 0; +} +.container .container-header img { + vertical-align: middle; + display: inline-block; + width: 128px; + height: 128px; +} +.container .container-header .text { + margin-left: 20px; + display: inline-block; + text-align: left; + align-self: center; +} +.container .container-header .text h1 { + color: darkred; + margin-bottom: 0; +} +.container .container-header .text h2 { + font-size: 1.25em; + margin-top: 0.2em; +} +.container .error-dump { + color: red; +} + +/*# sourceMappingURL=index.css.map */ diff --git a/modules/crash_handler/ui/index.css.map b/modules/crash_handler/ui/index.css.map new file mode 100644 index 0000000..fd28355 --- /dev/null +++ b/modules/crash_handler/ui/index.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":"AAAA;EACC;EACA;EAEA;EACA;EACA;;;AAIA;EACC;EACA;EACA;EACA;;AAEA;EACC;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EAEA;EACA;EACA;;AAEA;EACC;EACA;;AAGD;EACC;EACA;;AAKH;EACC","file":"index.css"} \ No newline at end of file diff --git a/modules/crash_handler/ui/index.html b/modules/crash_handler/ui/index.html new file mode 100644 index 0000000..06358b8 --- /dev/null +++ b/modules/crash_handler/ui/index.html @@ -0,0 +1,36 @@ + + + + + Application crashed! + + + +
    +
    + +
    +

    Ooops, something went incredible wrong!

    +

    It seems like your TeaSpeak Client has been crashed.

    +
    +
    +
    +

    + Please report this crash to TeaSpeak and help improving the client!
    + Official issue and bug tracker url: https://github.com/TeaSpeak/TeaClient/issues
    + Attention: Crash reports without a crash dump file will be ignored! +

    +

    + Crash dump file: undefined +

    +

    + Failed to create crash dump file: +

    +
    +
    + + + + \ No newline at end of file diff --git a/modules/crash_handler/ui/index.scss b/modules/crash_handler/ui/index.scss new file mode 100644 index 0000000..4a98240 --- /dev/null +++ b/modules/crash_handler/ui/index.scss @@ -0,0 +1,51 @@ +body { + background-color: grey; + min-width: 750px; + + display: flex; + flex-direction: row; + justify-content: center; +} + +.container { + .container-header { + display: flex; + flex-direction: row; + justify-content: center; + width: fit-content; + + > * { + flex-shrink: 0; + } + + img { + vertical-align: middle; + display: inline-block; + + width: 128px; + height: 128px; + } + + .text { + margin-left: 20px; + + display: inline-block;; + text-align: left; + align-self: center; + + h1 { + color: darkred; + margin-bottom: 0; + } + + h2 { + font-size: 1.25em; + margin-top: .2em; + } + } + } + + .error-dump { + color: red; + } +} \ No newline at end of file diff --git a/modules/crash_handler/ui/index.ts b/modules/crash_handler/ui/index.ts new file mode 100644 index 0000000..205f84e --- /dev/null +++ b/modules/crash_handler/ui/index.ts @@ -0,0 +1,30 @@ +import { shell, ipcRenderer } from "electron"; + +function open_issue_tracker() { + shell.openExternal("https://github.com/TeaSpeak/TeaClient/issues"); +} + +function set_dump_error_flag(flag: boolean) { + for(const node of document.getElementsByClassName("error-show") as HTMLCollectionOf) + node.style.display = flag ? "block" : "none"; + + for(const node of document.getElementsByClassName("error-hide") as HTMLCollectionOf) + node.style.display = flag ? "none" : "block"; +} + +function set_dump_url(url: string) { + for(const crash_path_node of document.getElementsByClassName("crash-dump-directory") as HTMLCollectionOf) { + crash_path_node.textContent = url; + crash_path_node.onclick = () => shell.showItemInFolder(url); + } + set_dump_error_flag(false); +} + +function set_dump_error(error: string) { + set_dump_error_flag(true); + for(const node of document.getElementsByClassName("crash-dump-error") as HTMLCollectionOf) + node.textContent = error; +} + +ipcRenderer.on('dump-url', (event, url) => set_dump_url(url)); +ipcRenderer.on('dump-error', (event, error) => set_dump_error(error)); \ No newline at end of file diff --git a/modules/renderer/PersistentLocalStorage.ts b/modules/renderer/PersistentLocalStorage.ts new file mode 100644 index 0000000..7f07d79 --- /dev/null +++ b/modules/renderer/PersistentLocalStorage.ts @@ -0,0 +1,82 @@ +import * as electron from "electron"; +import * as path from "path"; +import * as fs from "fs-extra"; + +const APP_DATA = electron.remote.app.getPath("userData"); +const SETTINGS_DIR = path.join(APP_DATA, "settings"); + +let _local_storage: {[key: string]: any} = {}; +let _local_storage_save: {[key: string]: boolean} = {}; +export async function initialize() { + await fs.mkdirs(SETTINGS_DIR); + + const files = await fs.readdir(SETTINGS_DIR); + for(const file of files) { + const key = decodeURIComponent(file); + console.log("Load settings: %s", key); + + try { + const data = await fs.readFile(path.join(SETTINGS_DIR, file)); + const decoded = JSON.parse(data.toString() || "{}"); + + _local_storage[key] = decoded; + } catch(error) { + console.error("Failed to load settings for %s: %o", key, error); + } + } + + let _new_storage: Storage = {} as any; + + _new_storage.getItem = key => _local_storage[key] || null; + _new_storage.setItem = (key, value) => { + _local_storage[key] = value; + _local_storage_save[key] = true; + save_key(key).catch(error => { + console.warn("Failed to save key: %s => %o", key, error); + }); + (_new_storage as any)["length"] = Object.keys(_local_storage).length; + }; + + _new_storage.clear = () => { + _local_storage = {}; + _local_storage_save = {}; + + try { + fs.emptyDirSync(SETTINGS_DIR); + } catch(error) { + console.warn("Failed to empty settings dir"); + } + (_new_storage as any)["length"] = 0; + }; + + _new_storage.key = index => Object.keys(_local_storage)[index]; + _new_storage.removeItem = key => { + delete _local_storage[key]; + delete_key(key).catch(error => { + console.warn("Failed to delete key on fs: %s => %o", key, error); + }); + (_new_storage as any)["length"] = Object.keys(_local_storage).length; + }; + + Object.assign(window.localStorage, _new_storage); +} + +export async function save_all() { + let promises: Promise[] = []; + for(const key of Object.keys(_local_storage)) + promises.push(save_key(key)); + await Promise.all(promises); +} + +export async function save_key(key: string) { + if(!_local_storage_save[key]) + return; + + _local_storage_save[key] = false; + await fs.writeJson(path.join(SETTINGS_DIR, encodeURIComponent(key)), _local_storage[key], {spaces: 0}); +} + +export async function delete_key(key: string) { + delete _local_storage_save[key]; + await fs.remove(path.join(SETTINGS_DIR, encodeURIComponent(key))); +} \ No newline at end of file diff --git a/modules/renderer/audio/AudioPlayer.ts b/modules/renderer/audio/AudioPlayer.ts new file mode 100644 index 0000000..7bb6f38 --- /dev/null +++ b/modules/renderer/audio/AudioPlayer.ts @@ -0,0 +1,121 @@ +window["require_setup"](module); + +import {audio as naudio} from "teaclient_connection"; + +namespace audio.player { + export interface Device { + device_id: string; + name: string; + } + + interface Navigator { + mozGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void; + webkitGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void; + } + + let _initialized_callbacks: (() => any)[] = []; + export let _initialized = false; + export let _audioContext: AudioContext; + export let _processor: ScriptProcessorNode; + export let _output_stream: naudio.playback.OwnedAudioOutputStream; + export let _current_device: naudio.AudioDevice; + + export function initialized() : boolean { + return _initialized; + } + + + export function context() : AudioContext { + if(!_audioContext) throw "Initialize first!"; + return _audioContext; + } + + export function destination() : AudioNode { + if(!_initialized) + throw "Audio player hasn't yet be initialized"; + return _processor || _audioContext.destination; + } + + export function on_ready(cb: () => any) { + if(_initialized) + cb(); + else + _initialized_callbacks.push(cb); + } + + export function initialize() { + _output_stream = naudio.playback.create_stream(); + _output_stream.set_buffer_max_latency(0.4); + _output_stream.set_buffer_latency(0.02); + + _output_stream.callback_overflow = () => { + console.warn("Main audio overflow"); + _output_stream.clear(); + }; + _output_stream.callback_underflow = () => { + console.warn("Main audio underflow"); + }; + + _audioContext = new AudioContext(); + _processor = _audioContext.createScriptProcessor(1024 * 8, _output_stream.channels, _output_stream.channels); + + _processor.onaudioprocess = function(event) { + const buffer = event.inputBuffer; + //console.log("Received %d channels of %d with a rate of %d", buffer.numberOfChannels, buffer.length, buffer.sampleRate); + const target_buffer = new Float32Array(buffer.numberOfChannels * buffer.length); + + for(let channel = 0; channel < buffer.numberOfChannels; channel++) { + const channel_data = buffer.getChannelData(channel); + target_buffer.set(channel_data, channel * buffer.length); + } + _output_stream.write_data_rated(target_buffer.buffer, false, buffer.sampleRate); + }; + _processor.connect(_audioContext.destination); + + + _initialized = true; + for(const callback of _initialized_callbacks) + callback(); + _initialized_callbacks = []; + return true; + } + + export async function available_devices() : Promise { + return naudio.available_devices().filter(e => e.output_supported || e.output_default).map(e => { + return { + device_id: e.device_id, + name: e.name + } + }); + } + + export async function set_device(device_id?: string) : Promise { + const dev = naudio.available_devices().filter(e => e.device_id == device_id); + if(dev.length == 0) { + console.warn("Missing audio device with is %s", device_id) + throw "invalid device id"; + } + + await naudio.playback.set_device(dev[0].device_index); + _current_device = dev[0]; + } + + export function current_device() : Device { + if(_current_device) + return _current_device; + + const dev = naudio.available_devices().filter(e => e.output_default); + if(dev.length > 0) + return dev[0]; + return {device_id: "default", name: "default"} as Device; + } + + export function get_master_volume() : number { + return naudio.playback.get_master_volume(); + } + export function set_master_volume(volume: number) { + naudio.playback.set_master_volume(volume); + } +} + +Object.assign(window["audio"] || (window["audio"] = {} as any), audio); \ No newline at end of file diff --git a/modules/renderer/audio/AudioRecorder.ts b/modules/renderer/audio/AudioRecorder.ts new file mode 100644 index 0000000..aae649c --- /dev/null +++ b/modules/renderer/audio/AudioRecorder.ts @@ -0,0 +1,510 @@ +window["require_setup"](module); + +import {audio as naudio} from "teaclient_connection"; +//import {audio, tr} from "../imports/imports_shared"; +/// + +export namespace _audio.recorder { + import InputDevice = audio.recorder.InputDevice; + import AbstractInput = audio.recorder.AbstractInput; + + interface NativeDevice extends InputDevice { + device_index: number; + } + + let _device_cache: NativeDevice[] = undefined; + export function devices() : InputDevice[] { + return _device_cache || (_device_cache = naudio.available_devices().filter(e => e.input_supported || e.input_default).map(e => { + return { + unique_id: e.device_id, + channels: 2, /* TODO */ + default_input: e.input_default, + supported: e.input_supported, + name: e.name, + driver: e.driver, + sample_rate: 44100, /* TODO! */ + device_index: e.device_index, + } as NativeDevice + })); + } + + export function device_refresh_available() : boolean { return false; } + export function refresh_devices() : Promise { throw "not supported yet!"; } + + export function create_input() : AbstractInput { + return new NativeInput(); + } + + namespace filter { + export abstract class NativeFilter implements audio.recorder.filter.Filter { + type: audio.recorder.filter.Type; + handle: NativeInput; + enabled: boolean = false; + + protected constructor(handle, type) { this.handle = handle; this.type = type; } + + abstract initialize(); + abstract finalize(); + + + is_enabled(): boolean { return this.enabled; } + } + + export class NThresholdFilter extends NativeFilter implements audio.recorder.filter.ThresholdFilter { + private filter: naudio.record.ThresholdConsumeFilter; + + private _margin_frames: number = 6; /* 120ms */ + private _threshold: number = 50; + private _callback_level: any; + + private _attack_smooth = 0; + private _release_smooth = 0; + + callback_level: (level: number) => any; + + constructor(handle) { + super(handle, audio.recorder.filter.Type.THRESHOLD); + + Object.defineProperty(this, 'callback_level', { + get(): any { + return this._callback_level; + }, set(v: any): void { + if(v === this._callback_level) + return; + + this._callback_level = v; + if(this.filter) + this.filter.set_analyze_filter(v); + }, + enumerable: true, + configurable: false, + }) + } + + get_margin_frames(): number { + return this.filter ? this.filter.get_margin_frames() : this._margin_frames; + } + + get_threshold(): number { + return this.filter ? this.filter.get_threshold() : this._threshold; + } + + set_margin_frames(value: number) { + this._margin_frames = value; + if(this.filter) + this.filter.set_margin_frames(value); + } + + get_attack_smooth(): number { + return this.filter ? this.filter.get_attack_smooth() : this._attack_smooth; + } + + get_release_smooth(): number { + return this.filter ? this.filter.get_release_smooth() : this._release_smooth; + } + + set_attack_smooth(value: number) { + this._attack_smooth = value; + if(this.filter) + this.filter.set_attack_smooth(value); + } + + set_release_smooth(value: number) { + this._release_smooth = value; + if(this.filter) + this.filter.set_release_smooth(value); + } + + set_threshold(value: number): Promise { + if(typeof(value) === "string") + value = parseInt(value); /* yes... this happens */ + this._threshold = value; + if(this.filter) + this.filter.set_threshold(value); + return Promise.resolve(); + } + + finalize() { + if(this.filter) { + if(this.handle.consumer) + this.handle.consumer.unregister_filter(this.filter); + this.filter = undefined; + } + } + + initialize() { + if(!this.handle.consumer) + return; + + this.finalize(); + this.filter = this.handle.consumer.create_filter_threshold(this._threshold); + if(this._callback_level) + this.filter.set_analyze_filter(this._callback_level); + this.filter.set_margin_frames(this._margin_frames); + this.filter.set_attack_smooth(this._attack_smooth); + this.filter.set_release_smooth(this._release_smooth); + } + } + + export class NStateFilter extends NativeFilter implements audio.recorder.filter.StateFilter { + private filter: naudio.record.StateConsumeFilter; + private active = false; + + constructor(handle) { + super(handle, audio.recorder.filter.Type.STATE); + } + + finalize() { + if(this.filter) { + if(this.handle.consumer) + this.handle.consumer.unregister_filter(this.filter); + this.filter = undefined; + } + } + + initialize() { + if(!this.handle.consumer) + return; + + this.finalize(); + this.filter = this.handle.consumer.create_filter_state(); + this.filter.set_consuming(this.active); + } + + is_active(): boolean { + return this.active; + } + + async set_state(state: boolean): Promise { + if(this.active === state) + return; + this.active = state; + if(this.filter) + this.filter.set_consuming(state); + } + } + + export class NVoiceLevelFilter extends NativeFilter implements audio.recorder.filter.VoiceLevelFilter { + private filter: naudio.record.VADConsumeFilter; + private level = 3; + private _margin_frames = 5; + + constructor(handle) { + super(handle, audio.recorder.filter.Type.VOICE_LEVEL); + } + + finalize() { + if(this.filter) { + if(this.handle.consumer) + this.handle.consumer.unregister_filter(this.filter); + this.filter = undefined; + } + } + + initialize() { + if(!this.handle.consumer) + return; + + this.finalize(); + this.filter = this.handle.consumer.create_filter_vad(this.level); + this.filter.set_margin_frames(this._margin_frames); + } + + get_level(): number { + return this.level; + } + + set_level(value: number) { + if(this.level === value) + return; + + this.level = value; + if(this.filter) { + this.finalize(); + this.initialize(); + } + } + + set_margin_frames(value: number) { + this._margin_frames = value; + if(this.filter) + this.filter.set_margin_frames(value); + } + + get_margin_frames(): number { + return this.filter ? this.filter.get_margin_frames() : this._margin_frames; + } + } + } + + export class NativeInput implements AbstractInput { + private handle: naudio.record.AudioRecorder; + consumer: naudio.record.AudioConsumer; + + private _current_device: audio.recorder.InputDevice; + private _current_state: audio.recorder.InputState = audio.recorder.InputState.PAUSED; + + callback_begin: () => any; + callback_end: () => any; + + private filters: filter.NativeFilter[] = []; + + constructor() { + this.handle = naudio.record.create_recorder(); + + this.consumer = this.handle.create_consumer(); + this.consumer.callback_ended = () => { + if(this._current_state !== audio.recorder.InputState.RECORDING) + return; + + this._current_state = audio.recorder.InputState.DRY; + if(this.callback_end) + this.callback_end(); + }; + this.consumer.callback_started = () => { + if(this._current_state !== audio.recorder.InputState.DRY) + return; + + this._current_state = audio.recorder.InputState.RECORDING; + if(this.callback_begin) + this.callback_begin(); + }; + + this._current_state = audio.recorder.InputState.PAUSED; + } + + /* TODO: some kind of finalize? */ + current_consumer(): audio.recorder.InputConsumer | undefined { + return { + type: audio.recorder.InputConsumerType.NATIVE + }; + } + + async set_consumer(consumer: audio.recorder.InputConsumer): Promise { + if(typeof(consumer) !== "undefined") + throw "we only support native consumers!"; /* TODO: May create a general wrapper? */ + return; + } + + async set_device(_device: audio.recorder.InputDevice | undefined): Promise { + if(_device === this._current_device) + return; + + const device = _device as NativeDevice; /* TODO: test for? */ + this._current_device = _device; + try { + await new Promise((resolve, reject) => { + this.handle.set_device(device ? device.device_index : -1, flag => { + if(typeof(flag) === "boolean" && flag) + resolve(); + else + reject("failed to set device" + (typeof(flag) === "string" ? (": " + flag) : "")); + }); + }); + if(!device) return; + + await new Promise((resolve, reject) => { + this.handle.start(flag => { + if(flag) + resolve(); + else + reject("start failed"); + }); + }); + } catch(error) { + console.warn(tr("Failed to start playback on new input device (%o)"), error); + throw error; + } + } + + current_device(): audio.recorder.InputDevice | undefined { + return this._current_device; + } + + current_state(): audio.recorder.InputState { + return this._current_state; + } + + disable_filter(type: audio.recorder.filter.Type) { + const filter = this.get_filter(type) as filter.NativeFilter; + if(filter.is_enabled()) + filter.enabled = false; + filter.finalize(); + } + + enable_filter(type: audio.recorder.filter.Type) { + const filter = this.get_filter(type) as filter.NativeFilter; + if(!filter.is_enabled()) { + filter.enabled = true; + filter.initialize(); + } + } + + clear_filter() { + for(const filter of this.filters) { + filter.enabled = false; + filter.finalize(); + } + } + + get_filter(type: audio.recorder.filter.Type): audio.recorder.filter.Filter | undefined { + for(const filter of this.filters) + if(filter.type === type) + return filter; + + let _filter: filter.NativeFilter; + switch (type) { + case audio.recorder.filter.Type.THRESHOLD: + _filter = new filter.NThresholdFilter(this); + break; + case audio.recorder.filter.Type.STATE: + _filter = new filter.NStateFilter(this); + break; + case audio.recorder.filter.Type.VOICE_LEVEL: + _filter = new filter.NVoiceLevelFilter(this); + break; + default: + throw "this filter isn't supported!"; + } + this.filters.push(_filter); + return _filter; + } + + supports_filter(type: audio.recorder.filter.Type) : boolean { + switch (type) { + case audio.recorder.filter.Type.THRESHOLD: + case audio.recorder.filter.Type.STATE: + case audio.recorder.filter.Type.VOICE_LEVEL: + return true; + default: + return false; + } + } + + async start(): Promise { + try { + await this.stop(); + } catch(error) { + console.warn(tr("Failed to stop old record session before start (%o)"), error); + } + + this._current_state = audio.recorder.InputState.DRY; + try { + await new Promise((resolve, reject) => { + this.handle.start(flag => { + if(flag) + resolve(); + else + reject("start failed"); + }); + }); + for(const filter of this.filters) + if(filter.is_enabled()) + filter.initialize(); + return audio.recorder.InputStartResult.EOK; + } catch(error) { + this._current_state = audio.recorder.InputState.PAUSED; + throw error; + } + } + + async stop(): Promise { + this.handle.stop(); + for(const filter of this.filters) + filter.finalize(); + if(this.callback_end) + this.callback_end(); + this._current_state = audio.recorder.InputState.PAUSED; + } + + get_volume(): number { + return this.handle.get_volume(); + } + + set_volume(volume: number) { + this.handle.set_volume(volume); + } + } + + export async function create_levelmeter(device: InputDevice) : Promise { + const meter = new NativeLevelmenter(device as any); + await meter.initialize(); + return meter; + } + + class NativeLevelmenter implements audio.recorder.LevelMeter { + readonly _device: NativeDevice; + + private _callback: (num: number) => any; + private _recorder: naudio.record.AudioRecorder; + private _consumer: naudio.record.AudioConsumer; + private _filter: naudio.record.ThresholdConsumeFilter; + + constructor(device: NativeDevice) { + this._device = device; + } + + async initialize() { + try { + this._recorder = naudio.record.create_recorder(); + this._consumer = this._recorder.create_consumer(); + + this._filter = this._consumer.create_filter_threshold(.5); + this._filter.set_attack_smooth(.75); + this._filter.set_release_smooth(.75); + + await new Promise((resolve, reject) => { + this._recorder.set_device(this._device.device_index, flag => { + if(typeof(flag) === "boolean" && flag) + resolve(); + else + reject("initialize failed" + (typeof(flag) === "string" ? (": " + flag) : "")); + }); + }); + await new Promise((resolve, reject) => { + this._recorder.start(flag => { + if(flag) + resolve(); + else + reject("start failed"); + }); + }); + } catch(error) { + if(typeof(error) === "string") + throw error; + console.warn(tr("Failed to initialize levelmeter for device %o: %o"), this._device, error); + throw "initialize failed (lookup console)"; + } + + /* references this variable, needs a destory() call, else memory leak */ + this._filter.set_analyze_filter(value => { + (this._callback || (() => {}))(value); + }); + } + + destory() { + if(this._filter) { + this._filter.set_analyze_filter(undefined); + this._consumer.unregister_filter(this._filter); + } + if(this._consumer) + this._recorder.delete_consumer(this._consumer); + this._recorder.stop(); + this._recorder.set_device(-1, () => {}); /* -1 := No device */ + this._recorder = undefined; + this._consumer = undefined; + this._filter = undefined; + } + + device(): audio.recorder.InputDevice { + return this._device; + } + + set_observer(callback: (value: number) => any) { + this._callback = callback; + } + } +} + +Object.assign(window["audio"] || (window["audio"] = {} as any), _audio); +_audio.recorder.devices(); /* query devices */ \ No newline at end of file diff --git a/modules/renderer/connection/FileTransfer.ts b/modules/renderer/connection/FileTransfer.ts new file mode 100644 index 0000000..e182ed4 --- /dev/null +++ b/modules/renderer/connection/FileTransfer.ts @@ -0,0 +1,186 @@ +/// + + +window["require_setup"](module); +import * as native from "teaclient_connection"; +import * as path from "path"; + +namespace _transfer { + class NativeFileDownload implements transfer.DownloadTransfer { + readonly key: transfer.DownloadKey; + private _handle: native.ft.NativeFileTransfer; + private _buffer: Uint8Array; + + private _result: Promise; + private _response: Response; + + private _result_success: () => any; + private _result_error: (error: any) => any; + + constructor(key: transfer.DownloadKey) { + this.key = key; + this._buffer = new Uint8Array(key.total_size); + this._handle = native.ft.spawn_connection({ + client_transfer_id: key.client_transfer_id, + server_transfer_id: key.server_transfer_id, + + remote_address: key.peer.hosts[0], + remote_port: key.peer.port, + + transfer_key: key.key, + + object: native.ft.download_transfer_object_from_buffer(this._buffer.buffer) + }); + } + + get_key(): transfer.DownloadKey { + return this.key; + } + + async request_file(): Promise { + if(this._response) + return this._response; + + try { + await (this._result || this._start_transfer()); + } catch(error) { + throw error; + } + + if(this._response) + return this._response; + + const buffer = this._buffer.buffer.slice(this._buffer.byteOffset, this._buffer.byteOffset + Math.min(64, this._buffer.byteLength)); + + /* may another task has been stepped by and already set the response */ + return this._response || (this._response = new Response(this._buffer, { + status: 200, + statusText: "success", + headers: { + "X-media-bytes": base64_encode_ab(buffer) + + } + })); + } + + _start_transfer() : Promise { + return this._result = new Promise((resolve, reject) => { + this._result_error = (error) => { + this._result_error = undefined; + this._result_success = undefined; + reject(error); + }; + this._result_success = () => { + this._result_error = undefined; + this._result_success = undefined; + resolve(); + }; + + this._handle.callback_failed = this._result_error; + this._handle.callback_finished = aborted => { + if(aborted) + this._result_error("aborted"); + else + this._result_success(); + }; + + this._handle.start(); + }); + } + } + + class NativeFileUpload implements transfer.UploadTransfer { + readonly transfer_key: transfer.UploadKey; + private _handle: native.ft.NativeFileTransfer; + + private _result: Promise; + + private _result_success: () => any; + private _result_error: (error: any) => any; + + constructor(key: transfer.UploadKey) { + this.transfer_key = key; + } + + async put_data(data: BlobPart | File) : Promise { + if(this._result) { + await this._result; + return; + } + + let buffer: native.ft.FileTransferSource; + + if(data instanceof File) { + if(data.size != this.transfer_key.total_size) + throw "invalid size"; + + buffer = native.ft.upload_transfer_object_from_file(path.dirname(data.path), data.name); + } else if(typeof(data) === "string") { + if(data.length != this.transfer_key.total_size) + throw "invalid size"; + + buffer = native.ft.upload_transfer_object_from_buffer(str2ab8(data)); + } else { + let buf = data; + if(buf.byteLength != this.transfer_key.total_size) + throw "invalid size"; + + if(ArrayBuffer.isView(buf)) + buf = buf.buffer.slice(buf.byteOffset); + + buffer = native.ft.upload_transfer_object_from_buffer(buf); + } + + this._handle = native.ft.spawn_connection({ + client_transfer_id: this.transfer_key.client_transfer_id, + server_transfer_id: this.transfer_key.server_transfer_id, + + remote_address: this.transfer_key.peer.hosts[0], + remote_port: this.transfer_key.peer.port, + + transfer_key: this.transfer_key.key, + + object: buffer + }); + + await (this._result = new Promise((resolve, reject) => { + this._result_error = (error) => { + this._result_error = undefined; + this._result_success = undefined; + reject(error); + }; + this._result_success = () => { + this._result_error = undefined; + this._result_success = undefined; + resolve(); + }; + + this._handle.callback_failed = this._result_error; + this._handle.callback_finished = aborted => { + if(aborted) + this._result_error("aborted"); + else + this._result_success(); + }; + + this._handle.start(); + })); + } + + get_key(): transfer.UploadKey { + return this.transfer_key; + } + } + + + export function spawn_download_transfer(key: transfer.DownloadKey) : transfer.DownloadTransfer { + return new NativeFileDownload(key); + } + + + export function spawn_upload_transfer(key: transfer.UploadKey) : transfer.UploadTransfer { + return new NativeFileUpload(key); + } +} + +Object.assign(window["transfer"] || (window["transfer"] = {} as any), _transfer); \ No newline at end of file diff --git a/modules/renderer/connection/ServerConnection.ts b/modules/renderer/connection/ServerConnection.ts new file mode 100644 index 0000000..14025ef --- /dev/null +++ b/modules/renderer/connection/ServerConnection.ts @@ -0,0 +1,318 @@ +/// + +window["require_setup"](module); +import { + destroy_server_connection as _destroy_server_connection, + NativeServerConnection, + ServerType, + spawn_server_connection as _spawn_server_connection +} from "teaclient_connection"; +import {_audio} from "./VoiceConnection"; + +export namespace _connection { + export namespace native { + import VoiceConnection = _audio.native.VoiceConnection; + + class ErrorCommandHandler extends connection.AbstractCommandHandler { + private _handle: ServerConnection; + + constructor(handle: ServerConnection) { + super(handle); + this._handle = handle; + } + + handle_command(command: connection.ServerCommand): boolean { + if(command.command === "error") { + const return_listener: {[key: string]: (result: CommandResult) => any} = this._handle["_return_listener"]; + const data = command.arguments[0]; + + let return_code : string = data["return_code"]; + if(!return_code) { + const listener = return_listener["last_command"] || return_listener["_clientinit"]; + if(typeof(listener) === "function") { + console.warn(tr("Received error without return code. Using last command (%o)"), listener); + listener(new CommandResult(data)); + delete return_listener["last_command"]; + delete return_listener["_clientinit"]; + } else { + console.warn(tr("Received error without return code."), data); + } + return false; + } + + if(return_listener[return_code]) { + return_listener[return_code](new CommandResult(data)); + } else { + console.warn(tr("Error received for no handler! (%o)"), data); + } + return true; + } else if(command.command == "initivexpand") { + if(command.arguments[0]["teaspeak"] == true) { + console.log("Using TeaSpeak identity type"); + this._handle.handshake_handler().startHandshake(); + } + return true; + } else if(command.command == "initivexpand2") { + /* its TeamSpeak or TeaSpeak with experimental 3.1 and not up2date */ + this._handle["_do_teamspeak"] = true; + } else if(command.command == "initserver") { + const return_listener: {[key: string]: (result: CommandResult) => any} = this._handle["_return_listener"]; + + if(typeof(return_listener["_clientinit"]) === "function") { + return_listener["_clientinit"](new CommandResult({id: 0, message: ""})); + delete return_listener["_clientinit"]; + } + + if(this._handle.onconnectionstatechanged) + this._handle.onconnectionstatechanged(ConnectionState.INITIALISING, ConnectionState.CONNECTING); + } else if(command.command == "notifyconnectioninforequest") { + this._handle.send_command("setconnectioninfo", + { + //TODO calculate + connection_ping: 0.0000, + connection_ping_deviation: 0.0, + + connection_packets_sent_speech: 0, + connection_packets_sent_keepalive: 0, + connection_packets_sent_control: 0, + connection_bytes_sent_speech: 0, + connection_bytes_sent_keepalive: 0, + connection_bytes_sent_control: 0, + connection_packets_received_speech: 0, + connection_packets_received_keepalive: 0, + connection_packets_received_control: 0, + connection_bytes_received_speech: 0, + connection_bytes_received_keepalive: 0, + connection_bytes_received_control: 0, + connection_server2client_packetloss_speech: 0.0000, + connection_server2client_packetloss_keepalive: 0.0000, + connection_server2client_packetloss_control: 0.0000, + connection_server2client_packetloss_total: 0.0000, + connection_bandwidth_sent_last_second_speech: 0, + connection_bandwidth_sent_last_second_keepalive: 0, + connection_bandwidth_sent_last_second_control: 0, + connection_bandwidth_sent_last_minute_speech: 0, + connection_bandwidth_sent_last_minute_keepalive: 0, + connection_bandwidth_sent_last_minute_control: 0, + connection_bandwidth_received_last_second_speech: 0, + connection_bandwidth_received_last_second_keepalive: 0, + connection_bandwidth_received_last_second_control: 0, + connection_bandwidth_received_last_minute_speech: 0, + connection_bandwidth_received_last_minute_keepalive: 0, + connection_bandwidth_received_last_minute_control: 0 + } + ); + } + return false; + } + } + + export class ServerConnection extends connection.AbstractServerConnection { + private _native_handle: NativeServerConnection; + private _voice_connection: VoiceConnection; + + private _do_teamspeak: boolean; + private _return_listener: {[key: string]: (result: CommandResult) => any} = {}; + + private _command_handler: NativeConnectionCommandBoss; + private _command_error_handler: ErrorCommandHandler; + private _command_handler_default: connection.ConnectionCommandHandler; + + private _remote_address: ServerAddress; + private _handshake_handler: connection.HandshakeHandler; + + private _return_code_index: number = 0; + + onconnectionstatechanged: connection.ConnectionStateListener; + + constructor(props: ConnectionHandler) { + super(props); + + this._command_handler = new NativeConnectionCommandBoss(this); + this._command_error_handler = new ErrorCommandHandler(this); + this._command_handler_default = new connection.ConnectionCommandHandler(this); + + this._command_handler.register_handler(this._command_error_handler); + this._command_handler.register_handler(this._command_handler_default); + + this._native_handle = _spawn_server_connection(); + this._native_handle.callback_disconnect = reason => { + this.client.handleDisconnect(DisconnectReason.CONNECTION_CLOSED, { + reason: reason, + event: event + }); + }; + this._native_handle.callback_command = (command, args, switches) => { + console.log("Received: %o %o %o", command, args, switches); + //FIXME catch error + + this._command_handler.invoke_handle({ + command: command, + arguments: args + }); + }; + this._voice_connection = new VoiceConnection(this, this._native_handle._voice_connection); + + this.command_helper.initialize(); + this._voice_connection.setup(); + } + + native_handle() : NativeServerConnection { + return this._native_handle; + } + + finalize() { + if(this._native_handle) + _destroy_server_connection(this._native_handle); + this._native_handle = undefined; + } + + connect(address: ServerAddress, handshake: connection.HandshakeHandler, timeout?: number): Promise { + this._remote_address = address; + this._handshake_handler = handshake; + this._do_teamspeak = false; + handshake.setConnection(this); + handshake.initialize(); + + return new Promise((resolve, reject) => { + this._native_handle.connect({ + remote_host: address.host, + remote_port: address.port, + + timeout: typeof(timeout) === "number" ? timeout : -1, + + + callback: error => { + if(error != 0) { + /* required to notify the handle, just a promise reject does not work */ + this.client.handleDisconnect(DisconnectReason.CONNECT_FAILURE, error); + reject(this._native_handle.error_message(error)); + return; + } else { + resolve(); + } + + console.log("Remote server type: %o (%s)", this._native_handle.server_type, ServerType[this._native_handle.server_type]); + if(this._native_handle.server_type == ServerType.TEAMSPEAK || this._do_teamspeak) { + console.log("Trying to use TeamSpeak's identity system"); + this.handshake_handler().on_teamspeak(); + } + }, + + identity_key: (handshake.get_identity_handler() as profiles.identities.TeaSpeakHandshakeHandler).identity.private_key, + teamspeak: false + }) + }); + } + + + remote_address(): ServerAddress { + return this._remote_address; + } + + handshake_handler(): connection.HandshakeHandler { + return this._handshake_handler; + } + + connected(): boolean { + return typeof(this._native_handle) !== "undefined" && this._native_handle.connected(); + } + + disconnect(reason?: string): Promise { + console.trace("Disconnect: %s",reason); + return new Promise((resolve, reject) => this._native_handle.disconnect(reason || "", error => { + if(error == 0) + resolve(); + else + reject(this._native_handle.error_message(error)); + })); + } + + support_voice(): boolean { + return true; + } + + voice_connection(): connection.voice.AbstractVoiceConnection { + return this._voice_connection; + } + + command_handler_boss(): connection.AbstractCommandHandlerBoss { + return this._command_handler; + } + + private generate_return_code() : string { + return (this._return_code_index++).toString(); + } + + send_command(command: string, data?: any, _options?: connection.CommandOptions): Promise { + if(!this.connected()) { + console.warn(tr("Tried to send a command without a valid connection.")); + return Promise.reject(tr("not connected")); + } + + const options: connection.CommandOptions = {}; + Object.assign(options, connection.CommandOptionDefaults); + Object.assign(options, _options); + + data = $.isArray(data) ? data : [data || {}]; + if(data.length == 0) /* we require min one arg to append return_code */ + data.push({}); + + let return_code = data[0]["return_code"] !== undefined ? data[0].return_code : this.generate_return_code(); + data[0]["return_code"] = return_code; + + console.log("Sending %s (%o)", command, data); + const promise = new Promise((resolve, reject) => { + const timeout_id = setTimeout(() => { + delete this._return_listener[return_code]; + reject("timeout"); + }, 5000); + + this._return_listener[return_code] = result => { + clearTimeout(timeout_id); + delete this._return_listener[return_code]; + + (result.success ? resolve : reject)(result); + }; + + if(command == "clientinit") + this._return_listener["_clientinit"] = this._return_listener[return_code]; /* fix for TS3 (clientinit does not accept a return code) */ + + try { + this._native_handle.send_command(command, data, options.flagset || []); + } catch(error) { + console.warn(tr("Failed to send command: %o"), error); + } + }); + return this._command_handler_default.proxy_command_promise(promise, options); + } + + ping(): { native: number; javascript?: number } { + return { + native: this._native_handle ? (this._native_handle.current_ping() / 1000) : -2 + }; + } + } + } + + export class NativeConnectionCommandBoss extends connection.AbstractCommandHandlerBoss { + constructor(connection: connection.AbstractServerConnection) { + super(connection); + } + } + + + /* override the "normal" connection */ + export function spawn_server_connection(handle: ConnectionHandler) : connection.AbstractServerConnection { + console.log("Spawning native connection"); + return new native.ServerConnection(handle); /* will be overridden by the client */ + } + + export function destroy_server_connection(handle: connection.AbstractServerConnection) { + if(!(handle instanceof native.ServerConnection)) + throw "invalid handle"; + //TODO: Here! + console.log("Call to destroy a server connection"); + } +} +Object.assign(window["connection"] || (window["connection"] = {} as any), _connection); \ No newline at end of file diff --git a/modules/renderer/connection/VoiceConnection.ts b/modules/renderer/connection/VoiceConnection.ts new file mode 100644 index 0000000..598be06 --- /dev/null +++ b/modules/renderer/connection/VoiceConnection.ts @@ -0,0 +1,161 @@ +import {_connection} from "./ServerConnection"; +import {_audio as _recorder} from "../audio/AudioRecorder"; + +import { + NativeVoiceConnection, + NativeVoiceClient +} from "teaclient_connection"; + +export namespace _audio { + export namespace native { + import ServerConnection = _connection.native.ServerConnection; + + export class VoiceConnection extends connection.voice.AbstractVoiceConnection { + readonly connection: ServerConnection; + readonly handle: NativeVoiceConnection; + + private _audio_source: RecorderProfile; + + constructor(connection: ServerConnection, voice: NativeVoiceConnection) { + super(connection); + this.connection = connection; + this.handle = voice; + } + + setup() { } + + async acquire_voice_recorder(recorder: RecorderProfile | undefined, enforce?: boolean) { + if(this._audio_source === recorder && !enforce) + return; + + if(this._audio_source) + await this._audio_source.unmount(); + + if(recorder) { + if(!(recorder.input instanceof _recorder.recorder.NativeInput)) + throw "Recorder input must be an instance of NativeInput!"; + await recorder.unmount(); + } + + this.handleVoiceEnded(); + this._audio_source = recorder; + + if(recorder) { + recorder.current_handler = this.connection.client; + + recorder.callback_unmount = () => { + this._audio_source = undefined; + this.handle.set_audio_source(undefined); + this.connection.client.update_voice_status(undefined); + }; + + recorder.callback_start = this.on_voice_started.bind(this); + recorder.callback_stop = this.handleVoiceEnded.bind(this); + + recorder.callback_support_change = () => { + this.connection.client.update_voice_status(undefined); + }; + + this.handle.set_audio_source((recorder.input as _recorder.recorder.NativeInput).consumer); + } + this.connection.client.update_voice_status(undefined); + } + + voice_playback_support() : boolean { + return this.connection.connected(); + } + + voice_send_support() : boolean { + return this.connection.connected(); + } + + private current_channel_codec() : number { + const chandler = this.connection.client; + return (chandler.getClient().currentChannel() || {properties: { channel_codec: 4}}).properties.channel_codec; + } + + private handleVoiceEnded() { + const chandler = this.connection.client; + chandler.getClient().speaking = false; + + if(!chandler.connected) + return false; + + if(chandler.client_status.input_muted) + return false; + + console.log(tr("Local voice ended")); + //TODO + } + + private on_voice_started() { + const chandler = this.connection.client; + if(chandler.client_status.input_muted) { + /* evil hack due to the settings :D */ + log.warn(LogCategory.VOICE, tr("Received local voice started event, even thou we're muted! Do not send any voice.")); + if(this.handle) { + this.handle.enable_voice_send(false); + } + return; + } + + log.info(LogCategory.VOICE, tr("Local voice started")); + this.handle.enable_voice_send(true); + + const ch = chandler.getClient(); + if(ch) ch.speaking = true; + } + + connected(): boolean { + return true; /* we cant be disconnected at any time! */ + } + + voice_recorder(): RecorderProfile { + return this._audio_source; + } + + available_clients(): connection.voice.VoiceClient[] { + return this.handle.available_clients(); + } + + find_client(client_id: number) : connection.voice.VoiceClient | undefined { + for(const client of this.available_clients()) + if(client.client_id === client_id) + return client; + return undefined; + } + + unregister_client(client: connection.voice.VoiceClient): Promise { + this.handle.unregister_client(client.client_id); + return Promise.resolve(); + } + + register_client(client_id: number): connection.voice.VoiceClient { + const client = this.handle.register_client(client_id); + if(!client) + return client; + + const stream = client.get_stream(); + stream.set_buffer_latency(0.02); + stream.set_buffer_max_latency(0.2); + return client; + } + + decoding_supported(codec: number): boolean { + return this.handle.decoding_supported(codec); + } + + encoding_supported(codec: number): boolean { + return this.handle.encoding_supported(codec); + } + + get_encoder_codec(): number { + return this.handle.get_encoder_codec(); + } + + set_encoder_codec(codec: number) { + return this.handle.set_encoder_codec(codec); + } + } + } +} \ No newline at end of file diff --git a/modules/renderer/context-menu.ts b/modules/renderer/context-menu.ts new file mode 100644 index 0000000..6c1805a --- /dev/null +++ b/modules/renderer/context-menu.ts @@ -0,0 +1,130 @@ +import {class_to_image} from "./icon-helper"; + +window["require_setup"](module); + +import * as electron from "electron"; +const remote = electron.remote; +const {Menu, MenuItem} = remote; + +import {isFunction} from "util"; + +class ElectronContextMenu implements contextmenu.ContextMenuProvider { + private _close_listeners: (() => any)[] = []; + private _current_menu: electron.Menu; + + private _div: JQuery; + + despawn_context_menu() { + if(!this._current_menu) + return; + this._current_menu.closePopup(); + this._current_menu = undefined; + + for(const listener of this._close_listeners) { + if(listener) { + listener(); + } + } + this._close_listeners = []; + } + + finalize() { + if(this._div) this._div.detach(); + this._div = undefined; + } + + initialize() { + } + + + private _entry_id = 0; + private build_menu(entry: contextmenu.MenuEntry) : electron.MenuItem { + if(entry.type == contextmenu.MenuEntryType.CLOSE) { + this._close_listeners.push(entry.callback); + return undefined; + } + + const click_callback = () => { + if(entry.callback) + entry.callback(); + this.despawn_context_menu(); + }; + const _id = "entry_" + (this._entry_id++); + if(entry.type == contextmenu.MenuEntryType.ENTRY) { + return new MenuItem({ + id: _id, + label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string, + type: "normal", + click: click_callback, + icon: class_to_image(entry.icon_class), + visible: entry.visible, + enabled: !entry.disabled + }); + } else if(entry.type == contextmenu.MenuEntryType.HR) { + if(typeof(entry.visible) === "boolean" && !entry.visible) + return undefined; + + return new MenuItem({ + id: _id, + type: "separator", + label: '', + click: click_callback + }) + } else if(entry.type == contextmenu.MenuEntryType.CHECKBOX) { + return new MenuItem({ + id: _id, + label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string, + type: "checkbox", + checked: !!entry.checkbox_checked, + click: click_callback, + icon: class_to_image(entry.icon_class), + visible: entry.visible, + enabled: !entry.disabled + }); + } else if (entry.type == contextmenu.MenuEntryType.SUB_MENU) { + const sub_menu = new Menu(); + for(const e of entry.sub_menu) { + const build = this.build_menu(e); + if(!build) + continue; + sub_menu.append(build); + } + return new MenuItem({ + id: _id, + label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string, + type: "submenu", + submenu: sub_menu, + click: click_callback, + icon: class_to_image(entry.icon_class), + visible: entry.visible, + enabled: !entry.disabled + }); + } + return undefined; + } + + spawn_context_menu(x: number, y: number, ...entries: contextmenu.MenuEntry[]) { + this.despawn_context_menu(); + + this._current_menu = new Menu(); + for(const entry of entries) { + const build = this.build_menu(entry); + if(!build) + continue; + this._current_menu.append(build); + } + + this._current_menu.popup({ + window: remote.getCurrentWindow(), + x: x, + y: y, + callback: () => this.despawn_context_menu() + }); + } + + html_format_enabled() { return false; } +} + +contextmenu.set_provider(new ElectronContextMenu()); + +export {}; \ No newline at end of file diff --git a/modules/renderer/dns/dns_resolver.ts b/modules/renderer/dns/dns_resolver.ts new file mode 100644 index 0000000..396ccf5 --- /dev/null +++ b/modules/renderer/dns/dns_resolver.ts @@ -0,0 +1,38 @@ +/// + +window["require_setup"](module); +import * as dns_handler from "teaclient_dns"; + +namespace _dns { + export function supported() { return true; } + export async function resolve_address(address: ServerAddress, _options?: dns.ResolveOptions) : Promise { + /* backwards compatibility */ + if(typeof(address) === "string") { + address = { + host: address, + port: 9987 + } + } + + return new Promise((resolve, reject) => { + dns_handler.resolve_cr(address.host, address.port, result => { + if(typeof(result) === "string") + reject(result); + else + resolve({ + target_ip: result.host, + target_port: result.port + }); + }); + }) + } +} + +Object.assign(window["dns"] || (window["dns"] = {} as any), _dns); +loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, { + name: "Native DNS initialized", + function: async () => { + dns_handler.initialize(); + }, + priority: 10 +}); \ No newline at end of file diff --git a/modules/renderer/icon-helper.ts b/modules/renderer/icon-helper.ts new file mode 100644 index 0000000..d18f490 --- /dev/null +++ b/modules/renderer/icon-helper.ts @@ -0,0 +1,63 @@ +import * as electron from "electron"; +import NativeImage = electron.NativeImage; + +let _div: JQuery; +let _icon_mash_url: string; +let _icon_mask_img: NativeImage; +let _cache_klass_map: {[key: string]: NativeImage}; + +export function class_to_image(klass: string) : NativeImage { + if(!klass || !_icon_mask_img || !_cache_klass_map) + return undefined; + + if(_cache_klass_map[klass]) + return _cache_klass_map[klass]; + + _div[0].classList.value = 'icon ' + klass; + const data = window.getComputedStyle(_div[0]); + + const offset_x = parseInt(data.backgroundPositionX.split(",")[0]); + const offset_y = parseInt(data.backgroundPositionY.split(",")[0]); + + //http://localhost/home/TeaSpeak/Web-Client/web/environment/development/img/client_icon_sprite.svg + //const hight = element.css('height'); + //const width = element.css('width'); + console.log("Offset: x: %o y: %o;", offset_x, offset_y); + return _cache_klass_map[klass] = _icon_mask_img.crop({ + height: 16, + width: 16, + x: offset_x == 0 ? 0 : -offset_x, + y: offset_y == 0 ? 0 : -offset_y + }); +} + +export async function initialize() { + if(!_div) { + _div = $.spawn("div"); + _div.css('display', 'none'); + _div.appendTo(document.body); + } + + const image = new Image(); + image.src = 'img/client_icon_sprite.svg'; + await new Promise((resolve, reject) => { + image.onload = resolve; + image.onerror = reject; + }); + + /* TODO: Get a size! */ + const canvas = document.createElement("canvas"); + canvas.width = 1024; + canvas.height = 1024; + canvas.getContext("2d").drawImage(image, 0, 0); + + _cache_klass_map = {}; + _icon_mash_url = canvas.toDataURL(); + _icon_mask_img = electron.remote.nativeImage.createFromDataURL(_icon_mash_url); +} + +export function finalize() { + _icon_mask_img = undefined; + _icon_mash_url = undefined; + _cache_klass_map = undefined; +} \ No newline at end of file diff --git a/modules/renderer/imports/.copy_imports_shared.d.ts b/modules/renderer/imports/.copy_imports_shared.d.ts new file mode 100644 index 0000000..e537540 --- /dev/null +++ b/modules/renderer/imports/.copy_imports_shared.d.ts @@ -0,0 +1,4677 @@ + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/audio/audio.ts */ +declare namespace audio { + export namespace player { + export interface Device { + device_id: string; + driver: string; + name: string; + } + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/bookmarks.ts */ +declare namespace bookmarks { + export const boorkmak_connect; + export interface ServerProperties { + server_address: string; + server_port: number; + server_password_hash?: string; + server_password?: string; + } + export enum BookmarkType { + ENTRY, + DIRECTORY + } + export interface Bookmark { + type: BookmarkType; + /* readonly */ parent: DirectoryBookmark; + server_properties: ServerProperties; + display_name: string; + unique_id: string; + nickname: string; + default_channel?: number | string; + default_channel_password_hash?: string; + default_channel_password?: string; + connect_profile: string; + last_icon_id?: number; + } + export interface DirectoryBookmark { + type: BookmarkType; + /* readonly */ parent: DirectoryBookmark; + readonly content: (Bookmark | DirectoryBookmark)[]; + unique_id: string; + display_name: string; + } + export function bookmarks(): DirectoryBookmark; + export function bookmarks_flat(): Bookmark[]; + export function find_bookmark(uuid: string): Bookmark | DirectoryBookmark | undefined; + export function parent_bookmark(bookmark: Bookmark): DirectoryBookmark; + export function create_bookmark(display_name: string, directory: DirectoryBookmark, server_properties: ServerProperties, nickname: string): Bookmark; + export function create_bookmark_directory(parent: DirectoryBookmark, name: string): DirectoryBookmark; + //TODO test if the new parent is within the old bookmark + export function change_directory(parent: DirectoryBookmark, bookmark: Bookmark | DirectoryBookmark); + export function save_bookmark(bookmark?: Bookmark | DirectoryBookmark); + export function delete_bookmark(bookmark: Bookmark | DirectoryBookmark); + export function add_current_server(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/BrowserIPC.ts */ +declare interface Window { + BroadcastChannel: BroadcastChannel; +} +declare namespace bipc { + export interface BroadcastMessage { + timestamp: number; + receiver: string; + sender: string; + type: string; + data: any; + } + export interface ChannelMessage { + channel_id: string; + key: string; + message: any; + } + export interface ProcessQueryResponse { + request_timestamp: number; + request_query_id: string; + device_id: string; + protocol: number; + } + export interface CertificateAcceptCallback { + request_id: string; + } + export interface CertificateAcceptSucceeded { + } + export abstract class BasicIPCHandler { + protected static readonly BROADCAST_UNIQUE_ID; + protected static readonly PROTOCOL_VERSION; + protected _channels: Channel[]; + protected unique_id; + protected constructor(); + setup(); + get_local_address(); + abstract send_message(type: string, data: any, target?: string); + protected handle_message(message: BroadcastMessage); + create_channel(target_id?: string, channel_id?: string); + channels(): Channel[]; + delete_channel(channel: Channel); + private _query_results: { + [key: string]: ProcessQueryResponse[]; + }; + query_processes(timeout?: number): Promise; + private _cert_accept_callbacks: { + [key: string]: (() => any); + }; + register_certificate_accept_callback(callback: () => any): string; + private _cert_accept_succeeded: { + [sender: string]: (() => any); + }; + post_certificate_accpected(id: string, timeout?: number): Promise; + } + export interface Channel { + readonly channel_id: string; + target_id?: string; + message_handler: (remote_id: string, message: ChannelMessage) => any; + send_message(key: string, message: any); + } + export class BroadcastChannelIPC extends BasicIPCHandler { + private static readonly CHANNEL_NAME; + private channel: BroadcastChannel; + constructor(); + setup(); + private on_message(event: MessageEvent); + private on_error(event: MessageEvent); + send_message(type: string, data: any, target?: string); + } + export interface MethodProxyInvokeData { + method_name: string; + arguments: any[]; + promise_id: string; + } + export interface MethodProxyResultData { + promise_id: string; + result: any; + success: boolean; + } + export interface MethodProxyCallback { + promise: Promise; + promise_id: string; + resolve: (object: any) => any; + reject: (object: any) => any; + } + export type MethodProxyConnectParameters = { + channel_id: string; + client_id: string; + }; + export abstract class MethodProxy { + readonly ipc_handler: BasicIPCHandler; + private _ipc_channel: Channel; + private _ipc_parameters: MethodProxyConnectParameters; + private readonly _local: boolean; + private readonly _slave: boolean; + private _connected: boolean; + private _proxied_methods: { + [key: string]: () => Promise; + }; + private _proxied_callbacks: { + [key: string]: MethodProxyCallback; + }; + protected constructor(ipc_handler: BasicIPCHandler, connect_params?: MethodProxyConnectParameters); + protected setup(); + protected finalize(); + protected register_method(method: (...args: any[]) => Promise | string); + private _handle_message(remote_id: string, message: ChannelMessage); + private _handle_finalize(); + private _handle_remote_callback(remote_id: string); + private _send_result(promise_id: string, success: boolean, message: any); + private _handle_invoke(data: MethodProxyInvokeData); + private _handle_result(data: MethodProxyResultData); + generate_connect_parameters(): MethodProxyConnectParameters; + is_slave(); + is_master(); + protected abstract on_connected(); + protected abstract on_disconnected(); + } + export function setup(); + export function get_handler(); + export function supported(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts */ +declare namespace connection { + export class ServerConnectionCommandBoss extends AbstractCommandHandlerBoss { + constructor(connection: AbstractServerConnection); + } + export class ConnectionCommandHandler extends AbstractCommandHandler { + readonly connection: AbstractServerConnection; + readonly connection_handler: ConnectionHandler; + constructor(connection: AbstractServerConnection); + proxy_command_promise(promise: Promise, options: connection.CommandOptions); + handle_command(command: ServerCommand): boolean; + set_handler(command: string, handler: any); + unset_handler(command: string, handler?: any); + handleCommandResult(json); + handleCommandServerInit(json); + handleNotifyServerConnectionInfo(json); + handleNotifyConnectionInfo(json); + private createChannelFromJson(json, ignoreOrder?: boolean); + handleCommandChannelList(json); + handleCommandChannelListFinished(json); + handleCommandChannelCreate(json); + handleCommandChannelShow(json); + handleCommandChannelDelete(json); + handleCommandChannelHide(json); + handleCommandClientEnterView(json); + handleCommandClientLeftView(json); + handleNotifyClientMoved(json); + handleNotifyChannelMoved(json); + handleNotifyChannelEdited(json); + handleNotifyTextMessage(json); + notifyClientChatComposing(json); + handleNotifyClientChatClosed(json); + handleNotifyClientUpdated(json); + handleNotifyServerEdited(json); + handleNotifyServerUpdated(json); + handleNotifyMusicPlayerInfo(json); + handleNotifyClientPoke(json); + //TODO server chat message + handleNotifyServerGroupClientAdd(json); + //TODO server chat message + handleNotifyServerGroupClientRemove(json); + //TODO server chat message + handleNotifyClientChannelGroupChanged(json); + handleNotifyChannelSubscribed(json); + handleNotifyChannelUnsubscribed(json); + handleNotifyConversationHistory(json: any[]); + handleNotifyConversationMessageDelete(json: any[]); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/CommandHelper.ts */ +declare namespace connection { + export class CommandHelper extends AbstractCommandHandler { + private _who_am_i: any; + private _awaiters_unique_ids: { + [unique_id: string]: ((resolved: ClientNameInfo) => any)[]; + }; + constructor(connection); + initialize(); + destroy(); + handle_command(command: connection.ServerCommand): boolean; + joinChannel(channel: ChannelEntry, password?: string): Promise; + sendMessage(message: string, type: ChatType, target?: ChannelEntry | ClientEntry): Promise; + updateClient(key: string, value: string): Promise; + info_from_uid(..._unique_ids: string[]): Promise; + private handle_notifyclientnamefromuid(json: any[]); + request_query_list(server_id?: number): Promise; + request_playlist_list(): Promise; + request_playlist_songs(playlist_id: number): Promise; + request_clients_by_server_group(group_id: number): Promise; + request_playlist_info(playlist_id: number): Promise; + /** + * @deprecated + * Its just a workaround for the query management. + * There is no garante that the whoami trick will work forever + */ + current_virtual_server_id(): Promise; + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/ConnectionBase.ts */ +declare namespace connection { + export interface CommandOptions { + flagset?: string[]; + process_result?: boolean; + timeout?: number /* default: 1000 */; + } + export const CommandOptionDefaults: CommandOptions; + export type ConnectionStateListener = (old_state: ConnectionState, new_state: ConnectionState) => any; + export abstract class AbstractServerConnection { + readonly client: ConnectionHandler; + readonly command_helper: CommandHelper; + protected constructor(client: ConnectionHandler); + /* resolved as soon a connection has been established. This does not means that the authentication had yet been done! */ + abstract connect(address: ServerAddress, handshake: HandshakeHandler, timeout?: number): Promise; + abstract connected(): boolean; + abstract disconnect(reason?: string): Promise; + abstract support_voice(): boolean; + abstract voice_connection(): voice.AbstractVoiceConnection | undefined; + abstract command_handler_boss(): AbstractCommandHandlerBoss; + abstract send_command(command: string, data?: any | any[], options?: CommandOptions): Promise; + // @ts-ignore + abstract get onconnectionstatechanged(): ConnectionStateListener; + // @ts-ignore + abstract set onconnectionstatechanged(listener: ConnectionStateListener); + abstract remote_address(): ServerAddress; + abstract handshake_handler(): HandshakeHandler; + abstract ping(): { + native: number; + javascript?: number; + }; + } + export namespace voice { + export enum PlayerState { + PREBUFFERING, + PLAYING, + BUFFERING, + STOPPING, + STOPPED + } + export interface VoiceClient { + client_id: number; + callback_playback: () => any; + callback_stopped: () => any; + callback_state_changed: (new_state: PlayerState) => any; + get_state(): PlayerState; + get_volume(): number; + set_volume(volume: number): void; + abort_replay(); + } + export abstract class AbstractVoiceConnection { + readonly connection: AbstractServerConnection; + protected constructor(connection: AbstractServerConnection); + abstract connected(): boolean; + abstract encoding_supported(codec: number): boolean; + abstract decoding_supported(codec: number): boolean; + abstract register_client(client_id: number): VoiceClient; + abstract available_clients(): VoiceClient[]; + abstract unregister_client(client: VoiceClient): Promise; + abstract voice_recorder(): RecorderProfile; + abstract acquire_voice_recorder(recorder: RecorderProfile | undefined): Promise; + } + } + export class ServerCommand { + command: string; + arguments: any[]; + } + export abstract class AbstractCommandHandler { + readonly connection: AbstractServerConnection; + handler_boss: AbstractCommandHandlerBoss | undefined; + volatile_handler_boss: boolean; + ignore_consumed: boolean; + protected constructor(connection: AbstractServerConnection); + /** + * @return If the command should be consumed + */ + abstract handle_command(command: ServerCommand): boolean; + } + export interface SingleCommandHandler { + name?: string; + command?: string; + timeout?: number; + /* if the return is true then the command handler will be removed */ + function: (command: ServerCommand) => boolean; + } + export abstract class AbstractCommandHandlerBoss { + readonly connection: AbstractServerConnection; + protected command_handlers: AbstractCommandHandler[]; + /* TODO: Timeout */ + protected single_command_handler: SingleCommandHandler[]; + protected constructor(connection: AbstractServerConnection); + destroy(); + register_handler(handler: AbstractCommandHandler); + unregister_handler(handler: AbstractCommandHandler); + register_single_handler(handler: SingleCommandHandler); + remove_single_handler(handler: SingleCommandHandler); + handlers(): AbstractCommandHandler[]; + invoke_handle(command: ServerCommand): boolean; + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/HandshakeHandler.ts */ +declare namespace connection { + export interface HandshakeIdentityHandler { + connection: AbstractServerConnection; + start_handshake(); + register_callback(callback: (success: boolean, message?: string) => any); + } + export class HandshakeHandler { + private connection: AbstractServerConnection; + private handshake_handler: HandshakeIdentityHandler; + private failed; + readonly profile: profiles.ConnectionProfile; + readonly parameters: ConnectParameters; + constructor(profile: profiles.ConnectionProfile, parameters: ConnectParameters); + setConnection(con: AbstractServerConnection); + initialize(); + get_identity_handler(): HandshakeIdentityHandler; + startHandshake(); + on_teamspeak(); + private handshake_failed(message: string); + private handshake_finished(version?: string); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/ServerConnectionDeclaration.ts */ +declare enum ErrorID { + PERMISSION_ERROR = 2568, + EMPTY_RESULT = 0x0501, + PLAYLIST_IS_IN_USE = 0x2103, + FILE_ALREADY_EXISTS = 2050, + CLIENT_INVALID_ID = 0x0200, + CONVERSATION_INVALID_ID = 0x2200, + CONVERSATION_MORE_DATA = 0x2201, + CONVERSATION_IS_PRIVATE = 0x2202 +} +declare class CommandResult { + success: boolean; + id: number; + message: string; + extra_message: string; + json: any; + constructor(json); +} +declare interface ClientNameInfo { + //cluid=tYzKUryn\/\/Y8VBMf8PHUT6B1eiE= name=Exp clname=Exp cldbid=9 + client_unique_id: string; + client_nickname: string; + client_database_id: number; +} +declare interface ClientNameFromUid { + promise: LaterPromise; + keys: string[]; + response: ClientNameInfo[]; +} +declare interface ServerGroupClient { + client_nickname: string; + client_unique_identifier: string; + client_database_id: number; +} +declare interface QueryListEntry { + username: string; + unique_id: string; + bounded_server: number; +} +declare interface QueryList { + flag_own: boolean; + flag_all: boolean; + queries: QueryListEntry[]; +} +declare interface Playlist { + playlist_id: number; + playlist_bot_id: number; + playlist_title: string; + playlist_type: number; + playlist_owner_dbid: number; + playlist_owner_name: string; + needed_power_modify: number; + needed_power_permission_modify: number; + needed_power_delete: number; + needed_power_song_add: number; + needed_power_song_move: number; + needed_power_song_remove: number; +} +declare interface PlaylistInfo { + playlist_id: number; + playlist_title: string; + playlist_description: string; + playlist_type: number; + playlist_owner_dbid: number; + playlist_owner_name: string; + playlist_flag_delete_played: boolean; + playlist_flag_finished: boolean; + playlist_replay_mode: number; + playlist_current_song_id: number; +} +declare interface PlaylistSong { + song_id: number; + song_previous_song_id: number; + song_invoker: string; + song_url: string; + song_url_loader: string; + song_loaded: boolean; + song_metadata: string; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ConnectionHandler.ts */ +declare enum DisconnectReason { + HANDLER_DESTROYED, + REQUESTED, + DNS_FAILED, + CONNECT_FAILURE, + CONNECTION_CLOSED, + CONNECTION_FATAL_ERROR, + CONNECTION_PING_TIMEOUT, + CLIENT_KICKED, + CLIENT_BANNED, + HANDSHAKE_FAILED, + HANDSHAKE_TEAMSPEAK_REQUIRED, + HANDSHAKE_BANNED, + SERVER_CLOSED, + SERVER_REQUIRES_PASSWORD, + SERVER_HOSTMESSAGE, + IDENTITY_TOO_LOW, + UNKNOWN +} +declare enum ConnectionState { + UNCONNECTED, + CONNECTING, + INITIALISING, + CONNECTED, + DISCONNECTING +} +declare enum ViewReasonId { + VREASON_USER_ACTION = 0, + VREASON_MOVED = 1, + VREASON_SYSTEM = 2, + VREASON_TIMEOUT = 3, + VREASON_CHANNEL_KICK = 4, + VREASON_SERVER_KICK = 5, + VREASON_BAN = 6, + VREASON_SERVER_STOPPED = 7, + VREASON_SERVER_LEFT = 8, + VREASON_CHANNEL_UPDATED = 9, + VREASON_EDITED = 10, + VREASON_SERVER_SHUTDOWN = 11 +} +declare interface VoiceStatus { + input_hardware: boolean; + input_muted: boolean; + output_muted: boolean; + channel_codec_encoding_supported: boolean; + channel_codec_decoding_supported: boolean; + sound_playback_supported: boolean; + sound_record_supported; + away: boolean | string; + channel_subscribe_all: boolean; + queries_visible: boolean; +} +declare interface ConnectParameters { + nickname?: string; + channel?: { + target: string | number; + password?: string; + }; + token?: string; + password?: { + password: string; + hashed: boolean; + }; +} +declare class ConnectionHandler { + channelTree: ChannelTree; + serverConnection: connection.AbstractServerConnection; + fileManager: FileManager; + permissions: PermissionManager; + groups: GroupManager; + side_bar: chat.Frame; + settings: ServerSettings; + sound: sound.SoundManager; + hostbanner: Hostbanner; + tag_connection_handler: JQuery; + private _clientId: number; + private _local_client: LocalClientEntry; + private _reconnect_timer: NodeJS.Timer; + private _reconnect_attempt: boolean; + private _connect_initialize_id: number; + client_status: VoiceStatus; + invoke_resized_on_activate: boolean; + log: log.ServerLog; + constructor(); + tab_set_name(name: string); + setup(); + startConnection(addr: string, profile: profiles.ConnectionProfile, user_action: boolean, parameters: ConnectParameters); + getClient(): LocalClientEntry; + getClientId(); + // @ts-ignore + set clientId(id: number); + // @ts-ignore + get clientId(); + getServerConnection(): connection.AbstractServerConnection; + /** + * LISTENER + */ + onConnected(); + private initialize_server_settings(); + // @ts-ignore + get connected(): boolean; + private generate_ssl_certificate_accept(): JQuery; + private _certificate_modal: Modal; + handleDisconnect(type: DisconnectReason, data?: any); + cancel_reconnect(log_event: boolean); + private on_connection_state_changed(); + update_voice_status(targetChannel?: ChannelEntry); + sync_status_with_server(); + set_away_status(state: boolean | string); + resize_elements(); + acquire_recorder(voice_recoder: RecorderProfile, update_control_bar: boolean); + reconnect_properties(profile?: profiles.ConnectionProfile): ConnectParameters; + update_avatar(); + destroy(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/crypto/asn1.ts */ +declare namespace asn1 { + export class Int10 { + constructor(value?: any); + sub(sub: number); + mulAdd(mul: number, add: number); + simplify(); + } + export class Stream { + private static HEX_DIGITS; + private static reTimeS; + private static reTimeL; + position: number; + data: string | ArrayBuffer; + constructor(data: string | Stream | ArrayBuffer, position: number); + length(): number; + get(position?: number); + hexByte(byte: number); + parseStringISO(start, end); + parseStringUTF(start, end); + parseStringBMP(start, end); + parseTime(start, end, shortYear); + parseInteger(start, end); + isASCII(start: number, end: number); + parseBitString(start, end, maxLength); + parseOctetString(start, end, maxLength); + parseOID(start, end, maxLength); + } + export enum TagClass { + UNIVERSAL = 0x00, + APPLICATION = 0x01, + CONTEXT = 0x02, + PRIVATE = 0x03 + } + export enum TagType { + EOC = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + NULL = 0x05, + OBJECT_IDENTIFIER = 0x06, + ObjectDescriptor = 0x07, + EXTERNAL = 0x08, + REAL = 0x09, + ENUMERATED = 0x0A, + EMBEDDED_PDV = 0x0B, + UTF8String = 0x0C, + SEQUENCE = 0x10, + SET = 0x11, + NumericString = 0x12, + PrintableString = 0x13, + TeletextString = 0x14, + VideotexString = 0x15, + IA5String = 0x16, + UTCTime = 0x17, + GeneralizedTime = 0x18, + GraphicString = 0x19, + VisibleString = 0x1A, + GeneralString = 0x1B, + UniversalString = 0x1C, + BMPString = 0x1E + } + export class ASN1Tag { + tagClass: TagClass; + type: TagType; + tagConstructed: boolean; + tagNumber: number; + constructor(stream: Stream); + isUniversal(); + isEOC(); + } + export class ASN1 { + stream: Stream; + header: number; + length: number; + tag: ASN1Tag; + children: ASN1[]; + constructor(stream: Stream, header: number, length: number, tag: ASN1Tag, children: ASN1[]); + content(max_length?: number, type?: TagType); + typeName(): string; + toString(); + toPrettyString(indent); + posStart(); + posContent(); + posEnd(); + static decodeLength(stream: Stream); + static encodeLength(buffer: Uint8Array, offset: number, length: number); + } + export function decode(stream: string | ArrayBuffer); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/crypto/crc32.ts */ +declare class Crc32 { + private static readonly lookup; + private crc: number; + constructor(); + update(data: ArrayBufferLike); + digest(radix: number); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/crypto/hex.ts */ +declare namespace hex { + export function encode(buffer); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/crypto/sha.ts */ +declare function define($); +declare function unescape(string: string): string; +declare class _sha1 { + static arrayBuffer($: ArrayBuffer): ArrayBuffer; +} +declare namespace sha { + export function encode_text(buffer: string): ArrayBuffer; + export function sha1(message: string | ArrayBuffer): PromiseLike; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/dns.ts */ +declare namespace dns { + export interface AddressTarget { + target_ip: string; + target_port?: number; + } + export interface ResolveOptions { + timeout?: number; + allow_cache?: boolean; + max_depth?: number; + allow_srv?: boolean; + allow_cname?: boolean; + allow_any?: boolean; + allow_a?: boolean; + allow_aaaa?: boolean; + } + export const default_options: ResolveOptions; + export function supported(); + export function resolve_address(address: string, options?: ResolveOptions): Promise; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/events.ts */ +declare namespace event { + namespace global { } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/FileManager.ts */ +declare class FileEntry { + name: string; + datetime: number; + type: number; + size: number; +} +declare class FileListRequest { + path: string; + entries: FileEntry[]; + callback: (entries: FileEntry[]) => void; +} +declare namespace transfer { + export interface TransferKey { + client_transfer_id: number; + server_transfer_id: number; + key: string; + file_path: string; + file_name: string; + peer: { + hosts: string[]; + port: number; + }; + total_size: number; + } + export interface UploadOptions { + name: string; + path: string; + channel?: ChannelEntry; + channel_password?: string; + size: number; + overwrite: boolean; + } + export interface DownloadTransfer { + get_key(): DownloadKey; + request_file(): Promise; + } + export interface UploadTransfer { + get_key(): UploadKey; + put_data(data: BlobPart | File): Promise; + } + export type DownloadKey = TransferKey; + export type UploadKey = TransferKey; + export function spawn_download_transfer(key: DownloadKey): DownloadTransfer; + export function spawn_upload_transfer(key: UploadKey): UploadTransfer; +} +declare class RequestFileDownload implements transfer.DownloadTransfer { + readonly transfer_key: transfer.DownloadKey; + constructor(key: transfer.DownloadKey); + request_file(): Promise; + private try_fetch(url: string): Promise; + get_key(): transfer.DownloadKey; +} +declare class RequestFileUpload implements transfer.UploadTransfer { + readonly transfer_key: transfer.UploadKey; + constructor(key: transfer.DownloadKey); + get_key(): transfer.UploadKey; + put_data(data: BlobPart | File): Promise; + private try_put(data: FormData, url: string): Promise; +} +declare class FileManager extends connection.AbstractCommandHandler { + handle: ConnectionHandler; + icons: IconManager; + avatars: AvatarManager; + private listRequests: FileListRequest[]; + private pending_download_requests: transfer.DownloadKey[]; + private pending_upload_requests: transfer.UploadKey[]; + private transfer_counter: number; + constructor(client: ConnectionHandler); + destroy(); + handle_command(command: connection.ServerCommand): boolean; + /******************************** File list ********************************/ + //TODO multiple requests (same path) + requestFileList(path: string, channel?: ChannelEntry, password?: string): Promise; + private notifyFileList(json); + private notifyFileListFinished(json); + /******************************** File download/upload ********************************/ + download_file(path: string, file: string, channel?: ChannelEntry, password?: string): Promise; + upload_file(options: transfer.UploadOptions): Promise; + private notifyStartDownload(json); + private notifyStartUpload(json); + delete_file(props: { + name: string; + path?: string; + cid?: number; + cpw?: string; + }): Promise; +} +declare class Icon { + id: number; + url: string; +} +declare enum ImageType { + UNKNOWN, + BITMAP, + PNG, + GIF, + SVG, + JPEG +} +declare function media_image_type(type: ImageType, file?: boolean); +declare function image_type(encoded_data: string | ArrayBuffer, base64_encoded?: boolean); +declare class CacheManager { + readonly cache_name: string; + private _cache_category: Cache; + constructor(name: string); + setupped(): boolean; + reset(); + setup(); + cleanup(max_age: number); + resolve_cached(key: string, max_age?: number): Promise; + put_cache(key: string, value: Response, type?: string, headers?: { + [key: string]: string; + }); + delete(key: string); +} +declare class IconManager { + private static cache: CacheManager; + handle: FileManager; + private _id_urls: { + [id: number]: string; + }; + private _loading_promises: { + [id: number]: Promise; + }; + constructor(handle: FileManager); + destroy(); + clear_cache(); + delete_icon(id: number): Promise; + iconList(): Promise; + create_icon_download(id: number): Promise; + private static _response_url(response: Response); + resolved_cached?(id: number): Promise; + private static _static_id_url: { + [icon: number]: string; + }; + private static _static_cached_promise: { + [icon: number]: Promise; + }; + static load_cached_icon(id: number, ignore_age?: boolean): Promise | Icon; + private _load_icon(id: number): Promise; + download_icon(id: number): Promise; + resolve_icon(id: number): Promise; + static generate_tag(icon: Promise | Icon, options?: { + animate?: boolean; + }): JQuery; + generateTag(id: number, options?: { + animate?: boolean; + }): JQuery; +} +declare class Avatar { + client_avatar_id: string; + avatar_id: string; + url: string; + type: ImageType; +} +declare class AvatarManager { + handle: FileManager; + private static cache: CacheManager; + private _cached_avatars: { + [response_avatar_id: number]: Avatar; + }; + private _loading_promises: { + [response_avatar_id: number]: Promise; + }; + constructor(handle: FileManager); + destroy(); + private _response_url(response: Response, type: ImageType): Promise; + resolved_cached?(client_avatar_id: string, avatar_version?: string): Promise; + create_avatar_download(client_avatar_id: string): Promise; + private _load_avatar(client_avatar_id: string, avatar_version: string); + /* loads an avatar by the avatar id and optional with the avatar version */ + load_avatar(client_avatar_id: string, avatar_version: string): Promise; + generate_client_tag(client: ClientEntry): JQuery; + update_cache(client_avatar_id: string, avatar_id: string); + generate_tag(client_avatar_id: string, avatar_id?: string, options?: { + callback_image?: (tag: JQuery) => any; + callback_avatar?: (avatar: Avatar) => any; + }): JQuery; + unique_id_2_avatar_id(unique_id: string); + private generate_default_image(): JQuery; + generate_chat_tag(client: { + id?: number; + database_id?: number; + }, client_unique_id: string, callback_loaded?: (successfully: boolean, error?: any) => any): JQuery; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/i18n/country.ts */ +declare namespace i18n { + export function country_name(alpha_code: string, fallback?: string); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/i18n/localize.ts */ +declare function guid(); +declare namespace i18n { + export interface TranslationKey { + message: string; + line?: number; + character?: number; + filename?: string; + } + export interface Translation { + key: TranslationKey; + translated: string; + flags?: string[]; + } + export interface Contributor { + name: string; + email: string; + } + export interface TranslationFile { + path: string; + full_url: string; + translations: Translation[]; + } + export interface RepositoryTranslation { + key: string; + path: string; + country_code: string; + name: string; + contributors: Contributor[]; + } + export interface TranslationRepository { + unique_id: string; + url: string; + name?: string; + contact?: string; + translations?: RepositoryTranslation[]; + load_timestamp?: number; + } + export function tr(message: string, key?: string); + export function tra(message: string, ...args: any[]); + export function load_file(url: string, path: string): Promise; + export function load_repository(url: string): Promise; + export namespace config { + export interface TranslationConfig { + current_repository_url?: string; + current_language?: string; + current_translation_url: string; + current_translation_path: string; + } + export interface RepositoryConfig { + repositories?: { + url?: string; + repository?: TranslationRepository; + }[]; + } + export function repository_config(); + export function save_repository_config(); + export function translation_config(): TranslationConfig; + export function save_translation_config(); + } + export function register_repository(repository: TranslationRepository); + export function registered_repositories(): TranslationRepository[]; + export function delete_repository(repository: TranslationRepository); + export function iterate_repositories(callback_entry: (repository: TranslationRepository) => any): Promise; + export function select_translation(repository: TranslationRepository, entry: RepositoryTranslation); + export function initialize(): Promise; +} +declare const tr: typeof i18n.tr; +declare const tra: typeof i18n.tra; + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/log.ts */ +declare enum LogCategory { + CHANNEL, + CHANNEL_PROPERTIES, + CLIENT, + BOOKMARKS, + SERVER, + PERMISSIONS, + GENERAL, + NETWORKING, + VOICE, + AUDIO, + I18N, + IPC, + IDENTITIES, + STATISTICS +} +declare namespace log { + export enum LogType { + TRACE, + DEBUG, + INFO, + WARNING, + ERROR + } + export let enabled_mapping; + //Values will be overridden by initialize() + export let level_mapping; + export enum GroupMode { + NATIVE, + PREFIX + } + //Category Example: ?log.i18n.enabled=0 + //Level Example A: ?log.level.trace.enabled=0 + //Level Example B: ?log.level=0 + export function initialize(default_level: LogType); + export function log(type: LogType, category: LogCategory, message: string, ...optionalParams: any[]); + export function trace(category: LogCategory, message: string, ...optionalParams: any[]); + export function debug(category: LogCategory, message: string, ...optionalParams: any[]); + export function info(category: LogCategory, message: string, ...optionalParams: any[]); + export function warn(category: LogCategory, message: string, ...optionalParams: any[]); + export function error(category: LogCategory, message: string, ...optionalParams: any[]); + export function group(level: LogType, category: LogCategory, name: string, ...optionalParams: any[]): Group; + export function table(level: LogType, category: LogCategory, title: string, arguments: any); + export class Group { + readonly mode: GroupMode; + readonly level: LogType; + readonly category: LogCategory; + readonly enabled: boolean; + owner: Group; + private readonly name: string; + private readonly optionalParams: any[][]; + private _collapsed: boolean; + private initialized; + private _log_prefix: string; + constructor(mode: GroupMode, level: LogType, category: LogCategory, name: string, optionalParams: any[][], owner?: Group); + group(level: LogType, name: string, ...optionalParams: any[]): Group; + collapsed(flag?: boolean): this; + log(message: string, ...optionalParams: any[]): this; + end(); + // @ts-ignore + get prefix(): string; + // @ts-ignore + set prefix(prefix: string); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/main.ts */ +declare const js_render; +declare const native_client; +declare function getUserMediaFunctionPromise(): (constraints: MediaStreamConstraints) => Promise; +declare interface Window { + open_connected_question: () => Promise; +} +declare function setup_close(); +declare function moment(...arguments): any; +declare function setup_jsrender(): boolean; +declare function initialize(): Promise; +declare function initialize_app(): Promise; +declare function str2ab8(str); +declare function arrayBufferBase64(base64: string); +declare function base64_encode_ab(source: ArrayBufferLike); +declare function main(); +declare const task_teaweb_starter: loader.Task; +declare const task_certificate_callback: loader.Task; + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/permission/GroupManager.ts */ +declare enum GroupType { + QUERY, + TEMPLATE, + NORMAL +} +declare enum GroupTarget { + SERVER, + CHANNEL +} +declare class GroupProperties { + iconid: number; + sortid: number; + savedb: boolean; + namemode: number; +} +declare class GroupPermissionRequest { + group_id: number; + promise: LaterPromise; +} +declare class Group { + properties: GroupProperties; + readonly handle: GroupManager; + readonly id: number; + readonly target: GroupTarget; + readonly type: GroupType; + name: string; + requiredModifyPower: number; + requiredMemberAddPower: number; + requiredMemberRemovePower: number; + constructor(handle: GroupManager, id: number, target: GroupTarget, type: GroupType, name: string); + updateProperty(key, value); +} +declare class GroupManager extends connection.AbstractCommandHandler { + readonly handle: ConnectionHandler; + serverGroups: Group[]; + channelGroups: Group[]; + private requests_group_permissions: GroupPermissionRequest[]; + constructor(client: ConnectionHandler); + destroy(); + handle_command(command: connection.ServerCommand): boolean; + requestGroups(); + static sorter(): (a: Group, b: Group) => number; + serverGroup?(id: number): Group; + channelGroup?(id: number): Group; + private handle_grouplist(json); + request_permissions(group: Group): Promise; + private handle_group_permission_list(json: any[]); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts */ +declare enum PermissionType { + B_SERVERINSTANCE_HELP_VIEW = "b_serverinstance_help_view", + B_SERVERINSTANCE_VERSION_VIEW = "b_serverinstance_version_view", + B_SERVERINSTANCE_INFO_VIEW = "b_serverinstance_info_view", + B_SERVERINSTANCE_VIRTUALSERVER_LIST = "b_serverinstance_virtualserver_list", + B_SERVERINSTANCE_BINDING_LIST = "b_serverinstance_binding_list", + B_SERVERINSTANCE_PERMISSION_LIST = "b_serverinstance_permission_list", + B_SERVERINSTANCE_PERMISSION_FIND = "b_serverinstance_permission_find", + B_VIRTUALSERVER_CREATE = "b_virtualserver_create", + B_VIRTUALSERVER_DELETE = "b_virtualserver_delete", + B_VIRTUALSERVER_START_ANY = "b_virtualserver_start_any", + B_VIRTUALSERVER_STOP_ANY = "b_virtualserver_stop_any", + B_VIRTUALSERVER_CHANGE_MACHINE_ID = "b_virtualserver_change_machine_id", + B_VIRTUALSERVER_CHANGE_TEMPLATE = "b_virtualserver_change_template", + B_SERVERQUERY_LOGIN = "b_serverquery_login", + B_SERVERINSTANCE_TEXTMESSAGE_SEND = "b_serverinstance_textmessage_send", + B_SERVERINSTANCE_LOG_VIEW = "b_serverinstance_log_view", + B_SERVERINSTANCE_LOG_ADD = "b_serverinstance_log_add", + B_SERVERINSTANCE_STOP = "b_serverinstance_stop", + B_SERVERINSTANCE_MODIFY_SETTINGS = "b_serverinstance_modify_settings", + B_SERVERINSTANCE_MODIFY_QUERYGROUP = "b_serverinstance_modify_querygroup", + B_SERVERINSTANCE_MODIFY_TEMPLATES = "b_serverinstance_modify_templates", + B_VIRTUALSERVER_SELECT = "b_virtualserver_select", + B_VIRTUALSERVER_SELECT_GODMODE = "b_virtualserver_select_godmode", + B_VIRTUALSERVER_INFO_VIEW = "b_virtualserver_info_view", + B_VIRTUALSERVER_CONNECTIONINFO_VIEW = "b_virtualserver_connectioninfo_view", + B_VIRTUALSERVER_CHANNEL_LIST = "b_virtualserver_channel_list", + B_VIRTUALSERVER_CHANNEL_SEARCH = "b_virtualserver_channel_search", + B_VIRTUALSERVER_CLIENT_LIST = "b_virtualserver_client_list", + B_VIRTUALSERVER_CLIENT_SEARCH = "b_virtualserver_client_search", + B_VIRTUALSERVER_CLIENT_DBLIST = "b_virtualserver_client_dblist", + B_VIRTUALSERVER_CLIENT_DBSEARCH = "b_virtualserver_client_dbsearch", + B_VIRTUALSERVER_CLIENT_DBINFO = "b_virtualserver_client_dbinfo", + B_VIRTUALSERVER_PERMISSION_FIND = "b_virtualserver_permission_find", + B_VIRTUALSERVER_CUSTOM_SEARCH = "b_virtualserver_custom_search", + B_VIRTUALSERVER_START = "b_virtualserver_start", + B_VIRTUALSERVER_STOP = "b_virtualserver_stop", + B_VIRTUALSERVER_TOKEN_LIST = "b_virtualserver_token_list", + B_VIRTUALSERVER_TOKEN_ADD = "b_virtualserver_token_add", + B_VIRTUALSERVER_TOKEN_USE = "b_virtualserver_token_use", + B_VIRTUALSERVER_TOKEN_DELETE = "b_virtualserver_token_delete", + B_VIRTUALSERVER_LOG_VIEW = "b_virtualserver_log_view", + B_VIRTUALSERVER_LOG_ADD = "b_virtualserver_log_add", + B_VIRTUALSERVER_JOIN_IGNORE_PASSWORD = "b_virtualserver_join_ignore_password", + B_VIRTUALSERVER_NOTIFY_REGISTER = "b_virtualserver_notify_register", + B_VIRTUALSERVER_NOTIFY_UNREGISTER = "b_virtualserver_notify_unregister", + B_VIRTUALSERVER_SNAPSHOT_CREATE = "b_virtualserver_snapshot_create", + B_VIRTUALSERVER_SNAPSHOT_DEPLOY = "b_virtualserver_snapshot_deploy", + B_VIRTUALSERVER_PERMISSION_RESET = "b_virtualserver_permission_reset", + B_VIRTUALSERVER_MODIFY_NAME = "b_virtualserver_modify_name", + B_VIRTUALSERVER_MODIFY_WELCOMEMESSAGE = "b_virtualserver_modify_welcomemessage", + B_VIRTUALSERVER_MODIFY_MAXCLIENTS = "b_virtualserver_modify_maxclients", + B_VIRTUALSERVER_MODIFY_RESERVED_SLOTS = "b_virtualserver_modify_reserved_slots", + B_VIRTUALSERVER_MODIFY_PASSWORD = "b_virtualserver_modify_password", + B_VIRTUALSERVER_MODIFY_DEFAULT_SERVERGROUP = "b_virtualserver_modify_default_servergroup", + B_VIRTUALSERVER_MODIFY_DEFAULT_MUSICGROUP = "b_virtualserver_modify_default_musicgroup", + B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELGROUP = "b_virtualserver_modify_default_channelgroup", + B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELADMINGROUP = "b_virtualserver_modify_default_channeladmingroup", + B_VIRTUALSERVER_MODIFY_CHANNEL_FORCED_SILENCE = "b_virtualserver_modify_channel_forced_silence", + B_VIRTUALSERVER_MODIFY_COMPLAIN = "b_virtualserver_modify_complain", + B_VIRTUALSERVER_MODIFY_ANTIFLOOD = "b_virtualserver_modify_antiflood", + B_VIRTUALSERVER_MODIFY_FT_SETTINGS = "b_virtualserver_modify_ft_settings", + B_VIRTUALSERVER_MODIFY_FT_QUOTAS = "b_virtualserver_modify_ft_quotas", + B_VIRTUALSERVER_MODIFY_HOSTMESSAGE = "b_virtualserver_modify_hostmessage", + B_VIRTUALSERVER_MODIFY_HOSTBANNER = "b_virtualserver_modify_hostbanner", + B_VIRTUALSERVER_MODIFY_HOSTBUTTON = "b_virtualserver_modify_hostbutton", + B_VIRTUALSERVER_MODIFY_PORT = "b_virtualserver_modify_port", + B_VIRTUALSERVER_MODIFY_HOST = "b_virtualserver_modify_host", + B_VIRTUALSERVER_MODIFY_DEFAULT_MESSAGES = "b_virtualserver_modify_default_messages", + B_VIRTUALSERVER_MODIFY_AUTOSTART = "b_virtualserver_modify_autostart", + B_VIRTUALSERVER_MODIFY_NEEDED_IDENTITY_SECURITY_LEVEL = "b_virtualserver_modify_needed_identity_security_level", + B_VIRTUALSERVER_MODIFY_PRIORITY_SPEAKER_DIMM_MODIFICATOR = "b_virtualserver_modify_priority_speaker_dimm_modificator", + B_VIRTUALSERVER_MODIFY_LOG_SETTINGS = "b_virtualserver_modify_log_settings", + B_VIRTUALSERVER_MODIFY_MIN_CLIENT_VERSION = "b_virtualserver_modify_min_client_version", + B_VIRTUALSERVER_MODIFY_ICON_ID = "b_virtualserver_modify_icon_id", + B_VIRTUALSERVER_MODIFY_WEBLIST = "b_virtualserver_modify_weblist", + B_VIRTUALSERVER_MODIFY_CODEC_ENCRYPTION_MODE = "b_virtualserver_modify_codec_encryption_mode", + B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS = "b_virtualserver_modify_temporary_passwords", + B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS_OWN = "b_virtualserver_modify_temporary_passwords_own", + B_VIRTUALSERVER_MODIFY_CHANNEL_TEMP_DELETE_DELAY_DEFAULT = "b_virtualserver_modify_channel_temp_delete_delay_default", + B_VIRTUALSERVER_MODIFY_MUSIC_BOT_LIMIT = "b_virtualserver_modify_music_bot_limit", + I_CHANNEL_MIN_DEPTH = "i_channel_min_depth", + I_CHANNEL_MAX_DEPTH = "i_channel_max_depth", + B_CHANNEL_GROUP_INHERITANCE_END = "b_channel_group_inheritance_end", + I_CHANNEL_PERMISSION_MODIFY_POWER = "i_channel_permission_modify_power", + I_CHANNEL_NEEDED_PERMISSION_MODIFY_POWER = "i_channel_needed_permission_modify_power", + B_CHANNEL_INFO_VIEW = "b_channel_info_view", + B_CHANNEL_CREATE_CHILD = "b_channel_create_child", + B_CHANNEL_CREATE_PERMANENT = "b_channel_create_permanent", + B_CHANNEL_CREATE_SEMI_PERMANENT = "b_channel_create_semi_permanent", + B_CHANNEL_CREATE_TEMPORARY = "b_channel_create_temporary", + B_CHANNEL_CREATE_PRIVATE = "b_channel_create_private", + B_CHANNEL_CREATE_WITH_TOPIC = "b_channel_create_with_topic", + B_CHANNEL_CREATE_WITH_DESCRIPTION = "b_channel_create_with_description", + B_CHANNEL_CREATE_WITH_PASSWORD = "b_channel_create_with_password", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX8 = "b_channel_create_modify_with_codec_speex8", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX16 = "b_channel_create_modify_with_codec_speex16", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX32 = "b_channel_create_modify_with_codec_speex32", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_CELTMONO48 = "b_channel_create_modify_with_codec_celtmono48", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSVOICE = "b_channel_create_modify_with_codec_opusvoice", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSMUSIC = "b_channel_create_modify_with_codec_opusmusic", + I_CHANNEL_CREATE_MODIFY_WITH_CODEC_MAXQUALITY = "i_channel_create_modify_with_codec_maxquality", + I_CHANNEL_CREATE_MODIFY_WITH_CODEC_LATENCY_FACTOR_MIN = "i_channel_create_modify_with_codec_latency_factor_min", + B_CHANNEL_CREATE_WITH_MAXCLIENTS = "b_channel_create_with_maxclients", + B_CHANNEL_CREATE_WITH_MAXFAMILYCLIENTS = "b_channel_create_with_maxfamilyclients", + B_CHANNEL_CREATE_WITH_SORTORDER = "b_channel_create_with_sortorder", + B_CHANNEL_CREATE_WITH_DEFAULT = "b_channel_create_with_default", + B_CHANNEL_CREATE_WITH_NEEDED_TALK_POWER = "b_channel_create_with_needed_talk_power", + B_CHANNEL_CREATE_MODIFY_WITH_FORCE_PASSWORD = "b_channel_create_modify_with_force_password", + I_CHANNEL_CREATE_MODIFY_WITH_TEMP_DELETE_DELAY = "i_channel_create_modify_with_temp_delete_delay", + B_CHANNEL_MODIFY_PARENT = "b_channel_modify_parent", + B_CHANNEL_MODIFY_MAKE_DEFAULT = "b_channel_modify_make_default", + B_CHANNEL_MODIFY_MAKE_PERMANENT = "b_channel_modify_make_permanent", + B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT = "b_channel_modify_make_semi_permanent", + B_CHANNEL_MODIFY_MAKE_TEMPORARY = "b_channel_modify_make_temporary", + B_CHANNEL_MODIFY_NAME = "b_channel_modify_name", + B_CHANNEL_MODIFY_TOPIC = "b_channel_modify_topic", + B_CHANNEL_MODIFY_DESCRIPTION = "b_channel_modify_description", + B_CHANNEL_MODIFY_PASSWORD = "b_channel_modify_password", + B_CHANNEL_MODIFY_CODEC = "b_channel_modify_codec", + B_CHANNEL_MODIFY_CODEC_QUALITY = "b_channel_modify_codec_quality", + B_CHANNEL_MODIFY_CODEC_LATENCY_FACTOR = "b_channel_modify_codec_latency_factor", + B_CHANNEL_MODIFY_MAXCLIENTS = "b_channel_modify_maxclients", + B_CHANNEL_MODIFY_MAXFAMILYCLIENTS = "b_channel_modify_maxfamilyclients", + B_CHANNEL_MODIFY_SORTORDER = "b_channel_modify_sortorder", + B_CHANNEL_MODIFY_NEEDED_TALK_POWER = "b_channel_modify_needed_talk_power", + I_CHANNEL_MODIFY_POWER = "i_channel_modify_power", + I_CHANNEL_NEEDED_MODIFY_POWER = "i_channel_needed_modify_power", + B_CHANNEL_MODIFY_MAKE_CODEC_ENCRYPTED = "b_channel_modify_make_codec_encrypted", + B_CHANNEL_MODIFY_TEMP_DELETE_DELAY = "b_channel_modify_temp_delete_delay", + B_CHANNEL_DELETE_PERMANENT = "b_channel_delete_permanent", + B_CHANNEL_DELETE_SEMI_PERMANENT = "b_channel_delete_semi_permanent", + B_CHANNEL_DELETE_TEMPORARY = "b_channel_delete_temporary", + B_CHANNEL_DELETE_FLAG_FORCE = "b_channel_delete_flag_force", + I_CHANNEL_DELETE_POWER = "i_channel_delete_power", + I_CHANNEL_NEEDED_DELETE_POWER = "i_channel_needed_delete_power", + B_CHANNEL_JOIN_PERMANENT = "b_channel_join_permanent", + B_CHANNEL_JOIN_SEMI_PERMANENT = "b_channel_join_semi_permanent", + B_CHANNEL_JOIN_TEMPORARY = "b_channel_join_temporary", + B_CHANNEL_JOIN_IGNORE_PASSWORD = "b_channel_join_ignore_password", + B_CHANNEL_JOIN_IGNORE_MAXCLIENTS = "b_channel_join_ignore_maxclients", + B_CHANNEL_IGNORE_VIEW_POWER = "b_channel_ignore_view_power", + I_CHANNEL_JOIN_POWER = "i_channel_join_power", + I_CHANNEL_NEEDED_JOIN_POWER = "i_channel_needed_join_power", + B_CHANNEL_IGNORE_JOIN_POWER = "b_channel_ignore_join_power", + I_CHANNEL_VIEW_POWER = "i_channel_view_power", + I_CHANNEL_NEEDED_VIEW_POWER = "i_channel_needed_view_power", + I_CHANNEL_SUBSCRIBE_POWER = "i_channel_subscribe_power", + I_CHANNEL_NEEDED_SUBSCRIBE_POWER = "i_channel_needed_subscribe_power", + I_CHANNEL_DESCRIPTION_VIEW_POWER = "i_channel_description_view_power", + I_CHANNEL_NEEDED_DESCRIPTION_VIEW_POWER = "i_channel_needed_description_view_power", + I_ICON_ID = "i_icon_id", + I_MAX_ICON_FILESIZE = "i_max_icon_filesize", + B_ICON_MANAGE = "b_icon_manage", + B_GROUP_IS_PERMANENT = "b_group_is_permanent", + I_GROUP_AUTO_UPDATE_TYPE = "i_group_auto_update_type", + I_GROUP_AUTO_UPDATE_MAX_VALUE = "i_group_auto_update_max_value", + I_GROUP_SORT_ID = "i_group_sort_id", + I_GROUP_SHOW_NAME_IN_TREE = "i_group_show_name_in_tree", + B_VIRTUALSERVER_SERVERGROUP_CREATE = "b_virtualserver_servergroup_create", + B_VIRTUALSERVER_SERVERGROUP_LIST = "b_virtualserver_servergroup_list", + B_VIRTUALSERVER_SERVERGROUP_PERMISSION_LIST = "b_virtualserver_servergroup_permission_list", + B_VIRTUALSERVER_SERVERGROUP_CLIENT_LIST = "b_virtualserver_servergroup_client_list", + B_VIRTUALSERVER_CHANNELGROUP_CREATE = "b_virtualserver_channelgroup_create", + B_VIRTUALSERVER_CHANNELGROUP_LIST = "b_virtualserver_channelgroup_list", + B_VIRTUALSERVER_CHANNELGROUP_PERMISSION_LIST = "b_virtualserver_channelgroup_permission_list", + B_VIRTUALSERVER_CHANNELGROUP_CLIENT_LIST = "b_virtualserver_channelgroup_client_list", + B_VIRTUALSERVER_CLIENT_PERMISSION_LIST = "b_virtualserver_client_permission_list", + B_VIRTUALSERVER_CHANNEL_PERMISSION_LIST = "b_virtualserver_channel_permission_list", + B_VIRTUALSERVER_CHANNELCLIENT_PERMISSION_LIST = "b_virtualserver_channelclient_permission_list", + B_VIRTUALSERVER_PLAYLIST_PERMISSION_LIST = "b_virtualserver_playlist_permission_list", + I_SERVER_GROUP_MODIFY_POWER = "i_server_group_modify_power", + I_SERVER_GROUP_NEEDED_MODIFY_POWER = "i_server_group_needed_modify_power", + I_SERVER_GROUP_MEMBER_ADD_POWER = "i_server_group_member_add_power", + I_SERVER_GROUP_SELF_ADD_POWER = "i_server_group_self_add_power", + I_SERVER_GROUP_NEEDED_MEMBER_ADD_POWER = "i_server_group_needed_member_add_power", + I_SERVER_GROUP_MEMBER_REMOVE_POWER = "i_server_group_member_remove_power", + I_SERVER_GROUP_SELF_REMOVE_POWER = "i_server_group_self_remove_power", + I_SERVER_GROUP_NEEDED_MEMBER_REMOVE_POWER = "i_server_group_needed_member_remove_power", + I_CHANNEL_GROUP_MODIFY_POWER = "i_channel_group_modify_power", + I_CHANNEL_GROUP_NEEDED_MODIFY_POWER = "i_channel_group_needed_modify_power", + I_CHANNEL_GROUP_MEMBER_ADD_POWER = "i_channel_group_member_add_power", + I_CHANNEL_GROUP_SELF_ADD_POWER = "i_channel_group_self_add_power", + I_CHANNEL_GROUP_NEEDED_MEMBER_ADD_POWER = "i_channel_group_needed_member_add_power", + I_CHANNEL_GROUP_MEMBER_REMOVE_POWER = "i_channel_group_member_remove_power", + I_CHANNEL_GROUP_SELF_REMOVE_POWER = "i_channel_group_self_remove_power", + I_CHANNEL_GROUP_NEEDED_MEMBER_REMOVE_POWER = "i_channel_group_needed_member_remove_power", + I_GROUP_MEMBER_ADD_POWER = "i_group_member_add_power", + I_GROUP_NEEDED_MEMBER_ADD_POWER = "i_group_needed_member_add_power", + I_GROUP_MEMBER_REMOVE_POWER = "i_group_member_remove_power", + I_GROUP_NEEDED_MEMBER_REMOVE_POWER = "i_group_needed_member_remove_power", + I_GROUP_MODIFY_POWER = "i_group_modify_power", + I_GROUP_NEEDED_MODIFY_POWER = "i_group_needed_modify_power", + I_PERMISSION_MODIFY_POWER = "i_permission_modify_power", + B_PERMISSION_MODIFY_POWER_IGNORE = "b_permission_modify_power_ignore", + B_VIRTUALSERVER_SERVERGROUP_DELETE = "b_virtualserver_servergroup_delete", + B_VIRTUALSERVER_CHANNELGROUP_DELETE = "b_virtualserver_channelgroup_delete", + I_CLIENT_PERMISSION_MODIFY_POWER = "i_client_permission_modify_power", + I_CLIENT_NEEDED_PERMISSION_MODIFY_POWER = "i_client_needed_permission_modify_power", + I_CLIENT_MAX_CLONES_UID = "i_client_max_clones_uid", + I_CLIENT_MAX_CLONES_IP = "i_client_max_clones_ip", + I_CLIENT_MAX_CLONES_HWID = "i_client_max_clones_hwid", + I_CLIENT_MAX_IDLETIME = "i_client_max_idletime", + I_CLIENT_MAX_AVATAR_FILESIZE = "i_client_max_avatar_filesize", + I_CLIENT_MAX_CHANNEL_SUBSCRIPTIONS = "i_client_max_channel_subscriptions", + I_CLIENT_MAX_CHANNELS = "i_client_max_channels", + I_CLIENT_MAX_TEMPORARY_CHANNELS = "i_client_max_temporary_channels", + I_CLIENT_MAX_SEMI_CHANNELS = "i_client_max_semi_channels", + I_CLIENT_MAX_PERMANENT_CHANNELS = "i_client_max_permanent_channels", + B_CLIENT_USE_PRIORITY_SPEAKER = "b_client_use_priority_speaker", + B_CLIENT_SKIP_CHANNELGROUP_PERMISSIONS = "b_client_skip_channelgroup_permissions", + B_CLIENT_FORCE_PUSH_TO_TALK = "b_client_force_push_to_talk", + B_CLIENT_IGNORE_BANS = "b_client_ignore_bans", + B_CLIENT_IGNORE_VPN = "b_client_ignore_vpn", + B_CLIENT_IGNORE_ANTIFLOOD = "b_client_ignore_antiflood", + B_CLIENT_ENFORCE_VALID_HWID = "b_client_enforce_valid_hwid", + B_CLIENT_ALLOW_INVALID_PACKET = "b_client_allow_invalid_packet", + B_CLIENT_ALLOW_INVALID_BADGES = "b_client_allow_invalid_badges", + B_CLIENT_ISSUE_CLIENT_QUERY_COMMAND = "b_client_issue_client_query_command", + B_CLIENT_USE_RESERVED_SLOT = "b_client_use_reserved_slot", + B_CLIENT_USE_CHANNEL_COMMANDER = "b_client_use_channel_commander", + B_CLIENT_REQUEST_TALKER = "b_client_request_talker", + B_CLIENT_AVATAR_DELETE_OTHER = "b_client_avatar_delete_other", + B_CLIENT_IS_STICKY = "b_client_is_sticky", + B_CLIENT_IGNORE_STICKY = "b_client_ignore_sticky", + B_CLIENT_MUSIC_CREATE_PERMANENT = "b_client_music_create_permanent", + B_CLIENT_MUSIC_CREATE_SEMI_PERMANENT = "b_client_music_create_semi_permanent", + B_CLIENT_MUSIC_CREATE_TEMPORARY = "b_client_music_create_temporary", + B_CLIENT_MUSIC_MODIFY_PERMANENT = "b_client_music_modify_permanent", + B_CLIENT_MUSIC_MODIFY_SEMI_PERMANENT = "b_client_music_modify_semi_permanent", + B_CLIENT_MUSIC_MODIFY_TEMPORARY = "b_client_music_modify_temporary", + I_CLIENT_MUSIC_CREATE_MODIFY_MAX_VOLUME = "i_client_music_create_modify_max_volume", + I_CLIENT_MUSIC_LIMIT = "i_client_music_limit", + I_CLIENT_MUSIC_NEEDED_DELETE_POWER = "i_client_music_needed_delete_power", + I_CLIENT_MUSIC_DELETE_POWER = "i_client_music_delete_power", + I_CLIENT_MUSIC_PLAY_POWER = "i_client_music_play_power", + I_CLIENT_MUSIC_NEEDED_PLAY_POWER = "i_client_music_needed_play_power", + I_CLIENT_MUSIC_MODIFY_POWER = "i_client_music_modify_power", + I_CLIENT_MUSIC_NEEDED_MODIFY_POWER = "i_client_music_needed_modify_power", + I_CLIENT_MUSIC_RENAME_POWER = "i_client_music_rename_power", + I_CLIENT_MUSIC_NEEDED_RENAME_POWER = "i_client_music_needed_rename_power", + B_PLAYLIST_CREATE = "b_playlist_create", + I_PLAYLIST_VIEW_POWER = "i_playlist_view_power", + I_PLAYLIST_NEEDED_VIEW_POWER = "i_playlist_needed_view_power", + I_PLAYLIST_MODIFY_POWER = "i_playlist_modify_power", + I_PLAYLIST_NEEDED_MODIFY_POWER = "i_playlist_needed_modify_power", + I_PLAYLIST_PERMISSION_MODIFY_POWER = "i_playlist_permission_modify_power", + I_PLAYLIST_NEEDED_PERMISSION_MODIFY_POWER = "i_playlist_needed_permission_modify_power", + I_PLAYLIST_DELETE_POWER = "i_playlist_delete_power", + I_PLAYLIST_NEEDED_DELETE_POWER = "i_playlist_needed_delete_power", + I_PLAYLIST_SONG_ADD_POWER = "i_playlist_song_add_power", + I_PLAYLIST_SONG_NEEDED_ADD_POWER = "i_playlist_song_needed_add_power", + I_PLAYLIST_SONG_REMOVE_POWER = "i_playlist_song_remove_power", + I_PLAYLIST_SONG_NEEDED_REMOVE_POWER = "i_playlist_song_needed_remove_power", + B_CLIENT_INFO_VIEW = "b_client_info_view", + B_CLIENT_PERMISSIONOVERVIEW_VIEW = "b_client_permissionoverview_view", + B_CLIENT_PERMISSIONOVERVIEW_OWN = "b_client_permissionoverview_own", + B_CLIENT_REMOTEADDRESS_VIEW = "b_client_remoteaddress_view", + I_CLIENT_SERVERQUERY_VIEW_POWER = "i_client_serverquery_view_power", + I_CLIENT_NEEDED_SERVERQUERY_VIEW_POWER = "i_client_needed_serverquery_view_power", + B_CLIENT_CUSTOM_INFO_VIEW = "b_client_custom_info_view", + B_CLIENT_MUSIC_CHANNEL_LIST = "b_client_music_channel_list", + B_CLIENT_MUSIC_SERVER_LIST = "b_client_music_server_list", + I_CLIENT_MUSIC_INFO = "i_client_music_info", + I_CLIENT_MUSIC_NEEDED_INFO = "i_client_music_needed_info", + I_CLIENT_KICK_FROM_SERVER_POWER = "i_client_kick_from_server_power", + I_CLIENT_NEEDED_KICK_FROM_SERVER_POWER = "i_client_needed_kick_from_server_power", + I_CLIENT_KICK_FROM_CHANNEL_POWER = "i_client_kick_from_channel_power", + I_CLIENT_NEEDED_KICK_FROM_CHANNEL_POWER = "i_client_needed_kick_from_channel_power", + I_CLIENT_BAN_POWER = "i_client_ban_power", + I_CLIENT_NEEDED_BAN_POWER = "i_client_needed_ban_power", + I_CLIENT_MOVE_POWER = "i_client_move_power", + I_CLIENT_NEEDED_MOVE_POWER = "i_client_needed_move_power", + I_CLIENT_COMPLAIN_POWER = "i_client_complain_power", + I_CLIENT_NEEDED_COMPLAIN_POWER = "i_client_needed_complain_power", + B_CLIENT_COMPLAIN_LIST = "b_client_complain_list", + B_CLIENT_COMPLAIN_DELETE_OWN = "b_client_complain_delete_own", + B_CLIENT_COMPLAIN_DELETE = "b_client_complain_delete", + B_CLIENT_BAN_LIST = "b_client_ban_list", + B_CLIENT_BAN_LIST_GLOBAL = "b_client_ban_list_global", + B_CLIENT_BAN_TRIGGER_LIST = "b_client_ban_trigger_list", + B_CLIENT_BAN_CREATE = "b_client_ban_create", + B_CLIENT_BAN_CREATE_GLOBAL = "b_client_ban_create_global", + B_CLIENT_BAN_NAME = "b_client_ban_name", + B_CLIENT_BAN_IP = "b_client_ban_ip", + B_CLIENT_BAN_HWID = "b_client_ban_hwid", + B_CLIENT_BAN_EDIT = "b_client_ban_edit", + B_CLIENT_BAN_EDIT_GLOBAL = "b_client_ban_edit_global", + B_CLIENT_BAN_DELETE_OWN = "b_client_ban_delete_own", + B_CLIENT_BAN_DELETE = "b_client_ban_delete", + B_CLIENT_BAN_DELETE_OWN_GLOBAL = "b_client_ban_delete_own_global", + B_CLIENT_BAN_DELETE_GLOBAL = "b_client_ban_delete_global", + I_CLIENT_BAN_MAX_BANTIME = "i_client_ban_max_bantime", + I_CLIENT_PRIVATE_TEXTMESSAGE_POWER = "i_client_private_textmessage_power", + I_CLIENT_NEEDED_PRIVATE_TEXTMESSAGE_POWER = "i_client_needed_private_textmessage_power", + B_CLIENT_EVEN_TEXTMESSAGE_SEND = "b_client_even_textmessage_send", + B_CLIENT_SERVER_TEXTMESSAGE_SEND = "b_client_server_textmessage_send", + B_CLIENT_CHANNEL_TEXTMESSAGE_SEND = "b_client_channel_textmessage_send", + B_CLIENT_OFFLINE_TEXTMESSAGE_SEND = "b_client_offline_textmessage_send", + I_CLIENT_TALK_POWER = "i_client_talk_power", + I_CLIENT_NEEDED_TALK_POWER = "i_client_needed_talk_power", + I_CLIENT_POKE_POWER = "i_client_poke_power", + I_CLIENT_NEEDED_POKE_POWER = "i_client_needed_poke_power", + B_CLIENT_SET_FLAG_TALKER = "b_client_set_flag_talker", + I_CLIENT_WHISPER_POWER = "i_client_whisper_power", + I_CLIENT_NEEDED_WHISPER_POWER = "i_client_needed_whisper_power", + B_CLIENT_MODIFY_DESCRIPTION = "b_client_modify_description", + B_CLIENT_MODIFY_OWN_DESCRIPTION = "b_client_modify_own_description", + B_CLIENT_USE_BBCODE_ANY = "b_client_use_bbcode_any", + B_CLIENT_USE_BBCODE_URL = "b_client_use_bbcode_url", + B_CLIENT_USE_BBCODE_IMAGE = "b_client_use_bbcode_image", + B_CLIENT_MODIFY_DBPROPERTIES = "b_client_modify_dbproperties", + B_CLIENT_DELETE_DBPROPERTIES = "b_client_delete_dbproperties", + B_CLIENT_CREATE_MODIFY_SERVERQUERY_LOGIN = "b_client_create_modify_serverquery_login", + B_CLIENT_QUERY_CREATE = "b_client_query_create", + B_CLIENT_QUERY_LIST = "b_client_query_list", + B_CLIENT_QUERY_LIST_OWN = "b_client_query_list_own", + B_CLIENT_QUERY_RENAME = "b_client_query_rename", + B_CLIENT_QUERY_RENAME_OWN = "b_client_query_rename_own", + B_CLIENT_QUERY_CHANGE_PASSWORD = "b_client_query_change_password", + B_CLIENT_QUERY_CHANGE_OWN_PASSWORD = "b_client_query_change_own_password", + B_CLIENT_QUERY_CHANGE_PASSWORD_GLOBAL = "b_client_query_change_password_global", + B_CLIENT_QUERY_DELETE = "b_client_query_delete", + B_CLIENT_QUERY_DELETE_OWN = "b_client_query_delete_own", + B_FT_IGNORE_PASSWORD = "b_ft_ignore_password", + B_FT_TRANSFER_LIST = "b_ft_transfer_list", + I_FT_FILE_UPLOAD_POWER = "i_ft_file_upload_power", + I_FT_NEEDED_FILE_UPLOAD_POWER = "i_ft_needed_file_upload_power", + I_FT_FILE_DOWNLOAD_POWER = "i_ft_file_download_power", + I_FT_NEEDED_FILE_DOWNLOAD_POWER = "i_ft_needed_file_download_power", + I_FT_FILE_DELETE_POWER = "i_ft_file_delete_power", + I_FT_NEEDED_FILE_DELETE_POWER = "i_ft_needed_file_delete_power", + I_FT_FILE_RENAME_POWER = "i_ft_file_rename_power", + I_FT_NEEDED_FILE_RENAME_POWER = "i_ft_needed_file_rename_power", + I_FT_FILE_BROWSE_POWER = "i_ft_file_browse_power", + I_FT_NEEDED_FILE_BROWSE_POWER = "i_ft_needed_file_browse_power", + I_FT_DIRECTORY_CREATE_POWER = "i_ft_directory_create_power", + I_FT_NEEDED_DIRECTORY_CREATE_POWER = "i_ft_needed_directory_create_power", + I_FT_QUOTA_MB_DOWNLOAD_PER_CLIENT = "i_ft_quota_mb_download_per_client", + I_FT_QUOTA_MB_UPLOAD_PER_CLIENT = "i_ft_quota_mb_upload_per_client" +} +declare class PermissionInfo { + name: string; + id: number; + description: string; + is_boolean(); + id_grant(): number; +} +declare class PermissionGroup { + begin: number; + end: number; + deep: number; + name: string; +} +declare class GroupedPermissions { + group: PermissionGroup; + permissions: PermissionInfo[]; + children: GroupedPermissions[]; + parent: GroupedPermissions; +} +declare class PermissionValue { + readonly type: PermissionInfo; + value: number; + flag_skip: boolean; + flag_negate: boolean; + granted_value: number; + constructor(type, value?); + granted(requiredValue: number, required?: boolean): boolean; + hasValue(): boolean; + hasGrant(): boolean; +} +declare class NeededPermissionValue extends PermissionValue { + constructor(type, value); +} +declare class ChannelPermissionRequest { + requested: number; + channel_id: number; + callback_success: ((_: PermissionValue[]) => any)[]; + callback_error: ((_: any) => any)[]; +} +declare class TeaPermissionRequest { + client_id?: number; + channel_id?: number; + playlist_id?: number; + promise: LaterPromise; +} +declare class PermissionManager extends connection.AbstractCommandHandler { + readonly handle: ConnectionHandler; + permissionList: PermissionInfo[]; + permissionGroups: PermissionGroup[]; + neededPermissions: NeededPermissionValue[]; + needed_permission_change_listener: { + [permission: string]: (() => any)[]; + }; + requests_channel_permissions: ChannelPermissionRequest[]; + requests_client_permissions: TeaPermissionRequest[]; + requests_client_channel_permissions: TeaPermissionRequest[]; + requests_playlist_permissions: TeaPermissionRequest[]; + initializedListener: ((initialized: boolean) => void)[]; + private _cacheNeededPermissions: any; + /* Static info mapping until TeaSpeak implements a detailed info */ + //TODO tr + static readonly group_mapping: { + name: string; + deep: number; + }[]; + private _group_mapping; + public static parse_permission_bulk(json: any[], manager: PermissionManager): PermissionValue[]; + constructor(client: ConnectionHandler); + destroy(); + handle_command(command: connection.ServerCommand): boolean; + initialized(): boolean; + public requestPermissionList(); + private onPermissionList(json); + private onNeededPermissions(json); + register_needed_permission(key: PermissionType, listener: () => any); + unregister_needed_permission(key: PermissionType, listener: () => any); + private onChannelPermList(json); + resolveInfo?(key: number | string | PermissionType): PermissionInfo; + requestChannelPermissions(channelId: number): Promise; + private onClientPermList(json: any[]); + requestClientPermissions(client_id: number): Promise; + requestClientChannelPermissions(client_id: number, channel_id: number): Promise; + private onPlaylistPermList(json: any[]); + requestPlaylistPermissions(playlist_id: number): Promise; + neededPermission(key: number | string | PermissionType | PermissionInfo): NeededPermissionValue; + groupedPermissions(): GroupedPermissions[]; + /** + * Generates an enum with all know permission types, used for the enum above + */ + export_permission_types(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/PPTListener.ts */ +declare enum KeyCode { + KEY_CANCEL = 3, + KEY_HELP = 6, + KEY_BACK_SPACE = 8, + KEY_TAB = 9, + KEY_CLEAR = 12, + KEY_RETURN = 13, + KEY_ENTER = 14, + KEY_SHIFT = 16, + KEY_CONTROL = 17, + KEY_ALT = 18, + KEY_PAUSE = 19, + KEY_CAPS_LOCK = 20, + KEY_ESCAPE = 27, + KEY_SPACE = 32, + KEY_PAGE_UP = 33, + KEY_PAGE_DOWN = 34, + KEY_END = 35, + KEY_HOME = 36, + KEY_LEFT = 37, + KEY_UP = 38, + KEY_RIGHT = 39, + KEY_DOWN = 40, + KEY_PRINTSCREEN = 44, + KEY_INSERT = 45, + KEY_DELETE = 46, + KEY_0 = 48, + KEY_1 = 49, + KEY_2 = 50, + KEY_3 = 51, + KEY_4 = 52, + KEY_5 = 53, + KEY_6 = 54, + KEY_7 = 55, + KEY_8 = 56, + KEY_9 = 57, + KEY_SEMICOLON = 59, + KEY_EQUALS = 61, + KEY_A = 65, + KEY_B = 66, + KEY_C = 67, + KEY_D = 68, + KEY_E = 69, + KEY_F = 70, + KEY_G = 71, + KEY_H = 72, + KEY_I = 73, + KEY_J = 74, + KEY_K = 75, + KEY_L = 76, + KEY_M = 77, + KEY_N = 78, + KEY_O = 79, + KEY_P = 80, + KEY_Q = 81, + KEY_R = 82, + KEY_S = 83, + KEY_T = 84, + KEY_U = 85, + KEY_V = 86, + KEY_W = 87, + KEY_X = 88, + KEY_Y = 89, + KEY_Z = 90, + KEY_LEFT_CMD = 91, + KEY_RIGHT_CMD = 93, + KEY_CONTEXT_MENU = 93, + KEY_NUMPAD0 = 96, + KEY_NUMPAD1 = 97, + KEY_NUMPAD2 = 98, + KEY_NUMPAD3 = 99, + KEY_NUMPAD4 = 100, + KEY_NUMPAD5 = 101, + KEY_NUMPAD6 = 102, + KEY_NUMPAD7 = 103, + KEY_NUMPAD8 = 104, + KEY_NUMPAD9 = 105, + KEY_MULTIPLY = 106, + KEY_ADD = 107, + KEY_SEPARATOR = 108, + KEY_SUBTRACT = 109, + KEY_DECIMAL = 110, + KEY_DIVIDE = 111, + KEY_F1 = 112, + KEY_F2 = 113, + KEY_F3 = 114, + KEY_F4 = 115, + KEY_F5 = 116, + KEY_F6 = 117, + KEY_F7 = 118, + KEY_F8 = 119, + KEY_F9 = 120, + KEY_F10 = 121, + KEY_F11 = 122, + KEY_F12 = 123, + KEY_F13 = 124, + KEY_F14 = 125, + KEY_F15 = 126, + KEY_F16 = 127, + KEY_F17 = 128, + KEY_F18 = 129, + KEY_F19 = 130, + KEY_F20 = 131, + KEY_F21 = 132, + KEY_F22 = 133, + KEY_F23 = 134, + KEY_F24 = 135, + KEY_NUM_LOCK = 144, + KEY_SCROLL_LOCK = 145, + KEY_COMMA = 188, + KEY_PERIOD = 190, + KEY_SLASH = 191, + KEY_BACK_QUOTE = 192, + KEY_OPEN_BRACKET = 219, + KEY_BACK_SLASH = 220, + KEY_CLOSE_BRACKET = 221, + KEY_QUOTE = 222, + KEY_META = 224 +} +declare namespace ppt { + export enum EventType { + KEY_PRESS, + KEY_RELEASE, + KEY_TYPED + } + export enum SpecialKey { + CTRL, + WINDOWS, + SHIFT, + ALT + } + export interface KeyDescriptor { + key_code: string; + key_ctrl: boolean; + key_windows: boolean; + key_shift: boolean; + key_alt: boolean; + } + export interface KeyEvent extends KeyDescriptor { + readonly type: EventType; + readonly key: string; + } + export interface KeyHook extends KeyDescriptor { + cancel: boolean; + callback_press: () => any; + callback_release: () => any; + } + export function key_description(key: KeyDescriptor); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/ConnectionProfile.ts */ +declare namespace profiles { + export class ConnectionProfile { + id: string; + profile_name: string; + default_username: string; + default_password: string; + selected_identity_type: string; + identities: { + [key: string]: identities.Identity; + }; + constructor(id: string); + selected_identity(current_type?: identities.IdentitifyType): identities.Identity; + selected_type?(): identities.IdentitifyType; + set_identity(type: identities.IdentitifyType, identity: identities.Identity); + spawn_identity_handshake_handler?(connection: connection.AbstractServerConnection): connection.HandshakeIdentityHandler; + encode?(): string; + valid(): boolean; + } + export function load(): Promise; + export function create_new_profile(name: string, id?: string): ConnectionProfile; + export function save(); + export function mark_need_save(); + export function requires_save(): boolean; + export function profiles(): ConnectionProfile[]; + export function find_profile(id: string): ConnectionProfile | undefined; + export function find_profile_by_name(name: string): ConnectionProfile | undefined; + export function default_profile(): ConnectionProfile; + export function set_default_profile(profile: ConnectionProfile); + export function delete_profile(profile: ConnectionProfile); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/identities/NameIdentity.ts */ +declare namespace profiles.identities { + export class NameHandshakeHandler extends AbstractHandshakeIdentityHandler { + readonly identity: NameIdentity; + handler: HandshakeCommandHandler; + constructor(connection: connection.AbstractServerConnection, identity: profiles.identities.NameIdentity); + start_handshake(); + protected trigger_fail(message: string); + protected trigger_success(); + } + export class NameIdentity implements Identity { + private _name: string; + constructor(name?: string); + set_name(name: string); + name(): string; + uid(): string; + type(): IdentitifyType; + valid(): boolean; + decode(data): Promise; + encode?(): string; + spawn_identity_handshake_handler(connection: connection.AbstractServerConnection): connection.HandshakeIdentityHandler; + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/identities/TeaForumIdentity.ts */ +declare namespace profiles.identities { + export class TeaForumHandshakeHandler extends AbstractHandshakeIdentityHandler { + readonly identity: TeaForumIdentity; + handler: HandshakeCommandHandler; + constructor(connection: connection.AbstractServerConnection, identity: profiles.identities.TeaForumIdentity); + start_handshake(); + private handle_proof(json); + protected trigger_fail(message: string); + protected trigger_success(); + } + export class TeaForumIdentity implements Identity { + private readonly identity_data: forum.Data; + valid(): boolean; + constructor(data: forum.Data); + data(): forum.Data; + decode(data): Promise; + encode(): string; + spawn_identity_handshake_handler(connection: connection.AbstractServerConnection): connection.HandshakeIdentityHandler; + name(): string; + type(): profiles.identities.IdentitifyType; + uid(): string; + } + export function set_static_identity(identity: TeaForumIdentity); + export function update_forum(); + export function valid_static_forum_identity(): boolean; + export function static_forum_identity(): TeaForumIdentity | undefined; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/identities/TeamSpeakIdentity.ts */ +declare namespace profiles.identities { + export namespace CryptoHelper { + export function base64_url_encode(str); + export function base64_url_decode(str: string, pad?: boolean); + export function arraybuffer_to_string(buf); + export function export_ecc_key(crypto_key: CryptoKey, public_key: boolean): Promise; + export function decrypt_ts_identity(buffer: Uint8Array): Promise; + export function encrypt_ts_identity(buffer: Uint8Array): Promise; + /** + * @param buffer base64 encoded ASN.1 string + */ + export function decode_tomcrypt_key(buffer: string); + } + export class TeaSpeakHandshakeHandler extends AbstractHandshakeIdentityHandler { + identity: TeaSpeakIdentity; + handler: HandshakeCommandHandler; + constructor(connection: connection.AbstractServerConnection, identity: TeaSpeakIdentity); + start_handshake(); + private handle_proof(json); + protected trigger_fail(message: string); + protected trigger_success(); + } + export class IdentityPOWWorker { + private _worker: Worker; + private _current_hash: string; + private _best_level: number; + initialize(key: string); + mine(hash: string, iterations: number, target: number, timeout?: number): Promise; + current_hash(): string; + current_level(): number; + finalize(timeout?: number); + private handle_message(message: any); + } + export class TeaSpeakIdentity implements Identity { + static generate_new(): Promise; + static import_ts(ts_string: string, ini?: boolean): Promise; + hash_number: string; + private_key: string; + _name: string; + public_key: string; + private _initialized: boolean; + private _crypto_key: CryptoKey; + private _crypto_key_sign: CryptoKey; + private _unique_id: string; + constructor(private_key?: string, hash?: string, name?: string, initialize?: boolean); + name(): string; + uid(): string; + type(): IdentitifyType; + valid(): boolean; + decode(data: string): Promise; + encode?(): string; + level(): Promise; + /** + * @param {string} a + * @param {string} b + * @description b must be smaller (in bytes) then a + */ + private string_add(a: string, b: string); + improve_level_for(time: number, threads: number): Promise; + improve_level(target: number, threads: number, active_callback: () => boolean, callback_level?: (current: number) => any, callback_status?: (hash_rate: number) => any): Promise; + private initialize(); + export_ts(ini?: boolean): Promise; + sign_message(message: string, hash?: string): Promise; + spawn_identity_handshake_handler(connection: connection.AbstractServerConnection): connection.HandshakeIdentityHandler; + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/identities/teaspeak-forum.ts */ +declare interface Window { + grecaptcha: GReCaptcha; +} +declare interface GReCaptcha { + render(container: string | HTMLElement, parameters: { + sitekey: string; + theme?: "dark" | "light"; + size?: "compact" | "normal"; + tabindex?: number; + callback?: (token: string) => any; + "expired-callback"?: () => any; + "error-callback"?: (error: any) => any; + }): string; /* widget_id */ + reset(widget_id?: string); +} +declare namespace forum { + export namespace gcaptcha { + export function initialize(): Promise; + export function spawn(container: JQuery, key: string, callback_data: (token: string) => any): Promise; + } + export class Data { + readonly auth_key: string; + readonly raw: string; + readonly sign: string; + parsed: { + user_id: number; + user_name: string; + data_age: number; + user_group_id: number; + is_staff: boolean; + user_groups: number[]; + }; + constructor(auth: string, raw: string, sign: string); + data_json(): string; + data_sign(): string; + name(): string; + user_id(); + user_group(); + is_stuff(): boolean; + is_premium(): boolean; + data_age(): Date; + is_expired(): boolean; + should_renew(): boolean; + } + export function logged_in(): boolean; + export function data(): Data; + export interface LoginResult { + status: "success" | "captcha" | "error"; + error_message?: string; + captcha?: { + type: "gre-captcha" | "unknown"; + data: any; /* in case of gre-captcha it would be the side key */ + }; + } + export function login(username: string, password: string, captcha?: any): Promise; + export function renew_data(): Promise<"success" | "login-required">; + export function logout(): Promise; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/Identity.ts */ +declare namespace profiles.identities { + export enum IdentitifyType { + TEAFORO, + TEAMSPEAK, + NICKNAME + } + export interface Identity { + name(): string; + uid(): string; + type(): IdentitifyType; + valid(): boolean; + encode?(): string; + decode(data: string): Promise; + spawn_identity_handshake_handler(connection: connection.AbstractServerConnection): connection.HandshakeIdentityHandler; + } + export function decode_identity(type: IdentitifyType, data: string): Promise; + export function create_identity(type: IdentitifyType); + export class HandshakeCommandHandler extends connection.AbstractCommandHandler { + readonly handle: T; + constructor(connection: connection.AbstractServerConnection, handle: T); + handle_command(command: connection.ServerCommand): boolean; + } + export abstract class AbstractHandshakeIdentityHandler implements connection.HandshakeIdentityHandler { + connection: connection.AbstractServerConnection; + protected callbacks: ((success: boolean, message?: string) => any)[]; + protected constructor(connection: connection.AbstractServerConnection); + register_callback(callback: (success: boolean, message?: string) => any); + abstract start_handshake(); + protected trigger_success(); + protected trigger_fail(message: string); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/proto.ts */ +declare interface Array { + remove(elem?: T): boolean; + last?(): T; + pop_front(): T | undefined; +} +declare interface JSON { + map_to(object: T, json: any, variables?: string | string[], validator?: (map_field: string, map_value: string) => boolean, variable_direction?: number): T; + map_field_to(object: T, value: any, field: string): T; +} +declare type JQueryScrollType = "height" | "width"; +declare interface JQuery { + render(values?: any): string; + renderTag(values?: any): JQuery; + hasScrollBar(direction?: JQueryScrollType): boolean; + visible_height(): number; + visible_width(): number; + /* bootstrap */ + alert(): JQuery; + modal(properties: any): this; + bootstrapMaterialDesign(): this; + /* first element which matches the selector, could be the element itself or a parent */ + firstParent(selector: string): JQuery; +} +declare interface JQueryStatic { + spawn(tagName: K): JQuery; + views: any; +} +declare interface String { + format(...fmt): string; + format(arguments: string[]): string; +} +declare function concatenate(resultConstructor, ...arrays); +declare function formatDate(secs: number): string; +declare function calculate_width(text: string): number; +declare interface Twemoji { + parse(message: string): string; +} +declare let twemoji: Twemoji; +declare interface HighlightJS { + listLanguages(): string[]; + getLanguage(name: string): any | undefined; + highlight(language: string, text: string, ignore_illegals?: boolean): HighlightJSResult; + highlightAuto(text: string): HighlightJSResult; +} +declare interface HighlightJSResult { + language: string; + relevance: number; + value: string; + second_best?: any; +} +declare interface DOMPurify { + sanitize(html: string, config?: { + ADD_ATTR?: string[]; + }): string; +} +declare let DOMPurify: DOMPurify; +declare let remarkable: typeof window.remarkable; +declare class webkitAudioContext extends AudioContext { +} +declare class webkitOfflineAudioContext extends OfflineAudioContext { +} +declare interface Window { + readonly webkitAudioContext: typeof webkitAudioContext; + readonly AudioContext: typeof webkitAudioContext; + readonly OfflineAudioContext: typeof OfflineAudioContext; + readonly webkitOfflineAudioContext: typeof webkitOfflineAudioContext; + readonly RTCPeerConnection: typeof RTCPeerConnection; + readonly Pointer_stringify: any; + readonly jsrender: any; + twemoji: Twemoji; + hljs: HighlightJS; + remarkable: any; + require(id: string): any; +} +declare interface Navigator { + browserSpecs: { + name: string; + version: string; + }; + mozGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void; + webkitGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/settings.ts */ +declare interface SettingsKey { + key: string; + fallback_keys?: string | string[]; + fallback_imports?: { + [key: string]: (value: string) => T; + }; + description?: string; + default_value?: T; + require_restart?: boolean; +} +declare class SettingsBase { + protected static readonly UPDATE_DIRECT: boolean; + protected static transformStO?(input?: string, _default?: T, default_type?: string): T; + protected static transformOtS?(input: T): string; + protected static resolveKey(key: SettingsKey, _default: T, resolver: (key: string) => string | boolean, default_type?: string): T; + protected static keyify(key: string | SettingsKey): SettingsKey; +} +declare class StaticSettings extends SettingsBase { + private static _instance: StaticSettings; + // @ts-ignore + static get instance(): StaticSettings; + protected _handle: StaticSettings; + protected _staticPropsTag: JQuery; + protected constructor(_reserved?); + private initializeStatic(); + static?(key: string | SettingsKey, _default?: T, default_type?: string): T; + deleteStatic(key: string | SettingsKey); +} +declare class Settings extends StaticSettings { + static readonly KEY_DISABLE_COSMETIC_SLOWDOWN: SettingsKey; + static readonly KEY_DISABLE_CONTEXT_MENU: SettingsKey; + static readonly KEY_DISABLE_GLOBAL_CONTEXT_MENU: SettingsKey; + static readonly KEY_DISABLE_UNLOAD_DIALOG: SettingsKey; + static readonly KEY_DISABLE_VOICE: SettingsKey; + static readonly KEY_DISABLE_MULTI_SESSION: SettingsKey; + static readonly KEY_LOAD_DUMMY_ERROR: SettingsKey; + /* Control bar */ + static readonly KEY_CONTROL_MUTE_INPUT: SettingsKey; + static readonly KEY_CONTROL_MUTE_OUTPUT: SettingsKey; + static readonly KEY_CONTROL_SHOW_QUERIES: SettingsKey; + static readonly KEY_CONTROL_CHANNEL_SUBSCRIBE_ALL: SettingsKey; + /* Connect parameters */ + static readonly KEY_FLAG_CONNECT_DEFAULT: SettingsKey; + static readonly KEY_CONNECT_ADDRESS: SettingsKey; + static readonly KEY_CONNECT_PROFILE: SettingsKey; + static readonly KEY_CONNECT_USERNAME: SettingsKey; + static readonly KEY_CONNECT_PASSWORD: SettingsKey; + static readonly KEY_FLAG_CONNECT_PASSWORD: SettingsKey; + static readonly KEY_CONNECT_HISTORY: SettingsKey; + static readonly KEY_CERTIFICATE_CALLBACK: SettingsKey; + /* sounds */ + static readonly KEY_SOUND_MASTER: SettingsKey; + static readonly KEY_SOUND_MASTER_SOUNDS: SettingsKey; + static readonly KEY_CHAT_FIXED_TIMESTAMPS: SettingsKey; + static readonly KEY_CHAT_COLLOQUIAL_TIMESTAMPS: SettingsKey; + static readonly KEY_CHAT_COLORED_EMOJIES: SettingsKey; + static readonly KEY_CHAT_TAG_URLS: SettingsKey; + static readonly KEY_CHAT_ENABLE_MARKDOWN: SettingsKey; + static readonly KEY_CHAT_ENABLE_BBCODE: SettingsKey; + static readonly KEY_SWITCH_INSTANT_CHAT: SettingsKey; + static readonly KEY_SWITCH_INSTANT_CLIENT: SettingsKey; + static readonly KEY_HOSTBANNER_BACKGROUND: SettingsKey; + static readonly KEY_CHANNEL_EDIT_ADVANCED: SettingsKey; + static readonly KEY_TEAFORO_URL: SettingsKey; + static readonly KEY_FONT_SIZE: SettingsKey; + static readonly FN_SERVER_CHANNEL_SUBSCRIBE_MODE: (channel_id: number) => SettingsKey; + static readonly FN_PROFILE_RECORD: (name: string) => SettingsKey; + static readonly KEYS; + static initialize(); + private cacheGlobal; + private saveWorker: NodeJS.Timer; + private updated: boolean; + constructor(); + static_global?(key: string | SettingsKey, _default?: T): T; + global?(key: string | SettingsKey, _default?: T): T; + changeGlobal(key: string | SettingsKey, value?: T); + save(); +} +declare class ServerSettings extends SettingsBase { + private cacheServer; + private _server_unique_id: string; + private _server_save_worker: NodeJS.Timer; + private _server_settings_updated: boolean; + private _destroyed; + constructor(); + destroy(); + server?(key: string | SettingsKey, _default?: T): T; + changeServer(key: string | SettingsKey, value?: T); + setServer(server_unique_id: string); + save(); +} +declare let settings: Settings; + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts */ +declare enum Sound { + SOUND_TEST = "sound.test", + SOUND_EGG = "sound.egg", + AWAY_ACTIVATED = "away_activated", + AWAY_DEACTIVATED = "away_deactivated", + MICROPHONE_MUTED = "microphone.muted", + MICROPHONE_ACTIVATED = "microphone.activated", + SOUND_MUTED = "sound.muted", + SOUND_ACTIVATED = "sound.activated", + CONNECTION_CONNECTED = "connection.connected", + CONNECTION_DISCONNECTED = "connection.disconnected", + CONNECTION_BANNED = "connection.banned", + CONNECTION_DISCONNECTED_TIMEOUT = "connection.disconnected.timeout", + CONNECTION_REFUSED = "connection.refused", + SERVER_EDITED = "server.edited", + SERVER_EDITED_SELF = "server.edited.self", + SERVER_KICKED = "server.kicked", + CHANNEL_CREATED = "channel.created", + CHANNEL_MOVED = "channel.moved", + CHANNEL_EDITED = "channel.edited", + CHANNEL_EDITED_SELF = "channel.edited.self", + CHANNEL_DELETED = "channel.deleted", + CHANNEL_JOINED = "channel.joined", + CHANNEL_KICKED = "channel.kicked", + USER_MOVED = "user.moved", + USER_MOVED_SELF = "user.moved.self", + USER_POKED_SELF = "user.poked.self", + USER_BANNED = "user.banned", + USER_ENTERED = "user.joined", + USER_ENTERED_MOVED = "user.joined.moved", + USER_ENTERED_KICKED = "user.joined.kicked", + USER_ENTERED_CONNECT = "user.joined.connect", + USER_LEFT = "user.left", + USER_LEFT_MOVED = "user.left.moved", + USER_LEFT_KICKED_CHANNEL = "user.left.kicked.server", + USER_LEFT_KICKED_SERVER = "user.left.kicked.channel", + USER_LEFT_DISCONNECT = "user.left.disconnect", + USER_LEFT_BANNED = "user.left.banned", + USER_LEFT_TIMEOUT = "user.left.timeout", + ERROR_INSUFFICIENT_PERMISSIONS = "error.insufficient_permissions", + MESSAGE_SEND = "message.send", + MESSAGE_RECEIVED = "message.received", + GROUP_SERVER_ASSIGNED = "group.server.assigned", + GROUP_SERVER_REVOKED = "group.server.revoked", + GROUP_CHANNEL_CHANGED = "group.channel.changed", + GROUP_SERVER_ASSIGNED_SELF = "group.server.assigned.self", + GROUP_SERVER_REVOKED_SELF = "group.server.revoked.self", + GROUP_CHANNEL_CHANGED_SELF = "group.channel.changed.self" +} +declare namespace sound { + export interface SoundHandle { + key: string; + filename: string; + not_supported?: boolean; + not_supported_timeout?: number; + cached?: AudioBuffer; + node?: HTMLAudioElement; + replaying: boolean; + } + export function get_sound_volume(sound: Sound, default_volume?: number): number; + export function set_sound_volume(sound: Sound, volume: number); + export function get_master_volume(): number; + export function set_master_volume(volume: number); + export function overlap_activated(): boolean; + export function set_overlap_activated(flag: boolean); + export function ignore_output_muted(): boolean; + export function set_ignore_output_muted(flag: boolean); + export function reinitialisize_audio(); + export function save(); + export function initialize(): Promise; + export interface PlaybackOptions { + ignore_muted?: boolean; + ignore_overlap?: boolean; + default_volume?: number; + callback?: (flag: boolean) => any; + } + export function resolve_sound(sound: Sound): Promise; + export let manager: SoundManager; + export class SoundManager { + private _handle: ConnectionHandler; + private _playing_sounds: { + [key: string]: number; + }; + constructor(handle: ConnectionHandler); + play(_sound: Sound, options?: PlaybackOptions); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/stats.ts */ +declare namespace stats { + export enum CloseCodes { + UNSET = 3000, + RECONNECT = 3001, + INTERNAL_ERROR = 3002, + BANNED = 3100 + } + export enum ConnectionState { + CONNECTING, + INITIALIZING, + CONNECTED, + UNSET + } + export class SessionConfig { + /* + * All collected statistics will only be cached by the stats server. + * No data will be saved. + */ + volatile_collection_only?: boolean; + /* + * Anonymize all IP addresses which will be provided while the stats collection. + * This option is quite useless when volatile_collection_only is active. + */ + anonymize_ip_addresses?: boolean; + } + export class Config extends SessionConfig { + verbose?: boolean; + reconnect_interval?: number; + } + export interface UserCountData { + online_users: number; + unique_online_users: number; + } + export type UserCountListener = (data: UserCountData) => any; + export function initialize(config: Config); + export function register_user_count_listener(listener: UserCountListener); + export function all_user_count_listener(): UserCountListener[]; + export function deregister_user_count_listener(listener: UserCountListener); + namespace connection { + export let connection_state: ConnectionState; + export function start_connection(); + export function close_connection(); + export function cancel_reconnect(); + namespace handler { } + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/channel.ts */ +declare enum ChannelType { + PERMANENT, + SEMI_PERMANENT, + TEMPORARY +} +declare namespace ChannelType { + export function normalize(mode: ChannelType); +} +declare enum ChannelSubscribeMode { + SUBSCRIBED, + UNSUBSCRIBED, + INHERITED +} +declare class ChannelProperties { + channel_order: number; + channel_name: string; + channel_name_phonetic: string; + channel_topic: string; + channel_password: string; + channel_codec: number; + channel_codec_quality: number; + channel_codec_is_unencrypted: boolean; + channel_maxclients: number; + channel_maxfamilyclients: number; + channel_needed_talk_power: number; + channel_flag_permanent: boolean; + channel_flag_semi_permanent: boolean; + channel_flag_default: boolean; + channel_flag_password: boolean; + channel_flag_maxclients_unlimited: boolean; + channel_flag_maxfamilyclients_inherited: boolean; + channel_flag_maxfamilyclients_unlimited: boolean; + channel_icon_id: number; + channel_delete_delay: number; + //Only after request + channel_description: string; + channel_flag_conversation_private: boolean; +} +declare class ChannelEntry { + channelTree: ChannelTree; + channelId: number; + parent?: ChannelEntry; + properties: ChannelProperties; + channel_previous?: ChannelEntry; + channel_next?: ChannelEntry; + private _channel_name_alignment: string; + private _channel_name_formatted: string; + private _family_index: number; + //HTML DOM elements + private _tag_root: JQuery; + private _tag_siblings: JQuery; + private _tag_clients: JQuery; + private _tag_channel: JQuery; + private _destroyed; + private _cachedPassword: string; + private _cached_channel_description: string; + private _cached_channel_description_promise: Promise; + private _cached_channel_description_promise_resolve: any; + private _cached_channel_description_promise_reject: any; + private _flag_subscribed: boolean; + private _subscribe_mode: ChannelSubscribeMode; + constructor(channelId, channelName, parent?); + destroy(); + channelName(); + formattedChannelName(); + getChannelDescription(): Promise; + parent_channel(); + hasParent(); + getChannelId(); + children(deep?): ChannelEntry[]; + clients(deep?): ClientEntry[]; + clients_ordered(): ClientEntry[]; + update_family_index(enforce?: boolean); + calculate_family_index(enforce_recalculate?: boolean): number; + private initializeTag(); + rootTag(): JQuery; + channelTag(): JQuery; + siblingTag(): JQuery; + clientTag(): JQuery; + reorderClients(); + initializeListener(); + showContextMenu(x: number, y: number, on_close?: () => void); + handle_frame_resized(); + private static NAME_ALIGNMENTS: string[]; + private __updateChannelName(); + recalculate_repetitive_name(); + updateVariables(...variables: { + key: string; + value: string; + }[]); + updateChannelTypeIcon(); + generate_bbcode(); + generate_tag(braces?: boolean): JQuery; + channelType(): ChannelType; + joinChannel(); + cached_password(); + subscribe(): Promise; + unsubscribe(inherited_subscription_mode?: boolean): Promise; + // @ts-ignore + get flag_subscribed(): boolean; + // @ts-ignore + set flag_subscribed(flag: boolean); + // @ts-ignore + get subscribe_mode(): ChannelSubscribeMode; + // @ts-ignore + set subscribe_mode(mode: ChannelSubscribeMode); + // @ts-ignore + set flag_text_unread(flag: boolean); + log_data(): log.server.base.Channel; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/client_move.ts */ +declare class ClientMover { + static readonly listener_root; + static readonly move_element; + readonly channel_tree: ChannelTree; + selected_client: ClientEntry | ClientEntry[]; + hovered_channel: HTMLDivElement; + callback: (channel?: ChannelEntry) => any; + enabled: boolean; + private _bound_finish; + private _bound_move; + private _active: boolean; + private origin_point: { + x: number; + y: number; + }; + constructor(tree: ChannelTree); + is_active(); + private hover_text(); + private bbcode_text(); + activate(client: ClientEntry | ClientEntry[], callback: (channel?: ChannelEntry) => any, event: any); + private move_listener(event); + private finish_listener(event); + deactivate(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/client.ts */ +declare enum ClientType { + CLIENT_VOICE, + CLIENT_QUERY, + CLIENT_INTERNAL, + CLIENT_WEB, + CLIENT_MUSIC, + CLIENT_UNDEFINED +} +declare class ClientProperties { + client_type: ClientType; + client_type_exact: ClientType; + client_database_id: number; + client_version: string; + client_platform: string; + client_nickname: string; + client_unique_identifier: string; + client_description: string; + client_servergroups: string; + client_channel_group_id: number; + client_lastconnected: number; + client_created: number; + client_totalconnections: number; + client_flag_avatar: string; + client_icon_id: number; + client_away_message: string; + client_away: boolean; + client_country: string; + client_input_hardware: boolean; + client_output_hardware: boolean; + client_input_muted: boolean; + client_output_muted: boolean; + client_is_channel_commander: boolean; + client_teaforo_id: number; + client_teaforo_name: string; + client_teaforo_flags: number; + /* not updated in view! */ + client_month_bytes_uploaded: number; + client_month_bytes_downloaded: number; + client_total_bytes_uploaded: number; + client_total_bytes_downloaded: number; + client_talk_power: number; +} +declare class ClientConnectionInfo { + connection_bandwidth_received_last_minute_control: number; + connection_bandwidth_received_last_minute_keepalive: number; + connection_bandwidth_received_last_minute_speech: number; + connection_bandwidth_received_last_second_control: number; + connection_bandwidth_received_last_second_keepalive: number; + connection_bandwidth_received_last_second_speech: number; + connection_bandwidth_sent_last_minute_control: number; + connection_bandwidth_sent_last_minute_keepalive: number; + connection_bandwidth_sent_last_minute_speech: number; + connection_bandwidth_sent_last_second_control: number; + connection_bandwidth_sent_last_second_keepalive: number; + connection_bandwidth_sent_last_second_speech: number; + connection_bytes_received_control: number; + connection_bytes_received_keepalive: number; + connection_bytes_received_speech: number; + connection_bytes_sent_control: number; + connection_bytes_sent_keepalive: number; + connection_bytes_sent_speech: number; + connection_packets_received_control: number; + connection_packets_received_keepalive: number; + connection_packets_received_speech: number; + connection_packets_sent_control: number; + connection_packets_sent_keepalive: number; + connection_packets_sent_speech: number; + connection_ping: number; + connection_ping_deviation: number; + connection_server2client_packetloss_control: number; + connection_server2client_packetloss_keepalive: number; + connection_server2client_packetloss_speech: number; + connection_server2client_packetloss_total: number; + connection_client2server_packetloss_speech: number; + connection_client2server_packetloss_keepalive: number; + connection_client2server_packetloss_control: number; + connection_client2server_packetloss_total: number; + connection_filetransfer_bandwidth_sent: number; + connection_filetransfer_bandwidth_received: number; + connection_connected_time: number; + connection_idle_time: number; + connection_client_ip: string | undefined; + connection_client_port: number; +} +declare class ClientEntry { + protected _clientId: number; + protected _channel: ChannelEntry; + protected _tag: JQuery; + protected _properties: ClientProperties; + protected lastVariableUpdate: number; + protected _speaking: boolean; + protected _listener_initialized: boolean; + protected _audio_handle: connection.voice.VoiceClient; + protected _audio_volume: number; + protected _audio_muted: boolean; + private _info_variables_promise: Promise; + private _info_variables_promise_timestamp: number; + private _info_connection_promise: Promise; + private _info_connection_promise_timestamp: number; + private _info_connection_promise_resolve: any; + private _info_connection_promise_reject: any; + channelTree: ChannelTree; + constructor(clientId: number, clientName, properties?: ClientProperties); + destroy(); + tree_unregistered(); + set_audio_handle(handle: connection.voice.VoiceClient); + get_audio_handle(): connection.voice.VoiceClient; + // @ts-ignore + get properties(): ClientProperties; + currentChannel(): ChannelEntry; + clientNickName(); + clientUid(); + clientId(); + is_muted(); + set_muted(flag: boolean, update_icon: boolean, force?: boolean); + protected initializeListener(); + protected contextmenu_info(): contextmenu.MenuEntry[]; + protected assignment_context(): contextmenu.MenuEntry[]; + open_text_chat(); + showContextMenu(x: number, y: number, on_close?: () => void); + // @ts-ignore + get tag(): JQuery; + static bbcodeTag(id: number, name: string, uid: string): string; + static chatTag(id: number, name: string, uid: string, braces?: boolean): JQuery; + create_bbcode(): string; + createChatTag(braces?: boolean): JQuery; + // @ts-ignore + set speaking(flag); + updateClientStatusIcons(); + updateClientSpeakIcon(); + updateAwayMessage(); + updateVariables(...variables: { + key: string; + value: string; + }[]); + update_displayed_client_groups(); + updateClientVariables(force_update?: boolean): Promise; + updateClientIcon(); + updateGroupIcon(group: Group); + update_group_icon_order(); + assignedServerGroupIds(): number[]; + assignedChannelGroup(): number; + groupAssigned(group: Group): boolean; + onDelete(); + calculateOnlineTime(): number; + avatarId?(): string; + update_family_index(); + log_data(): log.server.base.Client; + /* max 1s ago, so we could update every second */ + request_connection_info(): Promise; + set_connection_info(info: ClientConnectionInfo); +} +declare class LocalClientEntry extends ClientEntry { + handle: ConnectionHandler; + private renaming: boolean; + constructor(handle: ConnectionHandler); + showContextMenu(x: number, y: number, on_close?: () => void): void; + initializeListener(): void; + openRename(): void; +} +declare class MusicClientProperties extends ClientProperties { + player_state: number; + player_volume: number; + client_playlist_id: number; + client_disabled: boolean; +} +declare class MusicClientPlayerInfo { + bot_id: number; + player_state: number; + player_buffered_index: number; + player_replay_index: number; + player_max_index: number; + player_seekable: boolean; + player_title: string; + player_description: string; + song_id: number; + song_url: string; + song_invoker: number; + song_loaded: boolean; + song_title: string; + song_thumbnail: string; + song_length: number; +} +declare class MusicClientEntry extends ClientEntry { + private _info_promise: Promise; + private _info_promise_age: number; + private _info_promise_resolve: any; + private _info_promise_reject: any; + constructor(clientId, clientName); + destroy(); + // @ts-ignore + get properties(): MusicClientProperties; + showContextMenu(x: number, y: number, on_close?: () => void): void; + initializeListener(): void; + handlePlayerInfo(json); + requestPlayerInfo(max_age?: number): Promise; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/context_divider.ts */ +declare interface JQuery { + dividerfy(): this; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/context_menu.ts */ +declare namespace contextmenu { + export interface MenuEntry { + callback?: () => void; + type: MenuEntryType; + name: (() => string) | string; + icon_class?: string; + icon_path?: string; + disabled?: boolean; + visible?: boolean; + checkbox_checked?: boolean; + invalidPermission?: boolean; + sub_menu?: MenuEntry[]; + } + export enum MenuEntryType { + CLOSE, + ENTRY, + CHECKBOX, + HR, + SUB_MENU + } + export class Entry { + static HR(); + static CLOSE(callback: () => void); + } + export interface ContextMenuProvider { + despawn_context_menu(); + spawn_context_menu(x: number, y: number, ...entries: MenuEntry[]); + initialize(); + finalize(); + html_format_enabled(): boolean; + } + export function spawn_context_menu(x: number, y: number, ...entries: MenuEntry[]); + export function despawn_context_menu(); + export function get_provider(): ContextMenuProvider; + export function set_provider(_provider: ContextMenuProvider); +} +declare class HTMLContextMenuProvider implements contextmenu.ContextMenuProvider { + private _global_click_listener: (event) => any; + private _context_menu: JQuery; + private _close_callbacks: (() => any)[]; + private _visible; + despawn_context_menu(); + finalize(); + initialize(); + private on_global_click(event); + private generate_tag(entry: contextmenu.MenuEntry): JQuery; + spawn_context_menu(x: number, y: number, ...entries: contextmenu.MenuEntry[]); + html_format_enabled(): boolean; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/modal.ts */ +declare enum ElementType { + HEADER, + BODY, + FOOTER +} +declare type BodyCreator = (() => JQuery | JQuery[] | string) | string | JQuery | JQuery[]; +declare const ModalFunctions; +declare class ModalProperties { + template?: string; + header: BodyCreator; + body: BodyCreator; + footer: BodyCreator; + closeListener: (() => void) | (() => void)[]; + registerCloseListener(listener: () => void): this; + width: number | string; + min_width?: number | string; + height: number | string; + closeable: boolean; + triggerClose(); + template_properties?: any; + trigger_tab: boolean; + full_size?: boolean; +} +declare let _global_modal_count; +declare let _global_modal_last: HTMLElement; +declare let _global_modal_last_time: number; +declare class Modal { + private _htmlTag: JQuery; + properties: ModalProperties; + shown: boolean; + open_listener: (() => any)[]; + close_listener: (() => any)[]; + close_elements: JQuery; + constructor(props: ModalProperties); + // @ts-ignore + get htmlTag(): JQuery; + private _create(); + open(); + close(); + set_closeable(flag: boolean); +} +declare function createModal(data: ModalProperties | any): Modal; +declare class InputModalProperties extends ModalProperties { + maxLength?: number; + field_title?: string; + field_label?: string; + field_placeholder?: string; + error_message?: string; +} +declare function createInputModal(headMessage: BodyCreator, question: BodyCreator, validator: (input: string) => boolean, callback: (flag: boolean | string) => void, props?: InputModalProperties | any): Modal; +declare function createErrorModal(header: BodyCreator, message: BodyCreator, props?: ModalProperties | any); +declare function createInfoModal(header: BodyCreator, message: BodyCreator, props?: ModalProperties | any); +declare interface ModalElements { + header?: BodyCreator; + body?: BodyCreator; + footer?: BodyCreator; +} +declare interface JQuery { + modalize(entry_callback?: (header: JQuery, body: JQuery, footer: JQuery) => ModalElements | void, properties?: ModalProperties | any): Modal; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/net_graph.ts */ +declare namespace net.graph { + export type Entry = { + timestamp: number; + upload: number; + download: number; + }; + export type Style = { + background_color: string; + separator_color: string; + separator_count: number; + separator_width: number; + upload: { + fill: string; + stroke: string; + strike_width: number; + }; + download: { + fill: string; + stroke: string; + strike_width: number; + }; + }; + export type TimeSpan = { + origin: { + begin: number; + end: number; + time: number; + }; + target: { + begin: number; + end: number; + time: number; + }; + }; + /* Great explanation of Bezier curves: http://en.wikipedia.org/wiki/Bezier_curve#Quadratic_curves + * + * Assuming A was the last point in the line plotted and B is the new point, + * we draw a curve with control points P and Q as below. + * + * A---P + * | + * | + * | + * Q---B + * + * Importantly, A and P are at the same y coordinate, as are B and Q. This is + * so adjacent curves appear to flow as one. + */ + export class Graph { + private static _loops: (() => any)[]; + readonly canvas: HTMLCanvasElement; + public style: Style; + private _canvas_context: CanvasRenderingContext2D; + private _entries: Entry[]; + private _entry_max; + private _max_space; + private _max_gap; + private _animate_loop; + private _time_span: TimeSpan; + constructor(canvas: HTMLCanvasElement); + initialize(); + terminate(); + max_gap_size(value?: number): number; + private recalculate_cache(time_span?: boolean); + insert_entry(entry: Entry); + insert_entries(entries: Entry[]); + resize(); + cleanup(); + private calculate_time_span(): { + begin: number; + end: number; + }; + draw(); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/slider.ts */ +declare interface SliderOptions { + min_value?: number; + max_value?: number; + initial_value?: number; + step?: number; + unit?: string; + value_field?: JQuery | JQuery[]; +} +declare interface Slider { + value(value?: number): number; +} +declare function sliderfy(slider: JQuery, options?: SliderOptions): Slider; + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/tab.ts */ +declare interface JQuery { + asTabWidget(copy?: boolean): JQuery; + tabify(copy?: boolean): this; + changeElementType(type: string): JQuery; +} +declare var TabFunctions; + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/tooltip.ts */ +declare function tooltip(entry: JQuery); +declare namespace tooltip { + export type Handle = { + show(); + is_shown(); + hide(); + update(); + }; + export function initialize(entry: JQuery): Handle; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/chat_frame.ts */ +declare namespace chat { + export enum InfoFrameMode { + NONE = "none", + CHANNEL_CHAT = "channel_chat", + PRIVATE_CHAT = "private_chat", + CLIENT_INFO = "client_info" + } + export class InfoFrame { + private readonly handle: Frame; + private _html_tag: JQuery; + private _mode: InfoFrameMode; + private _value_ping: JQuery; + private _ping_updater: number; + private _button_conversation: HTMLElement; + constructor(handle: Frame); + html_tag(): JQuery; + destroy(); + private _build_html_tag(); + update_ping(); + update_channel_talk(); + update_channel_text(); + update_chat_counter(); + current_mode(): InfoFrameMode; + set_mode(mode: InfoFrameMode); + } + export class ChatBox { + private _html_tag: JQuery; + private _html_input: JQuery; + private _enabled: boolean; + private __callback_text_changed; + private __callback_key_down; + private __callback_paste; + private _typing_timeout: number; + private _typing_last_event: number; + typing_interval: number; + callback_typing: () => any; + callback_text: (text: string) => any; + constructor(); + html_tag(): JQuery; + destroy(); + private _initialize_listener(); + private _build_html_tag(); + private _callback_text_changed(event: Event); + private _text(element: HTMLElement); + private htmlEscape(message: string): string; + private _callback_paste(event: ClipboardEvent); + private test_message(message: string): boolean; + private _callback_key_down(event: KeyboardEvent); + set_enabled(flag: boolean); + is_enabled(); + focus_input(); + } + export namespace helpers { + namespace md2bbc { + export type RemarkToken = { + type: string; + tight: boolean; + lines: number[]; + level: number; + /* img */ + alt?: string; + src?: string; + /* link */ + href?: string; + /* table */ + align?: string; + /* code */ + params?: string; + content?: string; + hLevel?: number; + children?: RemarkToken[]; + }; + export class Renderer { + private static renderers; + private _options; + render(tokens: RemarkToken[], options: any, env: any); + private render_token(token: RemarkToken, index: number); + private render_inline(tokens: RemarkToken[], index: number); + options(): any; + maybe_escape_bb(text: string); + } + } + export function preprocess_chat_message(message: string): string; + export namespace history { + export function load_history(key: string): Promise; + export function save_history(key: string, value: any): Promise; + } + export namespace date { + export function same_day(a: number | Date, b: number | Date); + } + } + export namespace format { + export namespace date { + export enum ColloquialFormat { + YESTERDAY, + TODAY, + GENERAL + } + export function date_format(date: Date, now: Date, ignore_settings?: boolean): ColloquialFormat; + export function format_date_general(date: Date, hours?: boolean): string; + export function format_date_colloquial(date: Date, current_timestamp: Date): { + result: string; + format: ColloquialFormat; + }; + export function format_chat_time(date: Date): { + result: string; + next_update: number; /* in MS */ + }; + } + export namespace time { + export function format_online_time(secs: number): string; + } + } + export type PrivateConversationViewEntry = { + html_tag: JQuery; + }; + export type PrivateConversationMessageData = { + message_id: string; + message: string; + sender: "self" | "partner"; + sender_name: string; + sender_unique_id: string; + sender_client_id: number; + timestamp: number; + }; + export type PrivateConversationViewMessage = PrivateConversationMessageData & PrivateConversationViewEntry & { + time_update_id: number; + }; + export type PrivateConversationViewSpacer = PrivateConversationViewEntry; + export enum PrivateConversationState { + OPEN, + CLOSED, + DISCONNECTED + } + export type DisplayedMessage = { + timestamp: number; + message: PrivateConversationViewMessage | PrivateConversationViewEntry; + message_type: "spacer" | "message"; + /* structure as following + 1. time pointer + 2. unread + 3. message + */ + tag_message: JQuery; + tag_unread: PrivateConversationViewSpacer | undefined; + tag_timepointer: PrivateConversationViewSpacer | undefined; + }; + export class PrivateConveration { + readonly handle: PrivateConverations; + private _html_entry_tag: JQuery; + private _message_history: PrivateConversationMessageData[]; + private _callback_message: (text: string) => any; + private _state: PrivateConversationState; + private _last_message_updater_id: number; + private _last_typing: number; + private _typing_timeout: number; + private _typing_timeout_task: number; + _scroll_position: number | undefined; + _html_message_container: JQuery; + client_unique_id: string; + client_id: number; + client_name: string; + private _displayed_messages: DisplayedMessage[]; + private _displayed_messages_length: number; + private _spacer_unread_message: DisplayedMessage; + constructor(handle: PrivateConverations, client_unique_id: string, client_name: string, client_id: number); + private history_key(); + private load_history(); + private save_history(); + entry_tag(): JQuery; + destroy(); + private _2d_flat(array: T[][]): T[]; + messages_tags(): JQuery[]; + append_message(message: string, sender: { + type: "self" | "partner"; + name: string; + unique_id: string; + client_id: number; + }, timestamp?: Date, save_history?: boolean); + private _displayed_message_first_tag(message: DisplayedMessage); + private _destroy_displayed_message(message: DisplayedMessage, update_pointers: boolean); + clear_messages(save?: boolean); + fix_scroll(animate: boolean); + private _update_message_timestamp(); + private _destroy_message(message: PrivateConversationViewMessage); + private _build_message(message: PrivateConversationMessageData): PrivateConversationViewMessage; + private _build_spacer(message: string, type: "date" | "new" | "disconnect" | "reconnect" | "closed" | "error"): PrivateConversationViewSpacer; + private _register_displayed_message(message: DisplayedMessage); + private _destroy_view_entry(entry: PrivateConversationViewEntry); + private _build_entry_tag(); + update_avatar(); + close_conversation(); + set_client_name(name: string); + set_unread_flag(flag: boolean, update_chat_counter?: boolean); + is_unread(): boolean; + private _append_state_change(state: "disconnect" | "reconnect" | "closed"); + state(): PrivateConversationState; + set_state(state: PrivateConversationState); + set_text_callback(callback: (text: string) => any, update_enabled_state?: boolean); + chat_enabled(); + append_error(message: string, date?: number); + call_message(message: string); + private typing_expired(); + trigger_typing(); + typing_active(); + } + export class PrivateConverations { + readonly handle: Frame; + private _chat_box: ChatBox; + private _html_tag: JQuery; + private _container_conversation: JQuery; + private _container_conversation_messages: JQuery; + private _container_conversation_list: JQuery; + private _container_typing: JQuery; + private _html_no_chats: JQuery; + private _conversations: PrivateConveration[]; + private _current_conversation: PrivateConveration; + private _select_read_timer: number; + constructor(handle: Frame); + clear_client_ids(); + html_tag(): JQuery; + destroy(); + current_conversation(): PrivateConveration | undefined; + conversations(): PrivateConveration[]; + create_conversation(client_uid: string, client_name: string, client_id: number): PrivateConveration; + delete_conversation(conv: PrivateConveration, update_chat_couner?: boolean); + find_conversation(partner: { + name: string; + unique_id: string; + client_id: number; + }, mode: { + create: boolean; + attach: boolean; + }): PrivateConveration | undefined; + clear_conversations(); + set_selected_conversation(conv: PrivateConveration | undefined); + update_chatbox_state(); + update_typing_state(); + private _build_html_tag(); + try_input_focus(); + on_show(); + } + export namespace channel { + export type ViewEntry = { + html_element: JQuery; + update_timer?: number; + }; + export type MessageData = { + timestamp: number; + message: string; + sender_name: string; + sender_unique_id: string; + sender_database_id: number; + }; + export type Message = MessageData & ViewEntry; + export class Conversation { + readonly handle: ConversationManager; + readonly channel_id: number; + private _flag_private: boolean; + private _html_tag: JQuery; + private _container_messages: JQuery; + private _container_new_message: JQuery; + private _container_no_permissions: JQuery; + private _container_is_private: JQuery; + private _view_max_messages; + private _view_older_messages: ViewEntry; + private _has_older_messages: boolean; + private _view_entries: ViewEntry[]; + private _last_messages: MessageData[]; + private _last_messages_timestamp: number; + private _first_unread_message: Message; + private _first_unread_message_pointer: ViewEntry; + private _scroll_position: number | undefined; + constructor(handle: ConversationManager, channel_id: number); + html_tag(): JQuery; + destroy(); + private _build_html_tag(); + is_unread(); + mark_read(); + private _mark_read(); + private _generate_view_message(data: MessageData): Message; + private _generate_view_spacer(message: string, type: "date" | "new" | "old" | "error"): ViewEntry; + last_messages_timestamp(): number; + fetch_last_messages(); + fetch_older_messages(); + register_new_message(message: MessageData, update_view?: boolean); + fix_scroll(animate: boolean); + fix_view_size(); + chat_available(): boolean; + text_send_failed(error: CommandResult | any); + set_flag_private(flag: boolean); + update_private_state(); + delete_message(message: MessageData); + delete_messages(begin: number, end: number, sender: number, limit: number); + private _delete_message(message: Message); + } + export class ConversationManager { + readonly handle: Frame; + private _html_tag: JQuery; + private _chat_box: ChatBox; + private _container_conversation: JQuery; + private _conversations: Conversation[]; + private _current_conversation: Conversation | undefined; + private _needed_listener; + constructor(handle: Frame); + initialize_needed_listener(); + html_tag(): JQuery; + destroy(); + update_chat_box(); + private _build_html_tag(); + set_current_channel(channel_id: number, update_info_frame?: boolean); + current_channel(): number; + /* Used by notifychanneldeleted */ + delete_conversation(channel_id: number); + reset(); + conversation(channel_id: number, create?: boolean): Conversation; + on_show(); + } + } + export class ClientInfo { + readonly handle: Frame; + private _html_tag: JQuery; + private _current_client: ClientEntry | undefined; + private _online_time_updater: number; + previous_frame_content: FrameContent; + constructor(handle: Frame); + html_tag(): JQuery; + destroy(); + private _build_html_tag(); + current_client(): ClientEntry; + set_current_client(client: ClientEntry | undefined, enforce?: boolean); + } + export enum FrameContent { + NONE, + PRIVATE_CHAT, + CHANNEL_CHAT, + CLIENT_INFO + } + export class Frame { + readonly handle: ConnectionHandler; + private _info_frame: InfoFrame; + private _html_tag: JQuery; + private _container_info: JQuery; + private _container_chat: JQuery; + private _content_type: FrameContent; + private _conversations: PrivateConverations; + private _client_info: ClientInfo; + private _channel_conversations: channel.ConversationManager; + constructor(handle: ConnectionHandler); + html_tag(): JQuery; + info_frame(): InfoFrame; + content_type(): FrameContent; + destroy(); + private _build_html_tag(); + private_conversations(): PrivateConverations; + channel_conversations(): channel.ConversationManager; + client_info(): ClientInfo; + private _clear(); + show_private_conversations(); + show_channel_conversations(); + show_client_info(client: ClientEntry); + set_content(type: FrameContent); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/chat.ts */ +declare enum ChatType { + GENERAL, + SERVER, + CHANNEL, + CLIENT +} +declare const xbbcode: any; +declare namespace MessageHelper { + export function htmlEscape(message: string): string[]; + export function formatElement(object: any, escape_html?: boolean): JQuery[]; + export function formatMessage(pattern: string, ...objects: any[]): JQuery[]; + export function bbcode_chat(message: string): JQuery[]; + export namespace network { + export const KB; + export const MB; + export const GB; + export const TB; + export function format_bytes(value: number, options?: { + time?: string; + unit?: string; + exact?: boolean; + }): string; + } + export const K; + export const M; + export const G; + export const T; + export function format_number(value: number, options?: { + time?: string; + unit?: string; + }); + export const TIME_SECOND; + export const TIME_MINUTE; + export const TIME_HOUR; + export const TIME_DAY; + export const TIME_WEEK; + export function format_time(time: number, default_value: string); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/connection_handlers.ts */ +declare let server_connections: ServerConnectionManager; +declare class ServerConnectionManager { + private connection_handlers: ConnectionHandler[]; + private active_handler: ConnectionHandler | undefined; + private _container_log_server: JQuery; + private _container_channel_tree: JQuery; + private _container_hostbanner: JQuery; + private _container_chat: JQuery; + private _tag: JQuery; + private _tag_connection_entries: JQuery; + private _tag_buttons_scoll: JQuery; + private _tag_button_scoll_right: JQuery; + private _tag_button_scoll_left: JQuery; + constructor(tag: JQuery); + spawn_server_connection_handler(): ConnectionHandler; + destroy_server_connection_handler(handler: ConnectionHandler); + set_active_connection_handler(handler: ConnectionHandler); + active_connection_handler(): ConnectionHandler | undefined; + server_connection_handlers(): ConnectionHandler[]; + update_ui(); + private _update_scroll(); + private _button_scroll_right_clicked(); + private _button_scroll_left_clicked(); + private _update_scroll_buttons(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts */ +declare let control_bar: ControlBar; +declare type MicrophoneState = "disabled" | "muted" | "enabled"; +declare type HeadphoneState = "muted" | "enabled"; +declare type AwayState = "away-global" | "away" | "online"; +declare class ControlBar { + private _button_away_active: AwayState; + private _button_microphone: MicrophoneState; + private _button_speakers: HeadphoneState; + private _button_subscribe_all: boolean; + private _button_query_visible: boolean; + private connection_handler: ConnectionHandler | undefined; + private _button_hostbanner: JQuery; + htmlTag: JQuery; + constructor(htmlTag: JQuery); + initialize_connection_handler_state(handler?: ConnectionHandler); + set_connection_handler(handler?: ConnectionHandler); + apply_server_state(); + apply_server_hostbutton(); + apply_server_voice_state(); + current_connection_handler(); + initialise(); + // @ts-ignore + set button_away_active(flag: AwayState); + update_button_away(); + // @ts-ignore + set button_microphone(state: MicrophoneState); + // @ts-ignore + set button_speaker(state: HeadphoneState); + // @ts-ignore + set button_subscribe_all(state: boolean); + // @ts-ignore + set button_query_visible(state: boolean); + /* UI listener */ + private on_away_toggle(); + private on_away_enable(); + private on_away_disable(); + private on_away_set_message(); + private on_away_enable_global(); + private on_away_disable_global(); + private on_away_set_message_global(); + private on_toggle_microphone(); + private on_toggle_sound(); + private on_toggle_channel_subscribe(); + private on_toggle_query_view(); + private on_open_settings(); + private on_open_connect(); + private on_open_connect_new_tab(); + update_connection_state(); + private on_execute_disconnect(); + private on_token_use(); + private on_token_list(); + private on_open_permissions(); + private on_open_banslist(); + private on_bookmark_server_add(); + update_bookmark_status(); + update_bookmarks(); + private on_bookmark_manage(); + private on_open_query_create(); + private on_open_query_manage(); + private on_open_playlist_manage(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/hostbanner.ts */ +declare class Hostbanner { + readonly html_tag: JQuery; + readonly client: ConnectionHandler; + private _destryed; + private updater: NodeJS.Timer; + constructor(client: ConnectionHandler); + destroy(); + update(); + public static generate_tag(banner_url: string | undefined, gfx_interval: number, mode: number): Promise; + private generate_tag?(): Promise; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/MenuBar.ts */ +declare namespace top_menu { + export interface HRItem { + } + export interface MenuItem { + append_item(label: string): MenuItem; + append_hr(): HRItem; + delete_item(item: MenuItem | HRItem); + items(): (MenuItem | HRItem)[]; + icon(klass?: string | Promise | Icon): string; + label(value?: string): string; + visible(value?: boolean): boolean; + disabled(value?: boolean): boolean; + click(callback: () => any): this; + } + export interface MenuBarDriver { + initialize(); + append_item(label: string): MenuItem; + delete_item(item: MenuItem); + items(): MenuItem[]; + flush_changes(); + } + export function driver(): MenuBarDriver; + export function set_driver(driver: MenuBarDriver); + export interface NativeActions { + open_dev_tools(); + reload_page(); + check_native_update(); + open_change_log(); + quit(); + } + export let native_actions: NativeActions; + namespace html { + export class HTMLHrItem implements top_menu.HRItem { + readonly html_tag: JQuery; + constructor(); + } + export class HTMLMenuItem implements top_menu.MenuItem { + readonly html_tag: JQuery; + readonly _label_tag: JQuery; + readonly _label_icon_tag: JQuery; + readonly _label_text_tag: JQuery; + readonly _submenu_tag: JQuery; + private _items: (MenuItem | HRItem)[]; + private _label: string; + private _callback_click: () => any; + constructor(label: string, mode: "side" | "down"); + append_item(label: string): top_menu.MenuItem; + append_hr(): HRItem; + delete_item(item: top_menu.MenuItem | top_menu.HRItem); + disabled(value?: boolean): boolean; + items(): (top_menu.MenuItem | top_menu.HRItem)[]; + label(value?: string): string; + visible(value?: boolean): boolean; + click(callback: () => any): this; + icon(klass?: string | Promise | Icon): string; + } + export class HTMLMenuBarDriver implements MenuBarDriver { + private static _instance: HTMLMenuBarDriver; + public static instance(): HTMLMenuBarDriver; + readonly html_tag: JQuery; + private _items: MenuItem[]; + constructor(); + append_item(label: string): top_menu.MenuItem; + delete_item(item: MenuItem); + items(): top_menu.MenuItem[]; + flush_changes(); + initialize(); + } + } + export function rebuild_bookmarks(); + export function update_state(); + namespace native { + export function initialize(); + } + export function initialize(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/server_log.ts */ +declare namespace log { + export namespace server { + export enum Type { + CONNECTION_BEGIN = "connection_begin", + CONNECTION_HOSTNAME_RESOLVE = "connection_hostname_resolve", + CONNECTION_HOSTNAME_RESOLVE_ERROR = "connection_hostname_resolve_error", + CONNECTION_HOSTNAME_RESOLVED = "connection_hostname_resolved", + CONNECTION_LOGIN = "connection_login", + CONNECTION_CONNECTED = "connection_connected", + CONNECTION_FAILED = "connection_failed", + CONNECTION_VOICE_SETUP_FAILED = "connection_voice_setup_failed", + CONNECTION_COMMAND_ERROR = "connection_command_error", + GLOBAL_MESSAGE = "global_message", + SERVER_WELCOME_MESSAGE = "server_welcome_message", + SERVER_HOST_MESSAGE = "server_host_message", + SERVER_HOST_MESSAGE_DISCONNECT = "server_host_message_disconnect", + SERVER_CLOSED = "server_closed", + SERVER_BANNED = "server_banned", + SERVER_REQUIRES_PASSWORD = "server_requires_password", + CLIENT_VIEW_ENTER = "client_view_enter", + CLIENT_VIEW_LEAVE = "client_view_leave", + CLIENT_VIEW_MOVE = "client_view_move", + CLIENT_NICKNAME_CHANGED = "client_nickname_changed", + CLIENT_NICKNAME_CHANGE_FAILED = "client_nickname_change_failed", + CLIENT_SERVER_GROUP_ADD = "client_server_group_add", + CLIENT_SERVER_GROUP_REMOVE = "client_server_group_remove", + CLIENT_CHANNEL_GROUP_CHANGE = "client_channel_group_change", + CHANNEL_CREATE = "channel_create", + CHANNEL_DELETE = "channel_delete", + ERROR_CUSTOM = "error_custom", + ERROR_PERMISSION = "error_permission", + RECONNECT_SCHEDULED = "reconnect_scheduled", + RECONNECT_EXECUTE = "reconnect_execute", + RECONNECT_CANCELED = "reconnect_canceled" + } + export namespace base { + export type Client = { + client_unique_id: string; + client_name: string; + client_id: number; + }; + export type Channel = { + channel_id: number; + channel_name: string; + }; + export type Server = { + server_name: string; + server_unique_id: string; + }; + export type ServerAddress = { + server_hostname: string; + server_port: number; + }; + } + export namespace event { + export type GlobalMessage = { + sender: base.Client; + message: string; + }; + export type ConnectBegin = { + address: base.ServerAddress; + client_nickname: string; + }; + export type ErrorCustom = { + message: string; + }; + export type ReconnectScheduled = { + timeout: number; + }; + export type ReconnectCanceled = {}; + export type ReconnectExecute = {}; + export type ErrorPermission = { + permission: PermissionInfo; + }; + export type WelcomeMessage = { + message: string; + }; + export type HostMessageDisconnect = { + message: string; + }; + //tr("You was moved by {3} from channel {1} to {2}") : tr("{0} was moved from channel {1} to {2} by {3}") + //tr("You switched from channel {1} to {2}") : tr("{0} switched from channel {1} to {2}") + //tr("You got kicked out of the channel {1} to channel {2} by {3}{4}") : tr("{0} got kicked from channel {1} to {2} by {3}{4}") + export type ClientMove = { + channel_from?: base.Channel; + channel_from_own: boolean; + channel_to?: base.Channel; + channel_to_own: boolean; + client: base.Client; + client_own: boolean; + invoker?: base.Client; + message?: string; + reason: ViewReasonId; + }; + export type ClientEnter = { + channel_from?: base.Channel; + channel_to?: base.Channel; + client: base.Client; + invoker?: base.Client; + message?: string; + own_channel: boolean; + reason: ViewReasonId; + ban_time?: number; + }; + export type ClientLeave = { + channel_from?: base.Channel; + channel_to?: base.Channel; + client: base.Client; + invoker?: base.Client; + message?: string; + own_channel: boolean; + reason: ViewReasonId; + ban_time?: number; + }; + export type ChannelCreate = { + creator: base.Client; + channel: base.Channel; + own_action: boolean; + }; + export type ChannelDelete = { + deleter: base.Client; + channel: base.Channel; + own_action: boolean; + }; + export type ConnectionConnected = { + own_client: base.Client; + }; + export type ConnectionFailed = {}; + export type ConnectionLogin = {}; + export type ConnectionHostnameResolve = {}; + export type ConnectionHostnameResolved = { + address: base.ServerAddress; + }; + export type ConnectionHostnameResolveError = { + message: string; + }; + export type ConnectionVoiceSetupFailed = { + reason: string; + reconnect_delay: number; /* if less or equal to 0 reconnect is prohibited */ + }; + export type ConnectionCommandError = { + error: any; + }; + export type ClientNicknameChanged = { + own_client: boolean; + client: base.Client; + old_name: string; + new_name: string; + }; + export type ClientNicknameChangeFailed = { + reason: string; + }; + export type ServerClosed = { + message: string; + }; + export type ServerRequiresPassword = {}; + export type ServerBanned = { + message: string; + time: number; + invoker: base.Client; + }; + } + export type LogMessage = { + type: Type; + timestamp: number; + data: any; + }; + export interface TypeInfo { + "connection_begin": event.ConnectBegin; + "global_message": event.GlobalMessage; + "error_custom": event.ErrorCustom; + "error_permission": event.ErrorPermission; + "connection_hostname_resolved": event.ConnectionHostnameResolved; + "connection_hostname_resolve": event.ConnectionHostnameResolve; + "connection_hostname_resolve_error": event.ConnectionHostnameResolveError; + "connection_failed": event.ConnectionFailed; + "connection_login": event.ConnectionLogin; + "connection_connected": event.ConnectionConnected; + "connection_voice_setup_failed": event.ConnectionVoiceSetupFailed; + "connection_command_error": event.ConnectionCommandError; + "reconnect_scheduled": event.ReconnectScheduled; + "reconnect_canceled": event.ReconnectCanceled; + "reconnect_execute": event.ReconnectExecute; + "server_welcome_message": event.WelcomeMessage; + "server_host_message": event.WelcomeMessage; + "server_host_message_disconnect": event.HostMessageDisconnect; + "server_closed": event.ServerClosed; + "server_requires_password": event.ServerRequiresPassword; + "server_banned": event.ServerBanned; + "client_view_enter": event.ClientEnter; + "client_view_move": event.ClientMove; + "client_view_leave": event.ClientLeave; + "client_nickname_change_failed": event.ClientNicknameChangeFailed; + "client_nickname_changed": event.ClientNicknameChanged; + "channel_create": event.ChannelCreate; + "channel_delete": event.ChannelDelete; + } + export type MessageBuilderOptions = {}; + export type MessageBuilder = (data: TypeInfo[T], options: MessageBuilderOptions) => JQuery[] | undefined; + export const MessageBuilders: { + [key: string]: MessageBuilder; + }; + } + export class ServerLog { + private readonly handle: ConnectionHandler; + private history_length: number; + private _log: server.LogMessage[]; + private _html_tag: JQuery; + private _log_container: JQuery; + private auto_follow: boolean; + private _ignore_event: number; + constructor(handle: ConnectionHandler); + log(type: T, data: server.TypeInfo[T]); + html_tag(): JQuery; + destroy(); + private append_log(message: server.LogMessage); + } +} +declare namespace log { + export namespace server { + namespace impl { } + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/htmltags.ts */ +declare namespace htmltags { + export interface ClientProperties { + client_id: number; + client_unique_id: string; + client_name: string; + add_braces?: boolean; + } + export interface ChannelProperties { + channel_id: number; + channel_name: string; + channel_display_name?: string; + add_braces?: boolean; + } + export function generate_client(properties: ClientProperties): string; + export function generate_client_object(properties: ClientProperties): JQuery; + export function generate_channel(properties: ChannelProperties): string; + export function generate_channel_object(properties: ChannelProperties): JQuery; + export namespace callbacks { + export function callback_context_client(element: JQuery); + export function callback_context_channel(element: JQuery); + } + namespace bbcodes { } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalAbout.ts */ +declare namespace Modals { + export function spawnAbout(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalAvatar.ts */ +declare namespace Modals { + //TODO: Test if we could render this image and not only the browser by knowing the type. + export function spawnAvatarUpload(callback_data: (data: ArrayBuffer | undefined | null) => any); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalAvatarList.ts */ +declare namespace Modals { + export const human_file_size; + export function spawnAvatarList(client: ConnectionHandler); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanClient.ts */ +declare namespace Modals { + export function spawnBanClient(name: string | string[], callback: (data: { + length: number; + reason: string; + no_name: boolean; + no_ip: boolean; + no_hwid: boolean; + }) => void); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanCreate.ts */ +declare namespace Modals { + export function spawnBanCreate(connection: ConnectionHandler, base?: BanEntry, callback?: (entry?: BanEntry) => any); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts */ +declare namespace Modals { + export interface BanEntry { + server_id: number; + banid: number; + name?: string; + name_type?: number; + unique_id?: string; + ip?: string; + hardware_id?: string; + reason: string; + invoker_name: string; + invoker_unique_id?: string; + invoker_database_id?: number; + timestamp_created: Date; + timestamp_expire: Date; + enforcements: number; + flag_own?: boolean; + } + export interface BanListManager { + addbans: (ban: BanEntry[]) => void; + clear: (ban?: any) => void; + modal: Modal; + } + export function openBanList(client: ConnectionHandler); + export function spawnBanListModal(callback_update: () => any, callback_add: () => any, callback_edit: (entry: BanEntry) => any, callback_delete: (entry: BanEntry) => any): BanListManager; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBookmarks.ts */ +declare namespace Modals { + export function spawnBookmarkModal(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBotMenue.ts */ + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts */ +declare namespace Modals { + export function spawnChangeVolume(current: number, callback: (number) => void); + /* Units are between 0 and 1 */ + export function spawnChangeRemoteVolume(current: number, max_value: number, callback: (value: number) => void); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalClientInfo.ts */ +declare namespace Modals { + export function openClientInfo(client: ClientEntry); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalConnect.ts */ +declare namespace connection_log { + //TODO: Save password data + export type ConnectionData = { + name: string; + icon_id: number; + country: string; + clients_online: number; + clients_total: number; + flag_password: boolean; + password_hash: string; + }; + export type ConnectionEntry = ConnectionData & { + address: { + hostname: string; + port: number; + }; + total_connection: number; + first_timestamp: number; + last_timestamp: number; + }; + export function log_connect(address: { + hostname: string; + port: number; + }); + export function update_address_info(address: { + hostname: string; + port: number; + }, data: ConnectionData); + export function update_address_password(address: { + hostname: string; + port: number; + }, password_hash: string); + export function history(): ConnectionEntry[]; + export function delete_entry(address: { + hostname: string; + port: number; + }); +} +declare namespace Modals { + export function spawnConnectModal(options: { + default_connect_new_tab?: boolean; /* default false */ + }, defaultHost?: { + url: string; + enforce: boolean; + }, connect_profile?: { + profile: profiles.ConnectionProfile; + enforce: boolean; + }); + export const Regex; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts */ +declare namespace Modals { + export function createChannelModal(connection: ConnectionHandler, channel: ChannelEntry | undefined, parent: ChannelEntry | undefined, permissions: PermissionManager, callback: (properties?: ChannelProperties, permissions?: PermissionValue[]) => any); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalGroupAssignment.ts */ +declare namespace Modals { + export function createServerGroupAssignmentModal(client: ClientEntry, callback: (group: Group, flag: boolean) => Promise); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalIconSelect.ts */ +declare namespace Modals { + export function spawnIconSelect(client: ConnectionHandler, callback_icon?: (id: number) => any, selected_icon?: number); + export function spawnIconUpload(client: ConnectionHandler); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalIdentity.ts */ +declare namespace Modals { + export function spawnTeamSpeakIdentityImprove(identity: profiles.identities.TeaSpeakIdentity, name: string): Modal; + export function spawnTeamSpeakIdentityImport(callback: (identity: profiles.identities.TeaSpeakIdentity) => any): Modal; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalInvite.ts */ +declare namespace Modals { + export function spawnInviteEditor(connection: ConnectionHandler); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalKeySelect.ts */ +declare namespace Modals { + export function spawnKeySelect(callback: (key?: ppt.KeyEvent) => void); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts */ +declare namespace Modals { + export function spawnPlaylistSongInfo(song: PlaylistSong); + export function spawnSongAdd(playlist: Playlist, callback_add: (url: string, loader: string) => any); + export function spawnPlaylistEdit(client: ConnectionHandler, playlist: Playlist); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts */ +declare namespace Modals { + export function spawnPlaylistManage(client: ConnectionHandler); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPoke.ts */ +declare namespace Modals { + export class PokeModal { + private _handle: Modal; + private source_map: ServerEntry[]; + constructor(); + modal(); + add_poke(source: ConnectionHandler, invoker: PokeInvoker, message: string); + private _handle_close(); + } + export type PokeInvoker = { + name: string; + id: number; + unique_id: string; + }; + export function spawnPoke(source: ConnectionHandler, invoker: PokeInvoker, message: string); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts */ +declare namespace Modals { + export function spawnQueryCreate(connection: ConnectionHandler, callback_created?: (user, pass) => any); + export function spawnQueryCreated(credentials: { + username: string; + password: string; + }, just_created: boolean); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts */ +declare namespace Modals { + export function spawnQueryManage(client: ConnectionHandler); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalServerEdit.ts */ +declare namespace Modals { + export function createServerModal(server: ServerEntry, callback: (properties?: ServerProperties) => Promise); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalServerInfo.ts */ +declare namespace Modals { + export function openServerInfo(server: ServerEntry); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts */ +declare namespace Modals { + export function spawnSettingsModal(default_page?: string): Modal; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalYesNo.ts */ +declare namespace Modals { + export function spawnYesNo(header: BodyCreator, body: BodyCreator, callback: (_: boolean) => any, properties?: { + text_yes?: string; + text_no?: string; + }); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/permission/CanvasPermissionEditor.ts */ +declare namespace pe { + namespace ui { + export namespace scheme { + export interface CheckBox { + border: string; + checkmark: string; + checkmark_font: string; + background_checked: string; + background_checked_hovered: string; + background: string; + background_hovered: string; + } + export interface TextField { + color: string; + font: string; + background: string; + background_hovered: string; + } + export interface ColorScheme { + permission: { + background: string; + background_selected: string; + name: string; + name_unset: string; + name_font: string; + value: TextField; + value_b: CheckBox; + granted: TextField; + negate: CheckBox; + skip: CheckBox; + }; + group: { + name: string; + name_font: string; + }; + } + } + export enum RepaintMode { + NONE, + REPAINT, + REPAINT_OBJECT_FULL, + REPAINT_FULL + } + export interface AxisAlignedBoundingBox { + x: number; + y: number; + width: number; + height: number; + } + export enum ClickEventType { + SIGNLE, + DOUBLE, + CONTEXT_MENU + } + export interface InteractionClickEvent { + type: ClickEventType; + consumed: boolean; + offset_x: number; + offset_y: number; + } + export interface InteractionListener { + region: AxisAlignedBoundingBox; + region_weight: number; + /** + * @return true if a redraw is required + */ + on_mouse_enter?: () => RepaintMode; + /** + * @return true if a redraw is required + */ + on_mouse_leave?: () => RepaintMode; + /** + * @return true if a redraw is required + */ + on_click?: (event: InteractionClickEvent) => RepaintMode; + mouse_cursor?: string; + set_full_draw?: () => any; + disabled?: boolean; + } + export abstract class DrawableObject { + abstract draw(context: CanvasRenderingContext2D, full: boolean); + private _object_full_draw; + private _width: number; + set_width(value: number); + request_full_draw(); + pop_full_draw(); + width(); + abstract height(); + private _transforms: DOMMatrix[]; + protected push_transform(context: CanvasRenderingContext2D); + protected pop_transform(context: CanvasRenderingContext2D); + protected original_x(context: CanvasRenderingContext2D, x: number); + protected original_y(context: CanvasRenderingContext2D, y: number); + protected colors: scheme.ColorScheme; + set_color_scheme(scheme: scheme.ColorScheme); + protected manager: PermissionEditor; + set_manager(manager: PermissionEditor); + abstract initialize(); + abstract finalize(); + } + export class PermissionGroup extends DrawableObject { + public static readonly HEIGHT; + public static readonly ARROW_SIZE; + group: GroupedPermissions; + _sub_elements: PermissionGroup[]; + _element_permissions: PermissionList; + collapsed; + private _listener_colaps: InteractionListener; + constructor(group: GroupedPermissions); + draw(context: CanvasRenderingContext2D, full: boolean); + set_width(value: number); + set_color_scheme(scheme: scheme.ColorScheme); + set_manager(manager: PermissionEditor); + height(); + initialize(); + finalize(); + collapse_group(); + expend_group(); + } + export class PermissionList extends DrawableObject { + permissions: PermissionEntry[]; + constructor(permissions: PermissionInfo[]); + set_width(value: number); + draw(context: CanvasRenderingContext2D, full: boolean); + height(); + set_color_scheme(scheme: scheme.ColorScheme); + set_manager(manager: PermissionEditor); + initialize(); + finalize(); + handle_hide(); + } + export class PermissionEntry extends DrawableObject { + public static readonly HEIGHT; + public static readonly HALF_HEIGHT; + public static readonly CHECKBOX_HEIGHT; + public static readonly COLUMN_PADDING; + public static readonly COLUMN_VALUE; + public static readonly COLUMN_GRANTED; + //public static readonly COLUMN_NEGATE = 25; + //public static readonly COLUMN_SKIP = 25; + public static readonly COLUMN_NEGATE; + public static readonly COLUMN_SKIP; + private _permission: PermissionInfo; + hidden: boolean; + granted: number; + value: number; + flag_skip: boolean; + flag_negate: boolean; + private _prev_selected; + selected: boolean; + flag_skip_hovered; + flag_negate_hovered; + flag_value_hovered; + flag_grant_hovered; + private _listener_checkbox_skip: InteractionListener; + private _listener_checkbox_negate: InteractionListener; + private _listener_value: InteractionListener; + private _listener_grant: InteractionListener; + private _listener_general: InteractionListener; + private _icon_image: HTMLImageElement | undefined; + on_icon_select?: (current_id: number) => Promise; + on_context_menu?: (x: number, y: number) => any; + on_grant_change?: () => any; + on_change?: () => any; + constructor(permission: PermissionInfo); + set_icon_id_image(image: HTMLImageElement | undefined); + permission(); + draw(ctx: CanvasRenderingContext2D, full: boolean); + handle_hide(); + private _draw_icon_field(ctx: CanvasRenderingContext2D, scheme: scheme.CheckBox, x: number, y: number, width: number, hovered: boolean, image: HTMLImageElement); + private _draw_number_field(ctx: CanvasRenderingContext2D, scheme: scheme.TextField, x: number, y: number, width: number, value: number, hovered: boolean); + private _draw_checkbox_field(ctx: CanvasRenderingContext2D, scheme: scheme.CheckBox, x: number, y: number, height: number, checked: boolean, hovered: boolean); + height(); + set_width(value: number); + initialize(); + finalize(); + private _spawn_number_edit(x: number, y: number, width: number, height: number, color: scheme.TextField, value: number, callback: (new_value?: number) => any); + trigger_value_assign(); + trigger_grant_assign(); + } + export class InteractionManager { + private _listeners: InteractionListener[]; + private _entered_listeners: InteractionListener[]; + register_listener(listener: InteractionListener); + remove_listener(listener: InteractionListener); + process_mouse_move(new_x: number, new_y: number): { + repaint: RepaintMode; + cursor: string; + }; + private process_click_event(x: number, y: number, event: InteractionClickEvent): RepaintMode; + process_click(x: number, y: number): RepaintMode; + process_dblclick(x: number, y: number): RepaintMode; + process_context_menu(js_event: MouseEvent, x: number, y: number): RepaintMode; + } + export class PermissionEditor { + private static readonly PERMISSION_HEIGHT; + private static readonly PERMISSION_GROUP_HEIGHT; + readonly grouped_permissions: GroupedPermissions[]; + readonly canvas: HTMLCanvasElement; + readonly canvas_container: HTMLDivElement; + private _max_height: number; + private _permission_count: number; + private _permission_group_count: number; + private _canvas_context: CanvasRenderingContext2D; + private _selected_entry: PermissionEntry; + private _draw_requested: boolean; + private _draw_requested_full: boolean; + private _elements: PermissionGroup[]; + private _intersect_manager: InteractionManager; + private _permission_entry_map: { + [key: number]: PermissionEntry; + }; + mouse: { + x: number; + y: number; + }; + constructor(permissions: GroupedPermissions[]); + private _handle_repaint(mode: RepaintMode); + request_draw(full?: boolean); + draw(full?: boolean); + private initialize(); + intercept_manager(); + set_selected_entry(entry?: PermissionEntry); + permission_entries(): PermissionEntry[]; + collapse_all(); + expend_all(); + } + } + export class CanvasPermissionEditor extends Modals.AbstractPermissionEditor { + private container: JQuery; + private mode_container_permissions: JQuery; + private mode_container_error_permission: JQuery; + private mode_container_unset: JQuery; + /* references within the container tag */ + private permission_value_map: { + [key: number]: PermissionValue; + }; + private entry_editor: ui.PermissionEditor; + icon_resolver: (id: number) => Promise; + icon_selector: (current_id: number) => Promise; + constructor(); + initialize(permissions: GroupedPermissions[]); + html_tag(); + private build_tag(); + set_permissions(permissions?: PermissionValue[]); + set_mode(mode: Modals.PermissionEditorMode); + update_ui(); + set_toggle_button(callback: () => string, initial: string); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/permission/HTMLPermissionEditor.ts */ +declare namespace pe { + export class HTMLPermission { + readonly handle: HTMLPermissionEditor; + readonly group: HTMLPermissionGroup; + readonly permission: PermissionInfo; + readonly index: number; + tag: JQuery; + tag_name: JQuery; + tag_container_value: JQuery; + tag_container_granted: JQuery; + tag_container_skip: JQuery; + tag_container_negate: JQuery; + hidden: boolean; + /* the "actual" values */ + private _mask; + private _tag_value: JQuery; + private _tag_value_input: JQuery; + private _tag_granted: JQuery; + private _tag_granted_input: JQuery; + private _tag_skip: JQuery; + private _tag_skip_input: JQuery; + private _tag_negate: JQuery; + private _tag_negate_input: JQuery; + private _value: number | undefined; + private _grant: number | undefined; + private flags: number; + constructor(handle: HTMLPermissionEditor, group: HTMLPermissionGroup, permission: PermissionInfo, index: number); + private static build_checkbox(): { + tag: JQuery; + input: JQuery; + }; + private static number_filter_re; + private static number_filter; + private build_tag(); + private _trigger_value_assign(); + private _trigger_grant_assign(); + hide(); + show(); + is_filtered(): boolean; + set_filtered(flag: boolean); + is_set(): boolean; + value(value: number | undefined, skip?: boolean, negate?: boolean); + granted(value: number | undefined); + reset(); + private _reset_value(); + private _reset_grant(); + private _update_active_class(); + } + export class HTMLPermissionGroup { + readonly handle: HTMLPermissionEditor; + readonly group: PermissionGroup; + readonly index: number; + private _tag_arrow: JQuery; + permissions: HTMLPermission[]; + children: HTMLPermissionGroup[]; + tag: JQuery; + visible: boolean; + collapsed: boolean; + parent_collapsed: boolean; + constructor(handle: HTMLPermissionEditor, group: PermissionGroup, index: number); + private _build_tag(); + update_visibility(); + collapse(); + expend(); + } + export class HTMLPermissionEditor extends Modals.AbstractPermissionEditor { + container: JQuery; + private mode_container_permissions: JQuery; + private mode_container_error_permission: JQuery; + private mode_container_unset: JQuery; + private filter_input: JQuery; + private filter_grant: JQuery; + private button_toggle: JQuery; + private even_list: ({ + visible(): boolean; + set_even(flag: boolean); + })[]; + private permission_map: Array; + private permission_groups: HTMLPermissionGroup[]; + constructor(); + initialize(permissions: GroupedPermissions[]); + private update_filter(); + private build_tag(); + html_tag(): JQuery; + set_permissions(u_permissions?: PermissionValue[]); + set_mode(mode: Modals.PermissionEditorMode); + trigger_change(permission: PermissionInfo, value?: Modals.PermissionEditor.PermissionValue): Promise; + collapse_all(); + expend_all(); + update_view(); + set_toggle_button(callback: () => string, initial: string); + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/permission/ModalPermissionEdit.ts */ +declare interface JQuery { + dropdown: any; +} +declare namespace Modals { + export namespace PermissionEditor { + export interface PermissionEntry { + tag: JQuery; + tag_value: JQuery; + tag_grant: JQuery; + tag_flag_negate: JQuery; + tag_flag_skip: JQuery; + id: number; + filter: string; + is_bool: boolean; + } + export interface PermissionValue { + remove: boolean; + granted?: number; + value?: number; + flag_skip?: boolean; + flag_negate?: boolean; + } + export type change_listener_t = (permission: PermissionInfo, value?: PermissionEditor.PermissionValue) => Promise; + } + export enum PermissionEditorMode { + VISIBLE, + NO_PERMISSION, + UNSET + } + export abstract class AbstractPermissionEditor { + protected _permissions: GroupedPermissions[]; + protected _listener_update: () => any; + protected _listener_change: PermissionEditor.change_listener_t; + protected _toggle_callback: () => string; + icon_resolver: (id: number) => Promise; + icon_selector: (current_id: number) => Promise; + protected constructor(); + abstract set_mode(mode: PermissionEditorMode); + abstract initialize(permissions: GroupedPermissions[]); + abstract html_tag(): JQuery; + abstract set_permissions(permissions?: PermissionValue[]); + set_listener(listener?: PermissionEditor.change_listener_t); + set_listener_update(listener?: () => any); + trigger_update(); + abstract set_toggle_button(callback: () => string, initial: string); + } + export type OptionsServerGroup = {}; + export type OptionsChannelGroup = {}; + export type OptionsClientPermissions = { + unique_id?: string; + }; + export type OptionsChannelPermissions = { + channel_id?: number; + }; + export type OptionsClientChannelPermissions = OptionsClientPermissions & OptionsChannelPermissions; + export interface OptionMap { + "sg": OptionsServerGroup; + "cg": OptionsChannelGroup; + "clp": OptionsClientPermissions; + "chp": OptionsChannelPermissions; + "clchp": OptionsClientChannelPermissions; + } + export function _space(); + export function spawnPermissionEdit(connection: ConnectionHandler, selected_tab?: T, options?: OptionMap[T]): Modal; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/server.ts */ +declare class ServerProperties { + virtualserver_host: string; + virtualserver_port: number; + virtualserver_name: string; + virtualserver_name_phonetic: string; + virtualserver_icon_id: number; + virtualserver_version: string; + virtualserver_platform: string; + virtualserver_unique_identifier: string; + virtualserver_clientsonline: number; + virtualserver_queryclientsonline: number; + virtualserver_channelsonline: number; + virtualserver_uptime: number; + virtualserver_created: number; + virtualserver_maxclients: number; + virtualserver_reserved_slots: number; + virtualserver_password: string; + virtualserver_flag_password: boolean; + virtualserver_ask_for_privilegekey: boolean; + virtualserver_welcomemessage: string; + virtualserver_hostmessage: string; + virtualserver_hostmessage_mode: number; + virtualserver_hostbanner_url: string; + virtualserver_hostbanner_gfx_url: string; + virtualserver_hostbanner_gfx_interval: number; + virtualserver_hostbanner_mode: number; + virtualserver_hostbutton_tooltip: string; + virtualserver_hostbutton_url: string; + virtualserver_hostbutton_gfx_url: string; + virtualserver_codec_encryption_mode: number; + virtualserver_default_music_group: number; + virtualserver_default_server_group: number; + virtualserver_default_channel_group: number; + virtualserver_default_channel_admin_group: number; + //Special requested properties + virtualserver_default_client_description: string; + virtualserver_default_channel_description: string; + virtualserver_default_channel_topic: string; + virtualserver_antiflood_points_tick_reduce: number; + virtualserver_antiflood_points_needed_command_block: number; + virtualserver_antiflood_points_needed_ip_block: number; + virtualserver_country_code: string; + virtualserver_complain_autoban_count: number; + virtualserver_complain_autoban_time: number; + virtualserver_complain_remove_time: number; + virtualserver_needed_identity_security_level: number; + virtualserver_weblist_enabled: boolean; + virtualserver_min_clients_in_channel_before_forced_silence: number; + virtualserver_channel_temp_delete_delay_default: number; + virtualserver_priority_speaker_dimm_modificator: number; + virtualserver_max_upload_total_bandwidth: number; + virtualserver_upload_quota: number; + virtualserver_max_download_total_bandwidth: number; + virtualserver_download_quota: number; + virtualserver_month_bytes_downloaded: number; + virtualserver_month_bytes_uploaded: number; + virtualserver_total_bytes_downloaded: number; + virtualserver_total_bytes_uploaded: number; +} +declare interface ServerConnectionInfo { + connection_filetransfer_bandwidth_sent: number; + connection_filetransfer_bandwidth_received: number; + connection_filetransfer_bytes_sent_total: number; + connection_filetransfer_bytes_received_total: number; + connection_filetransfer_bytes_sent_month: number; + connection_filetransfer_bytes_received_month: number; + connection_packets_sent_total: number; + connection_bytes_sent_total: number; + connection_packets_received_total: number; + connection_bytes_received_total: number; + connection_bandwidth_sent_last_second_total: number; + connection_bandwidth_sent_last_minute_total: number; + connection_bandwidth_received_last_second_total: number; + connection_bandwidth_received_last_minute_total: number; + connection_connected_time: number; + connection_packetloss_total: number; + connection_ping: number; +} +declare interface ServerAddress { + host: string; + port: number; +} +declare class ServerEntry { + remote_address: ServerAddress; + channelTree: ChannelTree; + properties: ServerProperties; + private info_request_promise: Promise; + private info_request_promise_resolve: any; + private info_request_promise_reject: any; + private _info_connection_promise: Promise; + private _info_connection_promise_timestamp: number; + private _info_connection_promise_resolve: any; + private _info_connection_promise_reject: any; + lastInfoRequest: number; + nextInfoRequest: number; + private _htmlTag: JQuery; + private _destroyed; + constructor(tree, name, address: ServerAddress); + // @ts-ignore + get htmlTag(); + destroy(); + initializeListener(); + spawnContextMenu(x: number, y: number, on_close?: () => void); + updateVariables(is_self_notify: boolean, ...variables: { + key: string; + value: string; + }[]); + /* this result !must! be cached for at least a second */ + updateProperties(): Promise; + /* max 1s ago, so we could update every second */ + request_connection_info(): Promise; + set_connection_info(info: ServerConnectionInfo); + shouldUpdateProperties(): boolean; + calculateUptime(): number; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/view.ts */ +declare class ChannelTree { + client: ConnectionHandler; + server: ServerEntry; + channels: ChannelEntry[]; + clients: ClientEntry[]; + currently_selected: ClientEntry | ServerEntry | ChannelEntry | (ClientEntry | ServerEntry)[]; + currently_selected_context_callback: (event) => any; + readonly client_mover: ClientMover; + private _tag_container: JQuery; + private _tag_entries: JQuery; + private _tree_detached: boolean; + private _show_queries: boolean; + private channel_last?: ChannelEntry; + private channel_first?: ChannelEntry; + private _focused; + private _listener_document_click; + private _listener_document_key; + constructor(client); + tag_tree(): JQuery; + destroy(); + hide_channel_tree(); + show_channel_tree(); + showContextMenu(x: number, y: number, on_close?: () => void); + initialiseHead(serverName: string, address: ServerAddress); + private __deleteAnimation(element: ChannelEntry | ClientEntry); + rootChannel(): ChannelEntry[]; + deleteChannel(channel: ChannelEntry); + insertChannel(channel: ChannelEntry); + findChannel(channelId: number): ChannelEntry | undefined; + find_channel_by_name(name: string, parent?: ChannelEntry, force_parent?: boolean): ChannelEntry | undefined; + moveChannel(channel: ChannelEntry, channel_previous: ChannelEntry, parent: ChannelEntry); + deleteClient(client: ClientEntry, animate_tag?: boolean); + registerClient(client: ClientEntry); + unregisterClient(client: ClientEntry); + insertClient(client: ClientEntry, channel: ChannelEntry): ClientEntry; + moveClient(client: ClientEntry, channel: ChannelEntry); + findClient?(clientId: number): ClientEntry; + find_client_by_dbid?(client_dbid: number): ClientEntry; + find_client_by_unique_id?(unique_id: string): ClientEntry; + private static same_selected_type(a, b); + onSelect(entry?: ChannelEntry | ClientEntry | ServerEntry, enforce_single?: boolean, flag_shift?: boolean); + private callback_multiselect_channel(event); + private callback_multiselect_client(event); + clientsByGroup(group: Group): ClientEntry[]; + clientsByChannel(channel: ChannelEntry): ClientEntry[]; + reset(); + spawnCreateChannel(parent?: ChannelEntry); + handle_resized(); + private select_next_channel(channel: ChannelEntry, select_client: boolean); + handle_key_press(event: KeyboardEvent); + toggle_server_queries(flag: boolean); + get_first_channel?(): ChannelEntry; + unsubscribe_all_channels(subscribe_specified?: boolean); + subscribe_all_channels(); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/utils/helpers.ts */ +declare namespace helpers { + export function hashPassword(password: string): Promise; +} +declare class LaterPromise extends Promise { + private _handle: Promise; + private _resolve: ($: T) => any; + private _reject: ($: any) => any; + private _time: number; + constructor(); + resolved(object: T); + rejected(reason); + function_rejected(); + time(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; +} +declare const copy_to_clipboard; + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/voice/RecorderBase.ts */ +declare namespace audio { + export namespace recorder { + export interface InputDevice { + unique_id: string; + driver: string; + name: string; + default_input: boolean; + supported: boolean; + sample_rate: number; + channels: number; + } + export enum InputConsumerType { + CALLBACK, + NODE, + NATIVE + } + export interface InputConsumer { + type: InputConsumerType; + } + export interface CallbackInputConsumer extends InputConsumer { + callback_audio?: (buffer: AudioBuffer) => any; + callback_buffer?: (buffer: Float32Array, samples: number, channels: number) => any; + } + export interface NodeInputConsumer extends InputConsumer { + callback_node: (source_node: AudioNode) => any; + callback_disconnect: (source_node: AudioNode) => any; + } + export namespace filter { + export enum Type { + THRESHOLD, + VOICE_LEVEL, + STATE + } + export interface Filter { + type: Type; + is_enabled(): boolean; + } + export interface MarginedFilter { + get_margin_frames(): number; + set_margin_frames(value: number); + } + export interface ThresholdFilter extends Filter, MarginedFilter { + get_threshold(): number; + set_threshold(value: number): Promise; + get_attack_smooth(): number; + get_release_smooth(): number; + set_attack_smooth(value: number); + set_release_smooth(value: number); + callback_level?: (value: number) => any; + } + export interface VoiceLevelFilter extends Filter, MarginedFilter { + get_level(): number; + } + export interface StateFilter extends Filter { + set_state(state: boolean): Promise; + is_active(): boolean; /* if true the the filter allows data to pass */ + } + } + export enum InputState { + PAUSED, + INITIALIZING, + RECORDING, + DRY + } + export enum InputStartResult { + EOK = "eok", + EUNKNOWN = "eunknown", + EBUSY = "ebusy", + ENOTALLOWED = "enotallowed", + ENOTSUPPORTED = "enotsupported" + } + export interface AbstractInput { + callback_begin: () => any; + callback_end: () => any; + current_state(): InputState; + start(): Promise; + stop(): Promise; + current_device(): InputDevice | undefined; + set_device(device: InputDevice | undefined): Promise; + current_consumer(): InputConsumer | undefined; + set_consumer(consumer: InputConsumer): Promise; + get_filter(type: filter.Type): filter.Filter | undefined; + supports_filter(type: audio.recorder.filter.Type): boolean; + clear_filter(); + disable_filter(type: filter.Type); + enable_filter(type: filter.Type); + get_volume(): number; + set_volume(volume: number); + } + export interface LevelMeter { + device(): InputDevice; + set_observer(callback: (value: number) => any); + destory(); + } + } +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/voice/RecorderProfile.ts */ +declare type VadType = "threshold" | "push_to_talk" | "active"; +declare interface RecorderProfileConfig { + version: number; + /* devices unique id */ + device_id: string | undefined; + volume: number; + vad_type: VadType; + vad_threshold: { + threshold: number; + }; + vad_push_to_talk: { + delay: number; + key_code: string; + key_ctrl: boolean; + key_windows: boolean; + key_shift: boolean; + key_alt: boolean; + }; +} +declare let default_recorder: RecorderProfile /* needs initialize */; +declare class RecorderProfile { + readonly name; + readonly volatile; + config: RecorderProfileConfig; + input: audio.recorder.AbstractInput; + current_handler: ConnectionHandler; + callback_support_change: () => any; + callback_start: () => any; + callback_stop: () => any; + callback_unmount: () => any; + record_supported: boolean; + private _ppt_hook: ppt.KeyHook; + private _ppt_timeout: NodeJS.Timer; + private _ppt_hook_registered: boolean; + constructor(name: string, volatile?: boolean); + initialize(): Promise; + private initialize_input(); + private load(); + private save(enforce?: boolean); + private reinitialize_filter(); + unmount(): Promise; + get_vad_type(); + set_vad_type(type: VadType); + get_vad_threshold(); + set_vad_threshold(value: number); + get_vad_ppt_key(): ppt.KeyDescriptor; + set_vad_ppt_key(key: ppt.KeyDescriptor); + get_vad_ppt_delay(); + set_vad_ppt_delay(value: number); + current_device(): audio.recorder.InputDevice | undefined; + set_device(device: audio.recorder.InputDevice | undefined): Promise; + get_volume(): number; + set_volume(volume: number); +} diff --git a/modules/renderer/imports/.copy_imports_shared_loader.d.ts b/modules/renderer/imports/.copy_imports_shared_loader.d.ts new file mode 100644 index 0000000..80b4757 --- /dev/null +++ b/modules/renderer/imports/.copy_imports_shared_loader.d.ts @@ -0,0 +1,97 @@ + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/loader/loader.ts */ +declare interface Window { + tr(message: string): string; +} +declare namespace loader { + export namespace config { + export const loader_groups; + export const verbose; + export const error; + } + export type Task = { + name: string; + priority: number; /* tasks with the same priority will be executed in sync */ + function: () => Promise; + }; + export enum Stage { + /* + loading loader required files (incl this) + */ + INITIALIZING, + /* + setting up the loading process + */ + SETUP, + /* + loading all style sheet files + */ + STYLE, + /* + loading all javascript files + */ + JAVASCRIPT, + /* + loading all template files + */ + TEMPLATES, + /* + initializing static/global stuff + */ + JAVASCRIPT_INITIALIZING, + /* + finalizing load process + */ + FINALIZING, + /* + invoking main task + */ + LOADED, + DONE + } + export function get_cache_version(); + export function finished(); + export function running(); + export function register_task(stage: Stage, task: Task); + export function execute(): Promise; + export function execute_managed(); + export type DependSource = { + url: string; + depends: string[]; + }; + export type SourcePath = string | DependSource | string[]; + export class SyntaxError { + source: any; + constructor(source: any); + } + export function load_script(path: SourcePath): Promise; + export function load_scripts(paths: SourcePath[]): Promise; + export function load_style(path: SourcePath): Promise; + export function load_styles(paths: SourcePath[]): Promise; + export type ErrorHandler = (message: string, detail: string) => void; + export function critical_error(message: string, detail?: string); + export function critical_error_handler(handler?: ErrorHandler, override?: boolean): ErrorHandler; +} +declare let _fadeout_warned; +declare function fadeoutLoader(duration?, minAge?, ignoreAge?); + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/loader/app.ts */ +declare interface Window { + $: JQuery; +} +declare namespace app { + export enum Type { + UNKNOWN, + CLIENT_RELEASE, + CLIENT_DEBUG, + WEB_DEBUG, + WEB_RELEASE + } + export let type: Type; + export function is_web(); + export function ui_version(); +} +declare const loader_javascript; +declare const loader_webassembly; +declare const loader_style; +declare function load_templates(): Promise; diff --git a/modules/renderer/imports/.gitignore b/modules/renderer/imports/.gitignore new file mode 100644 index 0000000..303120f --- /dev/null +++ b/modules/renderer/imports/.gitignore @@ -0,0 +1,2 @@ +imports_shared.d.ts +imports_shared_loader.d.ts \ No newline at end of file diff --git a/modules/renderer/index.ts b/modules/renderer/index.ts new file mode 100644 index 0000000..4c174bd --- /dev/null +++ b/modules/renderer/index.ts @@ -0,0 +1,259 @@ +/// + +import {Arguments, process_args, parse_arguments} from "../shared/process-arguments"; +import {remote} from "electron"; +import * as crash_handler from "../crash_handler"; +import * as electron from "electron"; +import * as path from "path"; +import * as os from "os"; + +/* first of all setup crash handler */ +{ + const is_electron_run = process.argv[0].endsWith("electron") || process.argv[0].endsWith("electron.exe"); + crash_handler.initialize_handler("renderer", is_electron_run); +} + +interface Window { + $: any; + jQuery: any; + jsrender: any; + + impl_display_critical_error: any; + displayCriticalError: any; + teaclient_initialize: any; + + open_connected_question: () => Promise; +} + +declare const window: Window; + +export const require_native: NodeRequireFunction = id => require(id); +export const initialize = async () => { + /* we use out own jquery resource */ + loader.register_task(loader.Stage.JAVASCRIPT, { + name: "teaclient jquery", + function: jquery_initialize, + priority: 80 + }); + + loader.register_task(loader.Stage.JAVASCRIPT, { + name: "teaclient general", + function: load_basic_modules, + priority: 10 + }); + + loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, { + name: "teaclient javascript init", + function: load_modules, + priority: 50 + }); + + loader.register_task(loader.Stage.INITIALIZING, { + name: "teaclient initialize modules", + function: module_loader_setup, + priority: 60 + }); + + loader.register_task(loader.Stage.INITIALIZING, { + name: "teaclient initialize persistent storage", + function: async () => { + const storage = require("./PersistentLocalStorage"); + await storage.initialize(); + }, + priority: 90 + }); + + loader.register_task(loader.Stage.INITIALIZING, { + name: "teaclient initialize logging", + function: initialize_logging, + priority: 80 + }); + + loader.register_task(loader.Stage.INITIALIZING, { + name: "teaclient initialize error", + function: initialize_error_handler, + priority: 100 + }); + + loader.register_task(loader.Stage.INITIALIZING, { + name: "teaclient initialize arguments", + function: async () => { + parse_arguments(); + if(process_args.has_value(Arguments.DUMMY_CRASH_RENDERER)) + crash_handler.handler.crash(); + if(!process_args.has_flag(Arguments.DEBUG)) { + window.open_connected_question = () => remote.dialog.showMessageBox(remote.getCurrentWindow(), { + type: 'question', + buttons: ['Yes', 'No'], + title: 'Confirm', + message: 'Are you really sure?\nYou\'re still connected!' + }).then(result => result.response === 0); + } + }, + priority: 110 + }); + + loader.register_task(loader.Stage.INITIALIZING, { + name: 'gdb-waiter', + function: async () => { + if(process_args.has_flag(Arguments.DEV_TOOLS_GDB)) { + console.log("Process ID: %d", process.pid); + await new Promise(resolve => { + console.log("Waiting for continue!"); + + const listener = () => { + console.log("Continue"); + document.removeEventListener('click', listener); + resolve(); + }; + document.addEventListener('click', listener); + }); + } + }, + priority: 100 + }); +}; + +const jquery_initialize = async () => { + window.$ = require("jquery"); + window.jQuery = window.$; + Object.assign(window.$, window.jsrender = require('jsrender')); +}; + +const initialize_logging = async () => { + const logger = require("./logger"); + logger.setup(); +}; + +const initialize_error_handler = async () => { + const _impl = message => { + if(!process_args.has_flag(Arguments.DEBUG)) { + console.error("Displaying critical error: %o", message); + message = message.replace(/
    /i, "\n"); + + const win = remote.getCurrentWindow(); + remote.dialog.showMessageBox({ + type: "error", + buttons: ["exit"], + title: "A critical error happened!", + message: message + }); + + win.close(); + } else { + console.error("Received critical error: %o", message); + console.error("Ignoring error due to the debug mode"); + } + }; + + if(window.impl_display_critical_error) + window.impl_display_critical_error = _impl; + else + window.displayCriticalError = _impl; +}; + +const module_loader_setup = async () => { + const native_paths = (() => { + const app_path = (remote || electron).app.getAppPath(); + const result = []; + result.push(app_path + "/native/build/" + os.platform() + "_" + os.arch() + "/"); + if(app_path.endsWith(".asar")) + result.push(path.join(path.dirname(app_path), "natives")); + return result; + })(); + window["require_setup"] = _mod => { + if(!_mod || !_mod.paths) return; + + _mod.paths.push(...native_paths); + const original_require = _mod.__proto__.require; + if(!_mod.proxied) { + _mod.require = (path: string) => { + if(path.endsWith("imports/imports_shared")) { + console.log("Proxy require for %s. Using 'window' as result.", path); + return window; + } + return original_require.apply(_mod, [path]); + }; + _mod.proxied = true; + } + }; +}; + +const load_basic_modules = async () => { + console.dir(require("./audio/AudioPlayer")); /* setup audio */ + console.dir(require("./audio/AudioRecorder")); /* setup audio */ + require("./logger"); + + +}; + +const load_modules = async () => { + window["require_setup"](this); + + console.log(module.paths); + console.log("Loading native extensions..."); + try { + try { + require("./version"); + } catch(error) { + console.error("Failed to load version extension"); + console.dir(error); + throw error; + } + try { + const helper = require("./icon-helper"); + await helper.initialize(); + } catch(error) { + console.error("Failed to load the icon helper extension"); + console.dir(error); + throw error; + } + try { + require("./ppt"); + } catch(error) { + console.error("Failed to load ppt"); + console.dir(error); + throw error; + } + try { + require("./connection/ServerConnection"); + } catch(error) { + console.error("Failed to load server connection extension"); + console.dir(error); + throw error; + } + try { + require("./connection/FileTransfer"); + } catch(error) { + console.error("Failed to load file transfer extension"); + console.dir(error); + throw error; + } + try { + require("./dns/dns_resolver"); + } catch(error) { + console.error("Failed to load dns extension"); + console.dir(error); + throw error; + } + try { + require("./menu"); + } catch(error) { + console.error("Failed to load menu extension"); + console.dir(error); + throw error; + } + try { + require("./context-menu"); + } catch(error) { + console.error("Failed to load context menu extension"); + console.dir(error); + throw error; + } + } catch(error){ + console.log(error); + window.displayCriticalError("Failed to load native extensions: " + error); + throw error; + } + console.log("Loaded native extensions"); +}; \ No newline at end of file diff --git a/modules/renderer/logger.ts b/modules/renderer/logger.ts new file mode 100644 index 0000000..eb66505 --- /dev/null +++ b/modules/renderer/logger.ts @@ -0,0 +1,79 @@ +enum LogType { + TRACE, + DEBUG, + INFO, + WARNING, + ERROR +} + +export interface Logger { + trace(message: string, ...args); + debug(message: string, ...args); + info(message: string, ...args); + log(message: string, ...args); + warning(message: string, ...args); + error(message: string, ...args); + + dir_error(error: any, message?: string); +} + +let loggers = {}; +const original_console: Console = {} as any; + +export function setup() { + Object.assign(original_console, console); + Object.assign(console, logger("console")); +} + +export function logger(name: string = "console") : Logger { + if(loggers[name]) + return loggers[name]; + + return loggers[name] = create_logger(name); +} + +import * as util from "util"; +function create_logger(name: string) : Logger { + const log = (type, message: string, ...args) => { + switch (type) { + case LogType.TRACE: + original_console.trace(message, ...args); + break; + case LogType.DEBUG: + original_console.debug(message, ...args); + break; + case LogType.INFO: + original_console.info(message, ...args); + break; + case LogType.WARNING: + original_console.warn(message, ...args); + break; + case LogType.ERROR: + original_console.error(message, ...args); + break; + } + + const log_message = util.format(message, ...args); + process.stdout.write(util.format("[%s][%s] %s", name, LogType[type], log_message) + "\n"); + }; + + return { + trace: (m, ...a) => log(LogType.TRACE, m, ...a), + debug: (m, ...a) => log(LogType.DEBUG, m, ...a), + info: (m, ...a) => log(LogType.INFO, m, ...a), + log: (m, ...a) => log(LogType.INFO, m, ...a), + warning: (m, ...a) => log(LogType.WARNING, m, ...a), + error: (m, ...a) => log(LogType.ERROR, m, ...a), + + dir_error: (e, m) => { + log(LogType.ERROR, "Caught exception: " + m); + log(LogType.ERROR, e); + } + }; +} + +(window as any).logger = { + log: function (category, level, message) { + console.log("%d | %d | %s", category, level, message); + } +}; \ No newline at end of file diff --git a/modules/renderer/menu.ts b/modules/renderer/menu.ts new file mode 100644 index 0000000..8978727 --- /dev/null +++ b/modules/renderer/menu.ts @@ -0,0 +1,254 @@ +import {class_to_image} from "./icon-helper"; + +window["require_setup"](module); + +import * as electron from "electron"; +//import {top_menu as dtop_menu, Icon} from "./imports/imports_shared"; + +/// +import dtop_menu = top_menu; + +namespace _top_menu { + import ipcRenderer = electron.ipcRenderer; + namespace native { + import ipcRenderer = electron.ipcRenderer; + let _item_index = 1; + + abstract class NativeMenuBase { + protected _handle: NativeMenuBar; + protected _click: () => any; + id: string; + + protected constructor(handle: NativeMenuBar, id?: string) { + this._handle = handle; + this.id = id || ("item_" + (_item_index++)); + } + + abstract build() : electron.MenuItemConstructorOptions; + abstract items(): (dtop_menu.MenuItem | dtop_menu.HRItem)[]; + + trigger_click() { + if(this._click) + this._click(); + } + } + + class NativeMenuItem extends NativeMenuBase implements dtop_menu.MenuItem { + private _items: (NativeMenuItem | NativeHrItem)[] = []; + private _label: string; + private _enabled: boolean = true; + private _visible: boolean = true; + + private _icon_data: string; + + constructor(handle: NativeMenuBar) { + super(handle); + + } + + append_hr(): dtop_menu.HRItem { + const item = new NativeHrItem(this._handle); + this._items.push(item); + return item; + } + + append_item(label: string): dtop_menu.MenuItem { + const item = new NativeMenuItem(this._handle); + item.label(label); + this._items.push(item); + return item; + } + + click(callback: () => any): this { + this._click = callback; + return this; + } + + delete_item(item: dtop_menu.MenuItem | dtop_menu.HRItem) { + const i_index = this._items.indexOf(item as any); + if(i_index < 0) return; + this._items.splice(i_index, 1); + } + + disabled(value?: boolean): boolean { + if(typeof(value) === "boolean") + this._enabled = !value; + return !this._enabled; + } + + icon(klass?: string | Promise | Icon): string { + if(typeof(klass) === "string") { + const buffer = class_to_image(klass); + if(buffer) + this._icon_data = buffer.toDataURL(); + } + return ""; + } + + items(): (dtop_menu.MenuItem | dtop_menu.HRItem)[] { + return this._items; + } + + label(value?: string): string { + if(typeof(value) === "string") + this._label = value; + return this._label; + } + + visible(value?: boolean): boolean { + if(typeof(value) === "boolean") + this._visible = value; + return this._visible; + } + + build(): Electron.MenuItemConstructorOptions { + return { + id: this.id, + + label: this._label || "", + + submenu: this._items.length > 0 ? this._items.map(e => e.build()) : undefined, + enabled: this._enabled, + visible: this._visible, + + icon: this._icon_data + } + } + } + + class NativeHrItem extends NativeMenuBase implements dtop_menu.HRItem { + constructor(handle: NativeMenuBar) { + super(handle); + } + + build(): Electron.MenuItemConstructorOptions { + return { + type: 'separator', + id: this.id + } + } + + items(): (dtop_menu.MenuItem | dtop_menu.HRItem)[] { + return []; + } + } + + function is_similar_deep(a, b) { + if(typeof(a) !== typeof(b)) + return false; + if(typeof(a) !== "object") + return a === b; + + const aProps = Object.keys(a); + const bProps = Object.keys(b); + + if (aProps.length != bProps.length) + return false; + + for (let i = 0; i < aProps.length; i++) { + const propName = aProps[i]; + + if(!is_similar_deep(a[propName], b[propName])) + return false; + } + + return true; + } + + + export class NativeMenuBar implements dtop_menu.MenuBarDriver { + private static _instance: NativeMenuBar; + + private menu: electron.Menu; + private _items: NativeMenuItem[] = []; + private _current_menu: electron.MenuItemConstructorOptions[]; + + public static instance() : NativeMenuBar { + if(!this._instance) + this._instance = new NativeMenuBar(); + return this._instance; + } + + append_item(label: string): dtop_menu.MenuItem { + const item = new NativeMenuItem(this); + item.label(label); + this._items.push(item); + return item; + } + + delete_item(item: dtop_menu.MenuItem) { + const i_index = this._items.indexOf(item as any); + if(i_index < 0) return; + this._items.splice(i_index, 1); + } + + flush_changes() { + const target_menu = this.build_menu(); + if(is_similar_deep(target_menu, this._current_menu)) + return; + + this._current_menu = target_menu; + ipcRenderer.send('top-menu', target_menu); + } + + private build_menu() : electron.MenuItemConstructorOptions[] { + return this._items.map(e => e.build()); + } + + items(): dtop_menu.MenuItem[] { + return this._items; + } + + initialize() { + this.menu = new electron.remote.Menu(); + ipcRenderer.on('top-menu', (event, clicked_item) => { + console.log("Item %o clicked", clicked_item); + const check_item = (item: NativeMenuBase) => { + if(item.id == clicked_item) { + item.trigger_click(); + return true; + } + for(const child of item.items()) + if(check_item(child as NativeMenuBase)) + return true; + }; + + for(const item of this._items) + if(check_item(item)) + return; + }); + } + } + } + + //Global variable + // @ts-ignore + top_menu.set_driver(native.NativeMenuBar.instance()); + + + const call_basic_action = (name: string, ...args: any[]) => ipcRenderer.send('basic-action', name, ...args); + top_menu.native_actions = { + open_change_log() { + call_basic_action("open-changelog"); + }, + + check_native_update() { + call_basic_action("check-native-update"); + }, + + quit() { + call_basic_action("quit"); + }, + + open_dev_tools() { + call_basic_action("open-dev-tools"); + }, + + reload_page() { + call_basic_action("reload-window") + } + }; +} + + +export {}; \ No newline at end of file diff --git a/modules/renderer/ppt.ts b/modules/renderer/ppt.ts new file mode 100644 index 0000000..d3edd14 --- /dev/null +++ b/modules/renderer/ppt.ts @@ -0,0 +1,134 @@ +window["require_setup"](module); + +import {KeyEvent as NKeyEvent} from "teaclient_ppt"; +namespace _ppt { + let key_listener: ((_: ppt.KeyEvent) => any)[] = []; + + let native_ppt; + function listener_key(type: ppt.EventType, nevent: NKeyEvent) { + if(nevent.key_code === 'VoidSymbol' || nevent.key_code === 'error') + nevent.key_code = undefined; /* trigger event for state update */ + + let event: ppt.KeyEvent = { + type: type, + + key: nevent.key_code, + key_code: nevent.key_code, + + key_ctrl: nevent.key_ctrl, + key_shift: nevent.key_shift, + key_alt: nevent.key_alt, + key_windows: nevent.key_windows + } as any; + + //console.debug("Trigger key event %o", key_event); + + for (const listener of key_listener) + listener(event); + } + + function native_keyhook(event: NKeyEvent) { + //console.log("Native event!: %o", event); + + if(event.type == 0) + listener_key(ppt.EventType.KEY_PRESS, event); + else if(event.type == 1) + listener_key(ppt.EventType.KEY_RELEASE, event); + else if(event.type == 2) + listener_key(ppt.EventType.KEY_TYPED, event); + } + + export async function initialize() : Promise { + native_ppt = require("teaclient_ppt"); + + register_key_listener(listener_hook); + native_ppt.RegisterCallback(native_keyhook); + } + + export function finalize() { + unregister_key_listener(listener_hook); + native_ppt.UnregisterCallback(native_keyhook); + } + + export function register_key_listener(listener: (_: ppt.KeyEvent) => any) { + key_listener.push(listener); + } + + export function unregister_key_listener(listener: (_: ppt.KeyEvent) => any) { + key_listener.remove(listener); + } + + interface CurrentState { + event: ppt.KeyEvent; + code: string; + + special: { [key:number]:boolean }; + } + + let current_state: CurrentState = { + special: [] + } as any; + + let key_hooks: ppt.KeyHook[] = []; + let key_hooks_active: ppt.KeyHook[] = []; + + function listener_hook(event: ppt.KeyEvent) { + if(event.type == ppt.EventType.KEY_TYPED) + return; + + let old_hooks = [...key_hooks_active]; + let new_hooks = []; + + current_state.special[ppt.SpecialKey.ALT] = event.key_alt; + current_state.special[ppt.SpecialKey.CTRL] = event.key_ctrl; + current_state.special[ppt.SpecialKey.SHIFT] = event.key_shift; + current_state.special[ppt.SpecialKey.WINDOWS] = event.key_windows; + + current_state.code = undefined; + current_state.event = undefined; + + if(event.type == ppt.EventType.KEY_PRESS) { + current_state.event = event; + current_state.code = event.key_code; + + for(const hook of key_hooks) { + if(hook.key_code && hook.key_code != event.key_code) continue; + if(hook.key_alt != event.key_alt) continue; + if(hook.key_ctrl != event.key_ctrl) continue; + if(hook.key_shift != event.key_shift) continue; + if(hook.key_windows != event.key_windows) continue; + + new_hooks.push(hook); + if(!old_hooks.remove(hook) && hook.callback_press) { + hook.callback_press(); + console.debug("Trigger key press for %o!", hook); + } + } + } + + //We have a new situation + for(const hook of old_hooks) + if(hook.callback_release) { + hook.callback_release(); + console.debug("Trigger key release for %o!", hook); + } + key_hooks_active = new_hooks; + } + + export function register_key_hook(hook: ppt.KeyHook) { + key_hooks.push(hook); + } + + export function unregister_key_hook(hook: ppt.KeyHook) { + key_hooks.remove(hook); + key_hooks_active.remove(hook); + } + + export function key_pressed(code: string | ppt.SpecialKey) : boolean { + if(typeof(code) === 'string') + return current_state.code == code; + return current_state.special[code]; + } +} +Object.assign(window["ppt"] || (window["ppt"] = {} as any), _ppt); +console.dir(_ppt); \ No newline at end of file diff --git a/modules/renderer/version.ts b/modules/renderer/version.ts new file mode 100644 index 0000000..b720eee --- /dev/null +++ b/modules/renderer/version.ts @@ -0,0 +1,21 @@ +namespace native { + const remote = require('electron').remote; + export async function client_version() : Promise { + const version = remote.getGlobal("app_version_client"); + return version || "?.?.?"; + } +} + +window["native"] = native; + +namespace forum { + export interface UserData { + session_id: string; + username: string; + + application_data: string; + application_data_sign: string; + } +} + +//window["forum"] = forum; \ No newline at end of file diff --git a/modules/shared/process-arguments/index.ts b/modules/shared/process-arguments/index.ts new file mode 100644 index 0000000..2bc8e94 --- /dev/null +++ b/modules/shared/process-arguments/index.ts @@ -0,0 +1,99 @@ +import * as electron from "electron"; +import {app} from "electron"; + +export class Arguments { + static readonly DEV_TOOLS = ["t", "dev-tools"]; + static readonly DEV_TOOLS_GDB = ["gdb"]; + static readonly DEBUG = ["d", "debug"]; + static readonly DISABLE_ANIMATION = ["a", "disable-animation"]; + static readonly SERVER_URL = ["u", "server-url"]; + static readonly UPDATER_UI_DEBUG = ["updater-debug-ui"]; + static readonly UPDATER_ENFORCE = ["updater-enforce"]; + static readonly UPDATER_CHANNEL = ["updater-channel"]; + static readonly UPDATER_LOCAL_VERSION = ["updater-local-version"]; + static readonly UPDATER_UI_LOAD_TYPE = ["updater-ui-loader_type"]; + static readonly UPDATER_UI_NO_CACHE = ["updater-ui-no-cache"]; + static readonly DISABLE_HARDWARE_ACCELERATION = ["disable-hardware-acceleration"]; + static readonly NO_SINGLE_INSTANCE = ["no-single-instance"]; + static readonly DUMMY_CRASH_MAIN = ["dummy-crash-main"]; + static readonly DUMMY_CRASH_RENDERER = ["dummy-crash-renderer"]; + + has_flag: (...keys: (string | string[])[]) => boolean; + has_value: (...keys: (string | string[])[]) => boolean; + value: (...keys: (string | string[])[]) => string; +} + +export interface Window { + process_args: Arguments; +} + +export const process_args: Arguments = {} as Arguments; + +export function parse_arguments() { + if(!process || !process.type || process.type === 'renderer') { + Object.assign(process_args, electron.remote.getGlobal("process_arguments")); + (window as any).process_args = process_args; + } else { + const is_electron_run = process.argv[0].endsWith("electron") || process.argv[0].endsWith("electron.exe"); + + { + const minimist: (args, opts) => T = require("./minimist") as any; + let args = minimist(is_electron_run ? process.argv.slice(2) : process.argv.slice(1), { + boolean: true, + stopEarly: true + }) as Arguments; + args.has_flag = (...keys) => { + for(const key of [].concat(...Array.of(...keys).map(e => Array.isArray(e) ? Array.of(...e) : [e]))) + if(typeof process_args[key as any as string] === "boolean") + return process_args[key as any as string]; + return false; + }; + + args.value = (...keys) => { + for(const key of [].concat(...Array.of(...keys).map(e => Array.isArray(e) ? Array.of(...e) : [e]))) + if(typeof process_args[key] !== "undefined") + return process_args[key]; + return undefined; + }; + + args.has_value = (...keys) => { + return args.value(...keys) !== undefined; + }; + + if(args.has_flag(Arguments.DEBUG)) { + const _has_flag = args.has_flag; + args.has_flag = (...keys) => { + const result = _has_flag(...keys); + console.log("Process argument test for parameter %o results in %o", keys, result); + return result; + }; + + const _value = args.value; + args.value = (...keys) => { + const result = _value(...keys); + console.log("Process argument test for parameter %o results in %o", keys, result); + return result; + } + } + console.log("Parsed CMD arguments %o as %o", process.argv, args); + Object.assign(process_args, args); + Object.assign(global["process_arguments"] = {}, args); + } + + if(process_args.has_flag("help", "h")) { + console.log("TeaClient command line help page"); + console.log(" -h --help => Displays this page"); + console.log(" -d --debug => Enabled the application debug"); + console.log(" -t --dev-tools => Enables dev tools"); + console.log(" -u --server-url => Sets the remote client api server url"); + console.log(" --updater-channel => Set the updater channel"); + console.log(" -a --disable-animation => Disables some cosmetic animations and loadings"); + console.log(" --disable-hardware-acceleration => Disables the hardware acceleration for the UI"); + console.log(" --no-single-instance => Disable multi instance testing"); + + //is_debug = process_args.has_flag("debug", "d"); + //open_dev_tools = process_args.has_flag("dev-tools", "dt"); + app.exit(0); + } + } +} \ No newline at end of file diff --git a/modules/shared/process-arguments/minimist.ts b/modules/shared/process-arguments/minimist.ts new file mode 100644 index 0000000..7bdf35d --- /dev/null +++ b/modules/shared/process-arguments/minimist.ts @@ -0,0 +1,299 @@ +namespace minimist { + export interface Opts { + /** + * A string or array of strings argument names to always treat as strings + */ + string?: string | string[]; + + /** + * A boolean, string or array of strings to always treat as booleans. If true will treat + * all double hyphenated arguments without equals signs as boolean (e.g. affects `--foo`, not `-f` or `--foo=bar`) + */ + boolean?: boolean | string | string[]; + + /** + * An object mapping string names to strings or arrays of string argument names to use as aliases + */ + alias?: { [key: string]: string | string[] }; + + /** + * An object mapping string argument names to default values + */ + default?: { [key: string]: any }; + + /** + * When true, populate argv._ with everything after the first non-option + */ + stopEarly?: boolean; + + /** + * A function which is invoked with a command line parameter not defined in the opts + * configuration object. If the function returns false, the unknown option is not added to argv + */ + unknown?: (arg: string) => boolean; + + /** + * When true, populate argv._ with everything before the -- and argv['--'] with everything after the --. + * Note that with -- set, parsing for arguments still stops after the `--`. + */ + '--'?: boolean; + } + + export interface ParsedArgs { + [arg: string]: any; + + /** + * If opts['--'] is true, populated with everything after the -- + */ + '--'?: string[]; + + /** + * Contains all the arguments that didn't have an option associated with them + */ + _: string[]; + } +} + +const parse = (args: string[], options: minimist.Opts) => { + options = options || {}; + + var flags = { bools : {}, strings : {}, unknownFn: null, allBools: false }; + + if (typeof options['unknown'] === 'function') { + flags.unknownFn = options['unknown']; + } + + if (typeof options['boolean'] === 'boolean' && options['boolean']) { + flags.allBools = true; + } else { + [].concat(options['boolean']).filter(Boolean).forEach(function (key) { + flags.bools[key] = true; + }); + } + + var aliases = {}; + Object.keys(options.alias || {}).forEach(function (key) { + aliases[key] = [].concat(options.alias[key]); + aliases[key].forEach(function (x) { + aliases[x] = [key].concat(aliases[key].filter(function (y) { + return x !== y; + })); + }); + }); + + [].concat(options.string).filter(Boolean).forEach(function (key) { + flags.strings[key] = true; + if (aliases[key]) { + flags.strings[aliases[key]] = true; + } + }); + + var defaults = options['default'] || {}; + + var argv = { _ : [] }; + Object.keys(flags.bools).forEach(function (key) { + setArg(key, defaults[key] === undefined ? false : defaults[key]); + }); + + var notFlags = []; + + if (args.indexOf('--') !== -1) { + notFlags = args.slice(args.indexOf('--')+1); + args = args.slice(0, args.indexOf('--')); + } + + function argDefined(key, arg) { + return (flags.allBools && /^--[^=]+$/.test(arg)) || + flags.strings[key] || flags.bools[key] || aliases[key]; + } + + function setArg (key, val, arg?) { + if (arg && flags.unknownFn && !argDefined(key, arg)) { + if (flags.unknownFn(arg) === false) return; + } + + var value = !flags.strings[key] && isNumber(val) + ? Number(val) : val + ; + setKey(argv, key.split('.'), value); + + (aliases[key] || []).forEach(function (x) { + setKey(argv, x.split('.'), value); + }); + } + + function setKey (obj, keys, value) { + var o = obj; + keys.slice(0,-1).forEach(function (key) { + if (o[key] === undefined) o[key] = {}; + o = o[key]; + }); + + var key = keys[keys.length - 1]; + if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') { + o[key] = value; + } + else if (Array.isArray(o[key])) { + o[key].push(value); + } + else { + o[key] = [ o[key], value ]; + } + } + + function aliasIsBoolean(key) { + return aliases[key].some(function (x) { + return flags.bools[x]; + }); + } + + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + + if (/^--.+=/.test(arg)) { + // Using [\s\S] instead of . because js doesn't support the + // 'dotall' regex modifier. See: + // http://stackoverflow.com/a/1068308/13216 + var m = arg.match(/^--([^=]+)=([\s\S]*)$/); + var key = m[1]; + var value: any = m[2]; + if (flags.bools[key]) { + value = value !== 'false'; + } + setArg(key, value, arg); + } + /* + else if (/^--no-.+/.test(arg)) { + var key = arg.match(/^--no-(.+)/)[1]; + setArg(key, false, arg); + } + */ + else if (/^--.+/.test(arg)) { + var key = arg.match(/^--(.+)/)[1]; + var next = args[i + 1]; + if (next !== undefined && !/^-/.test(next) + && !flags.bools[key] + && !flags.allBools + && (aliases[key] ? !aliasIsBoolean(key) : true)) { + setArg(key, next, arg); + i++; + } + else if (/^(true|false)$/.test(next)) { + setArg(key, next === 'true', arg); + i++; + } + else { + setArg(key, flags.strings[key] ? '' : true, arg); + } + } + else if (/^-[^-]+/.test(arg)) { + var letters = arg.slice(1,-1).split(''); + + var broken = false; + for (var j = 0; j < letters.length; j++) { + var next = arg.slice(j+2); + + if (next === '-') { + setArg(letters[j], next, arg) + continue; + } + + if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) { + setArg(letters[j], next.split('=')[1], arg); + broken = true; + break; + } + + if (/[A-Za-z]/.test(letters[j]) + && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { + setArg(letters[j], next, arg); + broken = true; + break; + } + + if (letters[j+1] && letters[j+1].match(/\W/)) { + setArg(letters[j], arg.slice(j+2), arg); + broken = true; + break; + } + else { + setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg); + } + } + + var key = arg.slice(-1)[0]; + if (!broken && key !== '-') { + if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1]) + && !flags.bools[key] + && (aliases[key] ? !aliasIsBoolean(key) : true)) { + setArg(key, args[i+1], arg); + i++; + } + else if (args[i+1] && /true|false/.test(args[i+1])) { + setArg(key, args[i+1] === 'true', arg); + i++; + } + else { + setArg(key, flags.strings[key] ? '' : true, arg); + } + } + } + else { + if (!flags.unknownFn || flags.unknownFn(arg) !== false) { + argv._.push( + flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) + ); + } + if (options.stopEarly) { + argv._.push.apply(argv._, args.slice(i + 1)); + break; + } + } + } + + Object.keys(defaults).forEach(function (key) { + if (!hasKey(argv, key.split('.'))) { + setKey(argv, key.split('.'), defaults[key]); + + (aliases[key] || []).forEach(function (x) { + setKey(argv, x.split('.'), defaults[key]); + }); + } + }); + + if (options['--']) { + argv['--'] = new Array(); + notFlags.forEach(function(key) { + argv['--'].push(key); + }); + } + else { + notFlags.forEach(function(key) { + argv._.push(key); + }); + } + + return argv; +}; + +function hasKey (obj, keys) { + var o = obj; + keys.slice(0,-1).forEach(function (key) { + o = (o[key] || {}); + }); + + var key = keys[keys.length - 1]; + return key in o; +} + +function isNumber (x) { + if (typeof x === 'number') return true; + if (/^0x[0-9a-f]+$/i.test(x)) return true; + return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); +} + + +function minimist(args?: string[], opts?: minimist.Opts): T & minimist.ParsedArgs { + return parse(args || [], opts) as any; +} +export = minimist; \ No newline at end of file diff --git a/modules/shared/version/index.ts b/modules/shared/version/index.ts new file mode 100644 index 0000000..f56dcf3 --- /dev/null +++ b/modules/shared/version/index.ts @@ -0,0 +1,81 @@ +export class Version { + major: number = 0; + minor: number = 0; + patch: number = 0; + build: number = 0; + timestamp: number = 0; + + constructor(major: number, minor: number, patch: number, build: number, timestamp: number) { + this.major = major; + this.minor = minor; + this.patch = patch; + this.build = build; + } + + toString(timestamp: boolean = false) { + let result = ""; + result += this.major + "."; + result += this.minor + "."; + result += this.patch; + if(this.build > 0) + result += "-" + this.build; + if(timestamp && this.timestamp > 0) + result += " [" + this.timestamp + "]"; + return result; + } + + + equals(other: Version) : boolean { + if(other == this) return true; + if(typeof(other) != typeof(this)) return false; + + if(other.major != this.major) return false; + if(other.minor != this.minor) return false; + if(other.patch != this.patch) return false; + if(other.build != this.build) return false; + if(other.timestamp != this.timestamp) return false; + + return true; + } + + newer_than(other: Version) : boolean { + if(other.major > this.major) return false; + else if(other.major < this.major) return true; + + if(other.minor > this.minor) return false; + else if(other.minor < this.minor) return true; + + else if(other.patch < this.patch) return true; + if(other.patch > this.patch) return false; + + if(other.build > this.build) return false; + else if(other.build < this.build) return true; + + return false; + } + + in_dev() : boolean { + return this.build == 0 && this.major == 0 && this.minor == 0 && this.patch == 0 && this.timestamp == 0; + } +} + +//1.0.0-2 [1000] +export function parse_version(version: string) : Version { + let result: Version = new Version(0, 0, 0, 0, 0); + + const roots = version.split(" "); + { + const parts = roots[0].split("-"); + const numbers = parts[0].split("."); + + if(numbers.length > 0) result.major = parseInt(numbers[0]); + if(numbers.length > 1) result.minor = parseInt(numbers[1]); + if(numbers.length > 2) result.patch = parseInt(numbers[2]); + if(parts.length > 1) result.build = parseInt(parts[1]); + } + if(roots.length > 1 && ((roots[1] = roots[1].trim()).startsWith("[") && roots[1].endsWith("]"))) { + result.timestamp = parseInt(roots[1].substr(1, roots[1].length - 2)); + } + + return result; +} \ No newline at end of file diff --git a/modules/tsconfig_main.json b/modules/tsconfig_main.json new file mode 100644 index 0000000..94712dc --- /dev/null +++ b/modules/tsconfig_main.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "sourceMap": true, + "moduleResolution": "node" + }, + "include": [ + "./core", + "./crash_handler", + "./shared", + "../main.ts" + ], + "exclude": [ + "node_modules", + "declarations", + "app/dummy-declarations/*.d.ts" + ] +} \ No newline at end of file diff --git a/modules/tsconfig_renderer.json b/modules/tsconfig_renderer.json new file mode 100644 index 0000000..28ecbf9 --- /dev/null +++ b/modules/tsconfig_renderer.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "sourceMap": true, + "moduleResolution": "node" + }, + "include": [ + "./renderer", + "./crash_handler", + "./shared/*.ts", + "../native/*/exports/" + ], + "exclude": [ + "./renderer/imports/.copy_*.d.ts" + ] +} \ No newline at end of file diff --git a/native/.gitignore b/native/.gitignore new file mode 100644 index 0000000..fa77192 --- /dev/null +++ b/native/.gitignore @@ -0,0 +1,3 @@ +build/ +cmake-build-* +out/* \ No newline at end of file diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt new file mode 100644 index 0000000..f78f7de --- /dev/null +++ b/native/CMakeLists.txt @@ -0,0 +1,176 @@ +cmake_minimum_required(VERSION 3.1) + +project(TeaClient-Natives VERSION 1.0.0) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_VERBOSE_MAKEFILE ON) + +if (CMAKE_INCLUDE_FILE AND NOT CMAKE_INCLUDE_FILE STREQUAL "") + message("Include file ${CMAKE_INCLUDE_FILE}") + include("${CMAKE_INCLUDE_FILE}") +endif () + +if(CMAKE_PLATFORM_INCLUDE AND NOT CMAKE_PLATFORM_INCLUDE STREQUAL "") + message("Include file ${CMAKE_PLATFORM_INCLUDE}") + include("${CMAKE_PLATFORM_INCLUDE}") +endif() +message("Library path: ${LIBRARY_PATH}") +message("Module path: ${CMAKE_MODULE_PATH}") + +#Setup NodeJS +function(setup_nodejs) + set(NodeJS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + set(NODEJS_URL "https://atom.io/download/atom-shell") + set(NODEJS_VERSION "v6.0.7") + #set(NODEJS_VERSION "v8.0.0") + + #set(NODEJS_URL "https://nodejs.org/download/release/") + #set(NODEJS_VERSION "v12.7.0") + + find_package(NodeJS REQUIRED) + + set(NODEJS_NAN_DIR "node_modules/nan") + nodejs_init() + + #Fix nan include headers + set(NAN_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/../node_modules/nan") + if(NOT EXISTS "${NAN_INCLUDE_DIR}") + message(FATAL_ERROR "Failed to find nan headers.") + endif() + list(APPEND NODEJS_INCLUDE_DIRS ${NAN_INCLUDE_DIR}) + + set(EXE_DIRECTORY "${CMAKE_SOURCE_DIR}/build/exe/" PARENT_SCOPE) + if (MSVC) + set(NODE_LIB_DIRECTORY "${CMAKE_SOURCE_DIR}/build/win32_x64/" PARENT_SCOPE) + set(NODE_PDB_DIRECTORY "${CMAKE_SOURCE_DIR}/build/symbols/" PARENT_SCOPE) + else() + set(NODE_LIB_DIRECTORY "${CMAKE_SOURCE_DIR}/build/linux_x64/" PARENT_SCOPE) + endif() + + #Set some more variables + set(NODEJS_INCLUDE_DIRS "${NODEJS_INCLUDE_DIRS}" PARENT_SCOPE) + set(NODEJS_INIT ${NODEJS_INIT} PARENT_SCOPE) + + include_directories("dist/ext_nan") + + + function(add_nodejs_module NAME) + message("Registering module ${NAME}") + _add_nodejs_module(${NAME} ${ARGN}) + target_compile_features(${NAME} PUBLIC cxx_std_17) + set_target_properties(${NAME} + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${NODE_LIB_DIRECTORY}/" + ) + target_include_directories(${NAME} PUBLIC ${NODEJS_INCLUDE_DIRS}) + set_target_properties(${NAME} PROPERTIES CXX_STANDARD 17) #Needs to be overridden after _add_nodejs_module sets it to 11 + + if(MSVC) + add_custom_command(TARGET ${NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy "$" "${NODE_LIB_DIRECTORY}/${NAME}.node" + ) + add_custom_command(TARGET ${NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy "$" "${NODE_PDB_DIRECTORY}/${NAME}.pdb" + ) + else() + set_target_properties(${NAME} + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${NODE_LIB_DIRECTORY}/" + ) + endif() + endfunction() + + #Forward parameters to global scope + set(NODEJS_VERSION ${NODEJS_VERSION} PARENT_SCOPE) + set(NODEJS_SOURCES ${NODEJS_SOURCES} PARENT_SCOPE) + set(NODEJS_INCLUDE_DIRS ${NODEJS_INCLUDE_DIRS} PARENT_SCOPE) + set(NODEJS_LIBRARIES ${NODEJS_LIBRARIES} PARENT_SCOPE) + set(NODEJS_LINK_FLAGS ${NODEJS_LINK_FLAGS} PARENT_SCOPE) + set(NODEJS_DEFINITIONS ${NODEJS_DEFINITIONS} PARENT_SCOPE) + + # Prevents this function from executing more than once + set(NODEJS_INIT TRUE PARENT_SCOPE) +endfunction() + +#Setup the compiler (Cant be done within a function!) +if (MSVC) + set(CompilerFlags + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELWITHDEBINFO + ) + foreach(CompilerFlag ${CompilerFlags}) + string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") + endforeach() + add_compile_options("/EHsc") #We require exception handling +else() + #This is a bad thing here! + function(resolve_library VARIABLE FALLBACK PATHS) + set( _PATHS ${PATHS} ${ARGN} ) # Merge them together + + foreach(PATH IN ITEMS ${_PATHS}) + message(STATUS "Try to use path ${PATH} for ${VARIABLE}") + if(EXISTS ${PATH}) + message(STATUS "Setting ${VARIABLE} to ${PATH}") + set(${VARIABLE} ${PATH} PARENT_SCOPE) + return() + endif() + endforeach() + + if(FALLBACK) + message(WARNING "Failed to resolve library path for ${VARIABLE}. Using default ${VARIABLE}") + else() + message(FATAL_ERROR "Failed to find requited library. Variable: ${VARIABLE} Paths: ${_PATHS}") + endif() + endfunction() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -static-libgcc -static-libstdc++") + set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "") # Disable -fPIC (We dont want any relonking with build in electron libraries +endif() + +setup_nodejs() +if(NOT NODEJS_INCLUDE_DIRS OR NODEJS_INCLUDE_DIRS STREQUAL "") + message(FATAL_ERROR "Failed to find node headers") +else() + message("Including NodeJS headers: ${NODEJS_INCLUDE_DIRS}") +endif() +include_directories(${NODEJS_INCLUDE_DIRS}) + +function(build_update_installer) + add_subdirectory(updater) +endfunction() +build_update_installer() + + +function(build_codec) + add_subdirectory(codec) +endfunction() +#build_codec() + +function(build_ppt) + add_subdirectory(ppt) +endfunction() +build_ppt() + +function(build_connection) + add_subdirectory(serverconnection) +endfunction() +build_connection() + +function(build_crash_handler) + add_subdirectory(crash_handler) +endfunction() +build_crash_handler() + +function(build_dns) + add_subdirectory(dns) +endfunction() +build_dns() diff --git a/native/cmake/nodejs-config.cmake b/native/cmake/nodejs-config.cmake new file mode 100644 index 0000000..fcf7249 --- /dev/null +++ b/native/cmake/nodejs-config.cmake @@ -0,0 +1,1284 @@ +# Defaults for standard Node.exports builds +set(NODEJS_DEFAULT_URL https://nodejs.org/download/release) +set(NODEJS_DEFAULT_VERSION installed) +set(NODEJS_VERSION_FALLBACK latest) +set(NODEJS_DEFAULT_NAME node) +set(NODEJS_DEFAULT_CHECKSUM SHASUMS256.txt) +set(NODEJS_DEFAULT_CHECKTYPE SHA256) + +include(CMakeParseArguments) + +# Find a path by walking upward from a base directory until the path is +# found. Sets the variable ${PATH} to False if the path can't +# be determined +function(find_path_parent NAME BASE PATH) + set(ROOT ${BASE}) + set(${PATH} ${ROOT}/${NAME} PARENT_SCOPE) + set(DRIVE "^[A-Za-z]?:?/$") + + while(NOT ROOT MATCHES ${DRIVE} AND NOT ROOT STREQUAL "" AND NOT EXISTS ${ROOT}/${NAME}) + get_filename_component(ROOT ${ROOT} DIRECTORY) + set(${PATH} ${ROOT}/${NAME} PARENT_SCOPE) + endwhile() + + if(ROOT MATCHES ${DRIVE} OR ROOT STREQUAL "") + set(PATH False PARENT_SCOPE) + endif() +endfunction() + +# Shortcut for finding standard node module locations +macro(find_nodejs_module NAME BASE PATH) + find_path_parent(node_modules/${NAME} ${BASE} ${PATH}) +endmacro() + +# Download with a bit of nice output (without spewing progress) +function(download_file URL) + message(STATUS "Downloading: ${URL}") + file(APPEND ${TEMP}/download.log "Downloading: ${URL}\n") + file(APPEND ${TEMP}/download.log "----------------------------------------\n") + file(DOWNLOAD + ${URL} + ${ARGN} + LOG DOWNLOAD_LOG + ) + file(APPEND ${TEMP}/download.log ${DOWNLOAD_LOG}) + file(APPEND ${TEMP}/download.log "----------------------------------------\n") +endfunction() + +# Embedded win_delay_load_hook file so that this file can be copied +# into projects directly (recommended practice) +function(nodejs_generate_delayload_hook OUTPUT) + file(WRITE ${OUTPUT} "") + file(APPEND ${OUTPUT} "/*\n") + file(APPEND ${OUTPUT} " * When this file is linked to a DLL, it sets up a delay-load hook that\n") + file(APPEND ${OUTPUT} " * intervenes when the DLL is trying to load the main node binary\n") + file(APPEND ${OUTPUT} " * dynamically. Instead of trying to locate the .exe file it'll just return\n") + file(APPEND ${OUTPUT} " * a handle to the process image.\n") + file(APPEND ${OUTPUT} " *\n") + file(APPEND ${OUTPUT} " * This allows compiled addons to work when node.exe or iojs.exe is renamed.\n") + file(APPEND ${OUTPUT} " */\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#ifdef _MSC_VER\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#ifndef DELAYIMP_INSECURE_WRITABLE_HOOKS\n") + file(APPEND ${OUTPUT} "#define DELAYIMP_INSECURE_WRITABLE_HOOKS\n") + file(APPEND ${OUTPUT} "#endif\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#ifndef WIN32_LEAN_AND_MEAN\n") + file(APPEND ${OUTPUT} "#define WIN32_LEAN_AND_MEAN\n") + file(APPEND ${OUTPUT} "#endif\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "static FARPROC WINAPI load_exe_hook(unsigned int event, DelayLoadInfo* info) {\n") + file(APPEND ${OUTPUT} " if (event != dliNotePreLoadLibrary) return NULL;\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " if (_stricmp(info->szDll, \"iojs.exe\") != 0 &&\n") + file(APPEND ${OUTPUT} " _stricmp(info->szDll, \"node.exe\") != 0 &&\n") + file(APPEND ${OUTPUT} " _stricmp(info->szDll, \"node.dll\") != 0)\n") + file(APPEND ${OUTPUT} " return NULL;\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // Get a handle to the current process executable.\n") + file(APPEND ${OUTPUT} " HMODULE processModule = GetModuleHandle(NULL);\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // Get the path to the executable.\n") + file(APPEND ${OUTPUT} " TCHAR processPath[_MAX_PATH];\n") + file(APPEND ${OUTPUT} " GetModuleFileName(processModule, processPath, _MAX_PATH);\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // Get the name of the current executable.\n") + file(APPEND ${OUTPUT} " LPTSTR processName = PathFindFileName(processPath);\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // If the current process is node or iojs, then just return the proccess \n") + file(APPEND ${OUTPUT} " // module.\n") + file(APPEND ${OUTPUT} " if (_tcsicmp(processName, TEXT(\"node.exe\")) == 0 ||\n") + file(APPEND ${OUTPUT} " _tcsicmp(processName, TEXT(\"iojs.exe\")) == 0) {\n") + file(APPEND ${OUTPUT} " return (FARPROC) processModule;\n") + file(APPEND ${OUTPUT} " }\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // If it is another process, attempt to load 'node.dll' from the same \n") + file(APPEND ${OUTPUT} " // directory.\n") + file(APPEND ${OUTPUT} " PathRemoveFileSpec(processPath);\n") + file(APPEND ${OUTPUT} " PathAppend(processPath, TEXT(\"node.dll\"));\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " HMODULE nodeDllModule = GetModuleHandle(processPath);\n") + file(APPEND ${OUTPUT} " if(nodeDllModule != NULL) {\n") + file(APPEND ${OUTPUT} " // This application has a node.dll in the same directory as the executable,\n") + file(APPEND ${OUTPUT} " // use that.\n") + file(APPEND ${OUTPUT} " return (FARPROC) nodeDllModule;\n") + file(APPEND ${OUTPUT} " }\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // Fallback to the current executable, which must statically link to \n") + file(APPEND ${OUTPUT} " // node.lib\n") + file(APPEND ${OUTPUT} " return (FARPROC) processModule;\n") + file(APPEND ${OUTPUT} "}\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "PfnDliHook __pfnDliNotifyHook2 = load_exe_hook;\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#endif\n") +endfunction() + +# Sets up a project to build Node.exports native modules +# - Downloads required dependencies and unpacks them to the build directory. +# Internet access is required the first invocation but not after ( +# provided the download is successful) +# - Sets up several variables for building against the downloaded +# dependencies +# - Guarded to prevent multiple executions, so a single project hierarchy +# will only call this once +function(nodejs_init) + # Prevents this function from executing more than once + if(NODEJS_INIT) + return() + endif() + + # Regex patterns used by the init function for component extraction + set(HEADERS_MATCH "^([A-Fa-f0-9]+)[ \t]+([^-]+)-(headers|v?[0-9.]+(-beta[0-9.]+)?)-(headers|v?[0-9.]+)([.]tar[.]gz)$") + set(LIB32_MATCH "(^[0-9A-Fa-f]+)[\t ]+(win-x86)?(/)?([^/]*)(.lib)$") + set(LIB64_MATCH "(^[0-9A-Fa-f]+)[\t ]+(win-)?(x64/)(.*)(.lib)$") + + # Parse function arguments + cmake_parse_arguments(nodejs_init + "" "URL;NAME;VERSION;CHECKSUM;CHECKTYPE" "" ${ARGN} + ) + + # Allow the download URL to be overridden by command line argument + # NODEJS_URL + if(NODEJS_URL) + set(URL ${NODEJS_URL}) + else() + # Use the argument if specified, falling back to the default + set(URL ${NODEJS_DEFAULT_URL}) + if(nodejs_init_URL) + set(URL ${nodejs_init_URL}) + endif() + endif() + + # Allow name to be overridden by command line argument NODEJS_NAME + if(NODEJS_NAME) + set(NAME ${NODEJS_NAME}) + else() + # Use the argument if specified, falling back to the default + set(NAME ${NODEJS_DEFAULT_NAME}) + if(nodejs_init_NAME) + set(NAME ${nodejs_init_NAME}) + endif() + endif() + + # Allow the checksum file to be overridden by command line argument + # NODEJS_CHECKSUM + if(NODEJS_CHECKSUM) + set(CHECKSUM ${NODEJS_CHECKSUM}) + else() + # Use the argument if specified, falling back to the default + set(CHECKSUM ${NODEJS_DEFAULT_CHECKSUM}) + if(nodejs_init_CHECKSUM) + set(CHECKSUM ${nodejs_init_CHECKSUM}) + endif() + endif() + + # Allow the checksum type to be overriden by the command line argument + # NODEJS_CHECKTYPE + if(NODEJS_CHECKTYPE) + set(CHECKTYPE ${NODEJS_CHECKTYPE}) + else() + # Use the argument if specified, falling back to the default + set(CHECKTYPE ${NODEJS_DEFAULT_CHECKTYPE}) + if(nodejs_init_CHECKTYPE) + set(CHECKTYPE ${nodejs_init_CHECKTYPE}) + endif() + endif() + + # Allow the version to be overridden by the command line argument + # NODEJS_VERSION + if(NODEJS_VERSION) + set(VERSION ${NODEJS_VERSION}) + else() + # Use the argument if specified, falling back to the default + set(VERSION ${NODEJS_DEFAULT_VERSION}) + if(nodejs_init_VERSION) + set(VERSION ${nodejs_init_VERSION}) + endif() + endif() + + # "installed" is a special version that tries to use the currently + # installed version (determined by running node) + set(NODEJS_INSTALLED False CACHE BOOL "Node.js install status" FORCE) + if(VERSION STREQUAL "installed") + if(NOT NAME STREQUAL ${NODEJS_DEFAULT_NAME}) + message(FATAL_ERROR + "'Installed' version identifier can only be used with" + "the core Node.js library" + ) + endif() + # Fall back to the "latest" version if node isn't installed + set(VERSION ${NODEJS_VERSION_FALLBACK}) + # This has all of the implications of why the binary is called nodejs in the first place + # https://lists.debian.org/debian-devel-announce/2012/07/msg00002.html + # However, with nvm/n, its nearly standard to have a proper 'node' binary now (since the + # apt-based one is so out of date), so for now just assume that this rare binary conflict + # case is the degenerate case. May need a more complicated solution later. + find_program(NODEJS_BINARY NAMES node nodejs) + if(NODEJS_BINARY) + execute_process( + COMMAND ${NODEJS_BINARY} --version + RESULT_VARIABLE INSTALLED_VERSION_RESULT + OUTPUT_VARIABLE INSTALLED_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(INSTALLED_VERSION_RESULT STREQUAL "0") + set(NODEJS_INSTALLED True CACHE BOOL + "Node.js install status" FORCE + ) + set(VERSION ${INSTALLED_VERSION}) + endif() + endif() + endif() + + # Create a temporary download directory + set(TEMP ${CMAKE_CURRENT_BINARY_DIR}/temp) + if(EXISTS ${TEMP}) + file(REMOVE_RECURSE ${TEMP}) + endif() + file(MAKE_DIRECTORY ${TEMP}) + + # Unless the target is special version "latest", the parameters + # necessary to construct the root path are known + if(NOT VERSION STREQUAL "latest") + set(ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/${VERSION}) + # Extract checksums from the existing checksum file + set(CHECKSUM_TARGET ${ROOT}/CHECKSUM) + endif() + + # If we're trying to determine the version or we haven't saved the + # checksum file for this version, download it from the specified server + if(VERSION STREQUAL "latest" OR + (DEFINED ROOT AND NOT EXISTS ${ROOT}/CHECKSUM)) + if(DEFINED ROOT) + # Clear away the old checksum in case the new one is different + # and/or it fails to download + file(REMOVE ${ROOT}/CHECKSUM) + endif() + file(REMOVE ${TEMP}/CHECKSUM) + download_file( + ${URL}/${VERSION}/${CHECKSUM} + ${TEMP}/CHECKSUM + INACTIVITY_TIMEOUT 10 + STATUS CHECKSUM_STATUS + ) + list(GET CHECKSUM_STATUS 0 CHECKSUM_STATUS) + if(CHECKSUM_STATUS GREATER 0) + file(REMOVE ${TEMP}/CHECKSUM) + message(FATAL_ERROR + "Unable to download checksum file" + ) + endif() + # Extract checksums from the temporary file + set(CHECKSUM_TARGET ${TEMP}/CHECKSUM) + endif() + + # Extract the version, name, header archive and archive checksum + # from the file. This first extract is what defines / specifies the + # actual version number and name. + file(STRINGS + ${CHECKSUM_TARGET} HEADERS_CHECKSUM + REGEX ${HEADERS_MATCH} + LIMIT_COUNT 1 + ) + if(NOT HEADERS_CHECKSUM) + file(REMOVE ${TEMP}/CHECKSUM) + if(DEFINED ROOT) + file(REMOVE ${ROOT}/CHECKSUM) + endif() + message(FATAL_ERROR "Unable to extract header archive checksum") + endif() + string(REGEX MATCH ${HEADERS_MATCH} HEADERS_CHECKSUM ${HEADERS_CHECKSUM}) + set(HEADERS_CHECKSUM ${CMAKE_MATCH_1}) + set(NAME ${CMAKE_MATCH_2}) + if(CMAKE_MATCH_4 STREQUAL "headers") + set(VERSION ${CMAKE_MATCH_3}-${CMAKE_MATCH_4}) + else() + set(VERSION ${CMAKE_MATCH_3}) + endif() + set(HEADERS_ARCHIVE + ${CMAKE_MATCH_2}-${CMAKE_MATCH_3}-${CMAKE_MATCH_5}${CMAKE_MATCH_6} + ) + # Make sure that the root directory exists, and that the checksum + # file has been moved over from temp + if(DEFINED ROOT) + set(OLD_ROOT ${ROOT}) + endif() + set(ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/${VERSION}) + if(DEFINED OLD_ROOT AND NOT ROOT STREQUAL "${OLD_ROOT}") + file(REMOVE ${TEMP}/CHECKSUM) + file(REMOVE ${ROOT}/CHECKSUM) + message("${ROOT} -> ${OLD_ROOT}") + message(FATAL_ERROR "Version/Name mismatch") + endif() + file(MAKE_DIRECTORY ${ROOT}) + if(EXISTS ${TEMP}/CHECKSUM) + file(REMOVE ${ROOT}/CHECKSUM) + file(RENAME ${TEMP}/CHECKSUM ${ROOT}/CHECKSUM) + endif() + + # Now that its fully resolved, report the name and version of Node.exports being + # used + message(STATUS "NodeJS: Using ${NAME}, version ${VERSION}") + + # Download the headers for the version being used + # Theoretically, these could be found by searching the installed + # system, but in practice, this can be error prone. They're provided + # on the download servers, so just use the ones there. + if(NOT EXISTS ${ROOT}/include) + file(REMOVE ${TEMP}/${HEADERS_ARCHIVE}) + download_file( + ${URL}/${VERSION}/${HEADERS_ARCHIVE} + ${TEMP}/${HEADERS_ARCHIVE} + INACTIVITY_TIMEOUT 10 + EXPECTED_HASH ${CHECKTYPE}=${HEADERS_CHECKSUM} + STATUS HEADERS_STATUS + ) + list(GET HEADERS_STATUS 0 HEADERS_STATUS) + if(HEADER_STATUS GREATER 0) + file(REMOVE ${TEMP}/${HEADERS_ARCHIVE}) + message(FATAL_ERROR "Unable to download Node.js headers") + endif() + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xfz ${TEMP}/${HEADERS_ARCHIVE} + WORKING_DIRECTORY ${TEMP} + ) + + # This adapts the header extraction to support a number of different + # header archive contents in addition to the one used by the + # default Node.exports library + unset(NODEJS_HEADERS_PATH CACHE) + find_path(NODEJS_HEADERS_PATH + NAMES src include + PATHS + ${TEMP}/${NAME}-${VERSION}-headers + ${TEMP}/${NAME}-${VERSION} + ${TEMP}/${NODEJS_DEFAULT_NAME}-${VERSION}-headers + ${TEMP}/${NODEJS_DEFAULT_NAME}-${VERSION} + ${TEMP}/${NODEJS_DEFAULT_NAME} + ${TEMP}/${NODEJS_DEFAULT_NAME}_headers + ${TEMP} + NO_DEFAULT_PATH + ) + if(NOT NODEJS_HEADERS_PATH) + message(FATAL_ERROR "Unable to find extracted headers folder") + endif() + + # Move the headers into a standard location with a standard layout + file(REMOVE ${TEMP}/${HEADERS_ARCHIVE}) + file(REMOVE_RECURSE ${ROOT}/include) + if(EXISTS ${NODEJS_HEADERS_PATH}/include/node) + file(RENAME ${NODEJS_HEADERS_PATH}/include/node ${ROOT}/include) + elseif(EXISTS ${NODEJS_HEADERS_PATH}/src) + file(MAKE_DIRECTORY ${ROOT}/include) + if(NOT EXISTS ${NODEJS_HEADERS_PATH}/src) + file(REMOVE_RECURSE ${ROOT}/include) + message(FATAL_ERROR "Unable to find core headers") + endif() + file(COPY ${NODEJS_HEADERS_PATH}/src/ + DESTINATION ${ROOT}/include + ) + if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/uv/include) + file(REMOVE_RECURSE ${ROOT}/include) + message(FATAL_ERROR "Unable to find libuv headers") + endif() + file(COPY ${NODEJS_HEADERS_PATH}/deps/uv/include/ + DESTINATION ${ROOT}/include + ) + if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/v8/include) + file(REMOVE_RECURSE ${ROOT}/include) + message(FATAL_ERROR "Unable to find v8 headers") + endif() + file(COPY ${NODEJS_HEADERS_PATH}/deps/v8/include/ + DESTINATION ${ROOT}/include + ) + if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/zlib) + file(REMOVE_RECURSE ${ROOT}/include) + message(FATAL_ERROR "Unable to find zlib headers") + endif() + file(COPY ${NODEJS_HEADERS_PATH}/deps/zlib/ + DESTINATION ${ROOT}/include + ) + endif() + file(REMOVE_RECURSE ${NODEJS_HEADERS_PATH}) + unset(NODEJS_HEADERS_PATH CACHE) + endif() + + # Only download the libraries on windows, since its the only place + # its necessary. Note, this requires rerunning CMake if moving + # a module from one platform to another (should happen automatically + # with most generators) + if(WIN32) + # Download the win32 library for linking + file(STRINGS + ${ROOT}/CHECKSUM LIB32_CHECKSUM + LIMIT_COUNT 1 + REGEX ${LIB32_MATCH} + ) + if(NOT LIB32_CHECKSUM) + message(FATAL_ERROR "Unable to extract x86 library checksum") + endif() + string(REGEX MATCH ${LIB32_MATCH} LIB32_CHECKSUM ${LIB32_CHECKSUM}) + set(LIB32_CHECKSUM ${CMAKE_MATCH_1}) + set(LIB32_PATH win-x86) + set(LIB32_NAME ${CMAKE_MATCH_4}${CMAKE_MATCH_5}) + set(LIB32_TARGET ${CMAKE_MATCH_2}${CMAKE_MATCH_3}${LIB32_NAME}) + if(NOT EXISTS ${ROOT}/${LIB32_PATH}) + file(REMOVE_RECURSE ${TEMP}/${LIB32_PATH}) + download_file( + ${URL}/${VERSION}/${LIB32_TARGET} + ${TEMP}/${LIB32_PATH}/${LIB32_NAME} + INACTIVITY_TIMEOUT 10 + EXPECTED_HASH ${CHECKTYPE}=${LIB32_CHECKSUM} + STATUS LIB32_STATUS + ) + list(GET LIB32_STATUS 0 LIB32_STATUS) + if(LIB32_STATUS GREATER 0) + message(FATAL_ERROR + "Unable to download Node.js windows library (32-bit)" + ) + endif() + file(REMOVE_RECURSE ${ROOT}/${LIB32_PATH}) + file(MAKE_DIRECTORY ${ROOT}/${LIB32_PATH}) + file(RENAME + ${TEMP}/${LIB32_PATH}/${LIB32_NAME} + ${ROOT}/${LIB32_PATH}/${LIB32_NAME} + ) + file(REMOVE_RECURSE ${TEMP}/${LIB32_PATH}) + endif() + + # Download the win64 library for linking + file(STRINGS + ${ROOT}/CHECKSUM LIB64_CHECKSUM + LIMIT_COUNT 1 + REGEX ${LIB64_MATCH} + ) + if(NOT LIB64_CHECKSUM) + message(FATAL_ERROR "Unable to extract x64 library checksum") + endif() + string(REGEX MATCH ${LIB64_MATCH} LIB64_CHECKSUM ${LIB64_CHECKSUM}) + set(LIB64_CHECKSUM ${CMAKE_MATCH_1}) + set(LIB64_PATH win-x64) + set(LIB64_NAME ${CMAKE_MATCH_4}${CMAKE_MATCH_5}) + set(LIB64_TARGET ${CMAKE_MATCH_2}${CMAKE_MATCH_3}${LIB64_NAME}) + if(NOT EXISTS ${ROOT}/${LIB64_PATH}) + file(REMOVE_RECURSE ${TEMP}/${LIB64_PATH}) + download_file( + ${URL}/${VERSION}/${LIB64_TARGET} + ${TEMP}/${LIB64_PATH}/${LIB64_NAME} + INACTIVITY_TIMEOUT 10 + EXPECTED_HASH ${CHECKTYPE}=${LIB64_CHECKSUM} + STATUS LIB64_STATUS + ) + list(GET LIB64_STATUS 0 LIB64_STATUS) + if(LIB64_STATUS GREATER 0) + message(FATAL_ERROR + "Unable to download Node.js windows library (64-bit)" + ) + endif() + file(REMOVE_RECURSE ${ROOT}/${LIB64_PATH}) + file(MAKE_DIRECTORY ${ROOT}/${LIB64_PATH}) + file(RENAME + ${TEMP}/${LIB64_PATH}/${LIB64_NAME} + ${ROOT}/${LIB64_PATH}/${LIB64_NAME} + ) + file(REMOVE_RECURSE ${TEMP}/${LIB64_PATH}) + endif() + endif() + + # The downloaded headers should always be set for inclusion + list(APPEND INCLUDE_DIRS ${ROOT}/include) + + # Look for the NAN module, and add it to the includes + find_nodejs_module( + nan + .. + NODEJS_NAN_DIR + ) + if(NODEJS_NAN_DIR) + list(APPEND INCLUDE_DIRS ${NODEJS_NAN_DIR}) + endif() + + # Under windows, we need a bunch of libraries (due to the way + # dynamic linking works) + if(WIN32) + # Generate and use a delay load hook to allow the node binary + # name to be changed while still loading native modules + set(DELAY_LOAD_HOOK ${CMAKE_CURRENT_BINARY_DIR}/win_delay_load_hook.c) + nodejs_generate_delayload_hook(${DELAY_LOAD_HOOK}) + set(SOURCES ${DELAY_LOAD_HOOK}) + + # Necessary flags to get delayload working correctly + list(APPEND LINK_FLAGS + "-IGNORE:4199" + "-DELAYLOAD:iojs.exe" + "-DELAYLOAD:node.exe" + "-DELAYLOAD:node.dll" + ) + + # Core system libraries used by node + list(APPEND LIBRARIES + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib + odbc32.lib Shlwapi.lib DelayImp.lib + ) + + # Also link to the node stub itself (downloaded above) + if(CMAKE_CL_64) + list(APPEND LIBRARIES ${ROOT}/${LIB64_PATH}/${LIB64_NAME}) + else() + list(APPEND LIBRARIES ${ROOT}/${LIB32_PATH}/${LIB32_NAME}) + endif() + else() + # Non-windows platforms should use these flags + list(APPEND DEFINITIONS _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64) + endif() + + # Special handling for OSX / clang to allow undefined symbols + # Define is required by node on OSX + if(APPLE) + list(APPEND LINK_FLAGS "-undefined dynamic_lookup") + list(APPEND DEFINITIONS _DARWIN_USE_64_BIT_INODE=1) + endif() + + # Export all settings for use as arguments in the rest of the build + set(NODEJS_VERSION ${VERSION} PARENT_SCOPE) + set(NODEJS_SOURCES ${SOURCES} PARENT_SCOPE) + set(NODEJS_INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) + set(NODEJS_LIBRARIES ${LIBRARIES} PARENT_SCOPE) + set(NODEJS_LINK_FLAGS ${LINK_FLAGS} PARENT_SCOPE) + set(NODEJS_DEFINITIONS ${DEFINITIONS} PARENT_SCOPE) + + # Prevents this function from executing more than once + set(NODEJS_INIT TRUE PARENT_SCOPE) +endfunction() + +# Helper function for defining a node module +# After nodejs_init, all of the settings and dependencies necessary to do +# this yourself are defined, but this helps make sure everything is configured +# correctly. Feel free to use it as a model to do this by hand (or to +# tweak this configuration if you need something custom). +function(add_nodejs_module NAME) + # Validate name parameter (must be a valid C identifier) + string(MAKE_C_IDENTIFIER ${NAME} ${NAME}_SYMBOL_CHECK) + if(NOT "${NAME}" STREQUAL "${${NAME}_SYMBOL_CHECK}") + message(ERROR + "Module name must be a valid C identifier. " + "Suggested alternative: '${${NAME}_SYMBOL_CHECK}'" + ) + endif() + # Make sure node is initialized (variables set) before defining the module + if(NOT NODEJS_INIT) + message(FATAL_ERROR + "Node.js has not been initialized. " + "Call nodejs_init before adding any modules" + ) + endif() + # In order to match node-gyp, we need to build into type specific folders + # ncmake takes care of this, but be sure to set CMAKE_BUILD_TYPE yourself + # if invoking CMake directly + if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + message(FATAL_ERROR + "Configuration type must be specified. " + "Set CMAKE_BUILD_TYPE or use a different generator" + ) + endif() + + # A node module is a shared library + add_library(${NAME} SHARED ${NODEJS_SOURCES} ${ARGN}) + # Add compiler defines for the module + # Two helpful ones: + # MODULE_NAME must match the name of the build library, define that here + # ${NAME}_BUILD is for symbol visibility under windows + string(TOUPPER "${NAME}_BUILD" ${NAME}_BUILD_DEF) + target_compile_definitions(${NAME} + PRIVATE MODULE_NAME=${NAME} + PRIVATE ${${NAME}_BUILD_DEF} + PUBLIC ${NODEJS_DEFINITIONS} + ) + # This properly defines includes for the module + target_include_directories(${NAME} PUBLIC ${NODEJS_INCLUDE_DIRS}) + + # Add link flags to the module + target_link_libraries(${NAME} ${NODEJS_LIBRARIES}) + + # Set required properties for the module to build properly + # Correct naming, symbol visiblity and C++ standard + set_target_properties(${NAME} PROPERTIES + OUTPUT_NAME ${NAME} + PREFIX "" + SUFFIX ".node" + MACOSX_RPATH ON + C_VISIBILITY_PRESET hidden + CXX_VISIBILITY_PRESET hidden + POSITION_INDEPENDENT_CODE TRUE + CMAKE_CXX_STANDARD_REQUIRED TRUE + CXX_STANDARD 11 + ) + + # Handle link flag cases properly + # When there are link flags, they should be appended to LINK_FLAGS with space separation + # If the list is emtpy (true for most *NIX platforms), this is a no-op + foreach(NODEJS_LINK_FLAG IN LISTS NODEJS_LINK_FLAGS) + set_property(TARGET ${NAME} APPEND_STRING PROPERTY LINK_FLAGS " ${NODEJS_LINK_FLAG}") + endforeach() + + # Make sure we're buiilding in a build specific output directory + # Only necessary on single-target generators (Make, Ninja) + # Multi-target generators do this automatically + # This (luckily) mirrors node-gyp conventions + if(NOT CMAKE_CONFIGURATION_TYPES) + set_property(TARGET ${NAME} PROPERTY + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BUILD_TYPE} + ) + endif() +endfunction() +# Defaults for standard Node.exports builds +set(NODEJS_DEFAULT_URL https://nodejs.org/download/release) +set(NODEJS_DEFAULT_VERSION installed) +set(NODEJS_VERSION_FALLBACK latest) +set(NODEJS_DEFAULT_NAME node) +set(NODEJS_DEFAULT_CHECKSUM SHASUMS256.txt) +set(NODEJS_DEFAULT_CHECKTYPE SHA256) + +include(CMakeParseArguments) + +# Find a path by walking upward from a base directory until the path is +# found. Sets the variable ${PATH} to False if the path can't +# be determined +function(find_path_parent NAME BASE PATH) + set(ROOT ${BASE}) + set(${PATH} ${ROOT}/${NAME} PARENT_SCOPE) + set(DRIVE "^[A-Za-z]?:?/$") + + while(NOT ROOT MATCHES ${DRIVE} AND NOT ROOT STREQUAL "" AND NOT EXISTS ${ROOT}/${NAME}) + get_filename_component(ROOT ${ROOT} DIRECTORY) + set(${PATH} ${ROOT}/${NAME} PARENT_SCOPE) + endwhile() + + if(ROOT MATCHES ${DRIVE} OR ROOT STREQUAL "") + set(PATH False PARENT_SCOPE) + endif() +endfunction() + +# Shortcut for finding standard node module locations +macro(find_nodejs_module NAME BASE PATH) + find_path_parent(node_modules/${NAME} ${BASE} ${PATH}) +endmacro() + +# Download with a bit of nice output (without spewing progress) +function(download_file URL) + message(STATUS "Downloading: ${URL}") + file(APPEND ${TEMP}/download.log "Downloading: ${URL}\n") + file(APPEND ${TEMP}/download.log "----------------------------------------\n") + file(DOWNLOAD + ${URL} + ${ARGN} + LOG DOWNLOAD_LOG + ) + file(APPEND ${TEMP}/download.log ${DOWNLOAD_LOG}) + file(APPEND ${TEMP}/download.log "----------------------------------------\n") +endfunction() + +# Embedded win_delay_load_hook file so that this file can be copied +# into projects directly (recommended practice) +function(nodejs_generate_delayload_hook OUTPUT) + file(WRITE ${OUTPUT} "") + file(APPEND ${OUTPUT} "/*\n") + file(APPEND ${OUTPUT} " * When this file is linked to a DLL, it sets up a delay-load hook that\n") + file(APPEND ${OUTPUT} " * intervenes when the DLL is trying to load the main node binary\n") + file(APPEND ${OUTPUT} " * dynamically. Instead of trying to locate the .exe file it'll just return\n") + file(APPEND ${OUTPUT} " * a handle to the process image.\n") + file(APPEND ${OUTPUT} " *\n") + file(APPEND ${OUTPUT} " * This allows compiled addons to work when node.exe or iojs.exe is renamed.\n") + file(APPEND ${OUTPUT} " */\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#ifdef _MSC_VER\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#ifndef DELAYIMP_INSECURE_WRITABLE_HOOKS\n") + file(APPEND ${OUTPUT} "#define DELAYIMP_INSECURE_WRITABLE_HOOKS\n") + file(APPEND ${OUTPUT} "#endif\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#ifndef WIN32_LEAN_AND_MEAN\n") + file(APPEND ${OUTPUT} "#define WIN32_LEAN_AND_MEAN\n") + file(APPEND ${OUTPUT} "#endif\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "#include \n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "static FARPROC WINAPI load_exe_hook(unsigned int event, DelayLoadInfo* info) {\n") + file(APPEND ${OUTPUT} " if (event != dliNotePreLoadLibrary) return NULL;\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " if (_stricmp(info->szDll, \"iojs.exe\") != 0 &&\n") + file(APPEND ${OUTPUT} " _stricmp(info->szDll, \"node.exe\") != 0 &&\n") + file(APPEND ${OUTPUT} " _stricmp(info->szDll, \"node.dll\") != 0)\n") + file(APPEND ${OUTPUT} " return NULL;\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // Get a handle to the current process executable.\n") + file(APPEND ${OUTPUT} " HMODULE processModule = GetModuleHandle(NULL);\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // Get the path to the executable.\n") + file(APPEND ${OUTPUT} " TCHAR processPath[_MAX_PATH];\n") + file(APPEND ${OUTPUT} " GetModuleFileName(processModule, processPath, _MAX_PATH);\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // Get the name of the current executable.\n") + file(APPEND ${OUTPUT} " LPTSTR processName = PathFindFileName(processPath);\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // If the current process is node or iojs, then just return the proccess \n") + file(APPEND ${OUTPUT} " // module.\n") + file(APPEND ${OUTPUT} " if (_tcsicmp(processName, TEXT(\"node.exe\")) == 0 ||\n") + file(APPEND ${OUTPUT} " _tcsicmp(processName, TEXT(\"iojs.exe\")) == 0) {\n") + file(APPEND ${OUTPUT} " return (FARPROC) processModule;\n") + file(APPEND ${OUTPUT} " }\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // If it is another process, attempt to load 'node.dll' from the same \n") + file(APPEND ${OUTPUT} " // directory.\n") + file(APPEND ${OUTPUT} " PathRemoveFileSpec(processPath);\n") + file(APPEND ${OUTPUT} " PathAppend(processPath, TEXT(\"node.dll\"));\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " HMODULE nodeDllModule = GetModuleHandle(processPath);\n") + file(APPEND ${OUTPUT} " if(nodeDllModule != NULL) {\n") + file(APPEND ${OUTPUT} " // This application has a node.dll in the same directory as the executable,\n") + file(APPEND ${OUTPUT} " // use that.\n") + file(APPEND ${OUTPUT} " return (FARPROC) nodeDllModule;\n") + file(APPEND ${OUTPUT} " }\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} " // Fallback to the current executable, which must statically link to \n") + file(APPEND ${OUTPUT} " // node.lib\n") + file(APPEND ${OUTPUT} " return (FARPROC) processModule;\n") + file(APPEND ${OUTPUT} "}\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "PfnDliHook __pfnDliNotifyHook2 = load_exe_hook;\n") + file(APPEND ${OUTPUT} "\n") + file(APPEND ${OUTPUT} "#endif\n") +endfunction() + +# Sets up a project to build Node.exports native modules +# - Downloads required dependencies and unpacks them to the build directory. +# Internet access is required the first invocation but not after ( +# provided the download is successful) +# - Sets up several variables for building against the downloaded +# dependencies +# - Guarded to prevent multiple executions, so a single project hierarchy +# will only call this once +function(nodejs_init) + # Prevents this function from executing more than once + if(NODEJS_INIT) + return() + endif() + + # Regex patterns used by the init function for component extraction + set(HEADERS_MATCH "^([A-Fa-f0-9]+)[ \t]+([^-]+)-(headers|v?[0-9.]+(-beta[0-9.]+)?)-(headers|v?[0-9.]+)([.]tar[.]gz)$") + set(LIB32_MATCH "(^[0-9A-Fa-f]+)[\t ]+(win-x86)?(/)?([^/]*)(.lib)$") + set(LIB64_MATCH "(^[0-9A-Fa-f]+)[\t ]+(win-)?(x64/)(.*)(.lib)$") + + # Parse function arguments + cmake_parse_arguments(nodejs_init + "" "URL;NAME;VERSION;CHECKSUM;CHECKTYPE" "" ${ARGN} + ) + + # Allow the download URL to be overridden by command line argument + # NODEJS_URL + if(NODEJS_URL) + set(URL ${NODEJS_URL}) + else() + # Use the argument if specified, falling back to the default + set(URL ${NODEJS_DEFAULT_URL}) + if(nodejs_init_URL) + set(URL ${nodejs_init_URL}) + endif() + endif() + + # Allow name to be overridden by command line argument NODEJS_NAME + if(NODEJS_NAME) + set(NAME ${NODEJS_NAME}) + else() + # Use the argument if specified, falling back to the default + set(NAME ${NODEJS_DEFAULT_NAME}) + if(nodejs_init_NAME) + set(NAME ${nodejs_init_NAME}) + endif() + endif() + + # Allow the checksum file to be overridden by command line argument + # NODEJS_CHECKSUM + if(NODEJS_CHECKSUM) + set(CHECKSUM ${NODEJS_CHECKSUM}) + else() + # Use the argument if specified, falling back to the default + set(CHECKSUM ${NODEJS_DEFAULT_CHECKSUM}) + if(nodejs_init_CHECKSUM) + set(CHECKSUM ${nodejs_init_CHECKSUM}) + endif() + endif() + + # Allow the checksum type to be overriden by the command line argument + # NODEJS_CHECKTYPE + if(NODEJS_CHECKTYPE) + set(CHECKTYPE ${NODEJS_CHECKTYPE}) + else() + # Use the argument if specified, falling back to the default + set(CHECKTYPE ${NODEJS_DEFAULT_CHECKTYPE}) + if(nodejs_init_CHECKTYPE) + set(CHECKTYPE ${nodejs_init_CHECKTYPE}) + endif() + endif() + + # Allow the version to be overridden by the command line argument + # NODEJS_VERSION + if(NODEJS_VERSION) + set(VERSION ${NODEJS_VERSION}) + else() + # Use the argument if specified, falling back to the default + set(VERSION ${NODEJS_DEFAULT_VERSION}) + if(nodejs_init_VERSION) + set(VERSION ${nodejs_init_VERSION}) + endif() + endif() + + # "installed" is a special version that tries to use the currently + # installed version (determined by running node) + set(NODEJS_INSTALLED False CACHE BOOL "Node.js install status" FORCE) + if(VERSION STREQUAL "installed") + if(NOT NAME STREQUAL ${NODEJS_DEFAULT_NAME}) + message(FATAL_ERROR + "'Installed' version identifier can only be used with" + "the core Node.js library" + ) + endif() + # Fall back to the "latest" version if node isn't installed + set(VERSION ${NODEJS_VERSION_FALLBACK}) + # This has all of the implications of why the binary is called nodejs in the first place + # https://lists.debian.org/debian-devel-announce/2012/07/msg00002.html + # However, with nvm/n, its nearly standard to have a proper 'node' binary now (since the + # apt-based one is so out of date), so for now just assume that this rare binary conflict + # case is the degenerate case. May need a more complicated solution later. + find_program(NODEJS_BINARY NAMES node nodejs) + if(NODEJS_BINARY) + execute_process( + COMMAND ${NODEJS_BINARY} --version + RESULT_VARIABLE INSTALLED_VERSION_RESULT + OUTPUT_VARIABLE INSTALLED_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(INSTALLED_VERSION_RESULT STREQUAL "0") + set(NODEJS_INSTALLED True CACHE BOOL + "Node.js install status" FORCE + ) + set(VERSION ${INSTALLED_VERSION}) + endif() + endif() + endif() + + # Create a temporary download directory + set(TEMP ${CMAKE_CURRENT_BINARY_DIR}/temp) + if(EXISTS ${TEMP}) + file(REMOVE_RECURSE ${TEMP}) + endif() + file(MAKE_DIRECTORY ${TEMP}) + + # Unless the target is special version "latest", the parameters + # necessary to construct the root path are known + if(NOT VERSION STREQUAL "latest") + set(ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/${VERSION}) + # Extract checksums from the existing checksum file + set(CHECKSUM_TARGET ${ROOT}/CHECKSUM) + endif() + + # If we're trying to determine the version or we haven't saved the + # checksum file for this version, download it from the specified server + if(VERSION STREQUAL "latest" OR + (DEFINED ROOT AND NOT EXISTS ${ROOT}/CHECKSUM)) + if(DEFINED ROOT) + # Clear away the old checksum in case the new one is different + # and/or it fails to download + file(REMOVE ${ROOT}/CHECKSUM) + endif() + file(REMOVE ${TEMP}/CHECKSUM) + download_file( + ${URL}/${VERSION}/${CHECKSUM} + ${TEMP}/CHECKSUM + INACTIVITY_TIMEOUT 10 + STATUS CHECKSUM_STATUS + ) + list(GET CHECKSUM_STATUS 0 CHECKSUM_STATUS) + if(CHECKSUM_STATUS GREATER 0) + file(REMOVE ${TEMP}/CHECKSUM) + message(FATAL_ERROR + "Unable to download checksum file" + ) + endif() + # Extract checksums from the temporary file + set(CHECKSUM_TARGET ${TEMP}/CHECKSUM) + endif() + + # Extract the version, name, header archive and archive checksum + # from the file. This first extract is what defines / specifies the + # actual version number and name. + file(STRINGS + ${CHECKSUM_TARGET} HEADERS_CHECKSUM + REGEX ${HEADERS_MATCH} + LIMIT_COUNT 1 + ) + if(NOT HEADERS_CHECKSUM) + file(REMOVE ${TEMP}/CHECKSUM) + if(DEFINED ROOT) + file(REMOVE ${ROOT}/CHECKSUM) + endif() + message(FATAL_ERROR "Unable to extract header archive checksum") + endif() + string(REGEX MATCH ${HEADERS_MATCH} HEADERS_CHECKSUM ${HEADERS_CHECKSUM}) + set(HEADERS_CHECKSUM ${CMAKE_MATCH_1}) + set(NAME ${CMAKE_MATCH_2}) + if(CMAKE_MATCH_4 STREQUAL "headers") + set(VERSION ${CMAKE_MATCH_3}-${CMAKE_MATCH_4}) + else() + set(VERSION ${CMAKE_MATCH_3}) + endif() + set(HEADERS_ARCHIVE + ${CMAKE_MATCH_2}-${CMAKE_MATCH_3}-${CMAKE_MATCH_5}${CMAKE_MATCH_6} + ) + # Make sure that the root directory exists, and that the checksum + # file has been moved over from temp + if(DEFINED ROOT) + set(OLD_ROOT ${ROOT}) + endif() + set(ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/${VERSION}) + if(DEFINED OLD_ROOT AND NOT ROOT STREQUAL "${OLD_ROOT}") + file(REMOVE ${TEMP}/CHECKSUM) + file(REMOVE ${ROOT}/CHECKSUM) + message("${ROOT} -> ${OLD_ROOT}") + message(FATAL_ERROR "Version/Name mismatch") + endif() + file(MAKE_DIRECTORY ${ROOT}) + if(EXISTS ${TEMP}/CHECKSUM) + file(REMOVE ${ROOT}/CHECKSUM) + file(RENAME ${TEMP}/CHECKSUM ${ROOT}/CHECKSUM) + endif() + + # Now that its fully resolved, report the name and version of Node.exports being + # used + message(STATUS "NodeJS: Using ${NAME}, version ${VERSION}") + + # Download the headers for the version being used + # Theoretically, these could be found by searching the installed + # system, but in practice, this can be error prone. They're provided + # on the download servers, so just use the ones there. + if(NOT EXISTS ${ROOT}/include) + file(REMOVE ${TEMP}/${HEADERS_ARCHIVE}) + download_file( + ${URL}/${VERSION}/${HEADERS_ARCHIVE} + ${TEMP}/${HEADERS_ARCHIVE} + INACTIVITY_TIMEOUT 10 + EXPECTED_HASH ${CHECKTYPE}=${HEADERS_CHECKSUM} + STATUS HEADERS_STATUS + ) + list(GET HEADERS_STATUS 0 HEADERS_STATUS) + if(HEADER_STATUS GREATER 0) + file(REMOVE ${TEMP}/${HEADERS_ARCHIVE}) + message(FATAL_ERROR "Unable to download Node.js headers") + endif() + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xfz ${TEMP}/${HEADERS_ARCHIVE} + WORKING_DIRECTORY ${TEMP} + ) + + # This adapts the header extraction to support a number of different + # header archive contents in addition to the one used by the + # default Node.exports library + unset(NODEJS_HEADERS_PATH CACHE) + find_path(NODEJS_HEADERS_PATH + NAMES src include + PATHS + ${TEMP}/${NAME}-${VERSION}-headers + ${TEMP}/${NAME}-${VERSION} + ${TEMP}/${NODEJS_DEFAULT_NAME}-${VERSION}-headers + ${TEMP}/${NODEJS_DEFAULT_NAME}-${VERSION} + ${TEMP}/${NODEJS_DEFAULT_NAME} + ${TEMP}/${NODEJS_DEFAULT_NAME}_headers + ${TEMP} + NO_DEFAULT_PATH + ) + if(NOT NODEJS_HEADERS_PATH) + message(FATAL_ERROR "Unable to find extracted headers folder") + endif() + + # Move the headers into a standard location with a standard layout + file(REMOVE ${TEMP}/${HEADERS_ARCHIVE}) + file(REMOVE_RECURSE ${ROOT}/include) + if(EXISTS ${NODEJS_HEADERS_PATH}/include/node) + file(RENAME ${NODEJS_HEADERS_PATH}/include/node ${ROOT}/include) + elseif(EXISTS ${NODEJS_HEADERS_PATH}/src) + file(MAKE_DIRECTORY ${ROOT}/include) + if(NOT EXISTS ${NODEJS_HEADERS_PATH}/src) + file(REMOVE_RECURSE ${ROOT}/include) + message(FATAL_ERROR "Unable to find core headers") + endif() + file(COPY ${NODEJS_HEADERS_PATH}/src/ + DESTINATION ${ROOT}/include + ) + if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/uv/include) + file(REMOVE_RECURSE ${ROOT}/include) + message(FATAL_ERROR "Unable to find libuv headers") + endif() + file(COPY ${NODEJS_HEADERS_PATH}/deps/uv/include/ + DESTINATION ${ROOT}/include + ) + if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/v8/include) + file(REMOVE_RECURSE ${ROOT}/include) + message(FATAL_ERROR "Unable to find v8 headers") + endif() + file(COPY ${NODEJS_HEADERS_PATH}/deps/v8/include/ + DESTINATION ${ROOT}/include + ) + if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/zlib) + file(REMOVE_RECURSE ${ROOT}/include) + message(FATAL_ERROR "Unable to find zlib headers") + endif() + file(COPY ${NODEJS_HEADERS_PATH}/deps/zlib/ + DESTINATION ${ROOT}/include + ) + endif() + file(REMOVE_RECURSE ${NODEJS_HEADERS_PATH}) + unset(NODEJS_HEADERS_PATH CACHE) + endif() + + # Only download the libraries on windows, since its the only place + # its necessary. Note, this requires rerunning CMake if moving + # a module from one platform to another (should happen automatically + # with most generators) + if(WIN32) + # Download the win32 library for linking + file(STRINGS + ${ROOT}/CHECKSUM LIB32_CHECKSUM + LIMIT_COUNT 1 + REGEX ${LIB32_MATCH} + ) + if(NOT LIB32_CHECKSUM) + message(FATAL_ERROR "Unable to extract x86 library checksum") + endif() + string(REGEX MATCH ${LIB32_MATCH} LIB32_CHECKSUM ${LIB32_CHECKSUM}) + set(LIB32_CHECKSUM ${CMAKE_MATCH_1}) + set(LIB32_PATH win-x86) + set(LIB32_NAME ${CMAKE_MATCH_4}${CMAKE_MATCH_5}) + set(LIB32_TARGET ${CMAKE_MATCH_2}${CMAKE_MATCH_3}${LIB32_NAME}) + if(NOT EXISTS ${ROOT}/${LIB32_PATH}) + file(REMOVE_RECURSE ${TEMP}/${LIB32_PATH}) + download_file( + ${URL}/${VERSION}/${LIB32_TARGET} + ${TEMP}/${LIB32_PATH}/${LIB32_NAME} + INACTIVITY_TIMEOUT 10 + EXPECTED_HASH ${CHECKTYPE}=${LIB32_CHECKSUM} + STATUS LIB32_STATUS + ) + list(GET LIB32_STATUS 0 LIB32_STATUS) + if(LIB32_STATUS GREATER 0) + message(FATAL_ERROR + "Unable to download Node.js windows library (32-bit)" + ) + endif() + file(REMOVE_RECURSE ${ROOT}/${LIB32_PATH}) + file(MAKE_DIRECTORY ${ROOT}/${LIB32_PATH}) + file(RENAME + ${TEMP}/${LIB32_PATH}/${LIB32_NAME} + ${ROOT}/${LIB32_PATH}/${LIB32_NAME} + ) + file(REMOVE_RECURSE ${TEMP}/${LIB32_PATH}) + endif() + + # Download the win64 library for linking + file(STRINGS + ${ROOT}/CHECKSUM LIB64_CHECKSUM + LIMIT_COUNT 1 + REGEX ${LIB64_MATCH} + ) + if(NOT LIB64_CHECKSUM) + message(FATAL_ERROR "Unable to extract x64 library checksum") + endif() + string(REGEX MATCH ${LIB64_MATCH} LIB64_CHECKSUM ${LIB64_CHECKSUM}) + set(LIB64_CHECKSUM ${CMAKE_MATCH_1}) + set(LIB64_PATH win-x64) + set(LIB64_NAME ${CMAKE_MATCH_4}${CMAKE_MATCH_5}) + set(LIB64_TARGET ${CMAKE_MATCH_2}${CMAKE_MATCH_3}${LIB64_NAME}) + if(NOT EXISTS ${ROOT}/${LIB64_PATH}) + file(REMOVE_RECURSE ${TEMP}/${LIB64_PATH}) + download_file( + ${URL}/${VERSION}/${LIB64_TARGET} + ${TEMP}/${LIB64_PATH}/${LIB64_NAME} + INACTIVITY_TIMEOUT 10 + EXPECTED_HASH ${CHECKTYPE}=${LIB64_CHECKSUM} + STATUS LIB64_STATUS + ) + list(GET LIB64_STATUS 0 LIB64_STATUS) + if(LIB64_STATUS GREATER 0) + message(FATAL_ERROR + "Unable to download Node.js windows library (64-bit)" + ) + endif() + file(REMOVE_RECURSE ${ROOT}/${LIB64_PATH}) + file(MAKE_DIRECTORY ${ROOT}/${LIB64_PATH}) + file(RENAME + ${TEMP}/${LIB64_PATH}/${LIB64_NAME} + ${ROOT}/${LIB64_PATH}/${LIB64_NAME} + ) + file(REMOVE_RECURSE ${TEMP}/${LIB64_PATH}) + endif() + endif() + + # The downloaded headers should always be set for inclusion + list(APPEND INCLUDE_DIRS ${ROOT}/include) + + # Look for the NAN module, and add it to the includes + find_nodejs_module( + nan + .. + NODEJS_NAN_DIR + ) + if(NODEJS_NAN_DIR) + list(APPEND INCLUDE_DIRS ${NODEJS_NAN_DIR}) + endif() + + # Under windows, we need a bunch of libraries (due to the way + # dynamic linking works) + if(WIN32) + # Generate and use a delay load hook to allow the node binary + # name to be changed while still loading native modules + set(DELAY_LOAD_HOOK ${CMAKE_CURRENT_BINARY_DIR}/win_delay_load_hook.c) + nodejs_generate_delayload_hook(${DELAY_LOAD_HOOK}) + set(SOURCES ${DELAY_LOAD_HOOK}) + + # Necessary flags to get delayload working correctly + list(APPEND LINK_FLAGS + "-IGNORE:4199" + "-DELAYLOAD:iojs.exe" + "-DELAYLOAD:node.exe" + "-DELAYLOAD:node.dll" + ) + + # Core system libraries used by node + list(APPEND LIBRARIES + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib + odbc32.lib Shlwapi.lib DelayImp.lib + ) + + # Also link to the node stub itself (downloaded above) + if(CMAKE_CL_64) + list(APPEND LIBRARIES ${ROOT}/${LIB64_PATH}/${LIB64_NAME}) + else() + list(APPEND LIBRARIES ${ROOT}/${LIB32_PATH}/${LIB32_NAME}) + endif() + else() + # Non-windows platforms should use these flags + list(APPEND DEFINITIONS _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64) + endif() + + # Special handling for OSX / clang to allow undefined symbols + # Define is required by node on OSX + if(APPLE) + list(APPEND LINK_FLAGS "-undefined dynamic_lookup") + list(APPEND DEFINITIONS _DARWIN_USE_64_BIT_INODE=1) + endif() + + # Export all settings for use as arguments in the rest of the build + set(NODEJS_VERSION ${VERSION} PARENT_SCOPE) + set(NODEJS_SOURCES ${SOURCES} PARENT_SCOPE) + set(NODEJS_INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) + set(NODEJS_LIBRARIES ${LIBRARIES} PARENT_SCOPE) + set(NODEJS_LINK_FLAGS ${LINK_FLAGS} PARENT_SCOPE) + set(NODEJS_DEFINITIONS ${DEFINITIONS} PARENT_SCOPE) + + # Prevents this function from executing more than once + set(NODEJS_INIT TRUE PARENT_SCOPE) +endfunction() + +# Helper function for defining a node module +# After nodejs_init, all of the settings and dependencies necessary to do +# this yourself are defined, but this helps make sure everything is configured +# correctly. Feel free to use it as a model to do this by hand (or to +# tweak this configuration if you need something custom). +function(add_nodejs_module NAME) + # Validate name parameter (must be a valid C identifier) + string(MAKE_C_IDENTIFIER ${NAME} ${NAME}_SYMBOL_CHECK) + if(NOT "${NAME}" STREQUAL "${${NAME}_SYMBOL_CHECK}") + message(ERROR + "Module name must be a valid C identifier. " + "Suggested alternative: '${${NAME}_SYMBOL_CHECK}'" + ) + endif() + # Make sure node is initialized (variables set) before defining the module + if(NOT NODEJS_INIT) + message(FATAL_ERROR + "Node.js has not been initialized. " + "Call nodejs_init before adding any modules" + ) + endif() + # In order to match node-gyp, we need to build into type specific folders + # ncmake takes care of this, but be sure to set CMAKE_BUILD_TYPE yourself + # if invoking CMake directly + if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + message(FATAL_ERROR + "Configuration type must be specified. " + "Set CMAKE_BUILD_TYPE or use a different generator" + ) + endif() + + # A node module is a shared library + add_library(${NAME} SHARED ${NODEJS_SOURCES} ${ARGN}) + # Add compiler defines for the module + # Two helpful ones: + # MODULE_NAME must match the name of the build library, define that here + # ${NAME}_BUILD is for symbol visibility under windows + string(TOUPPER "${NAME}_BUILD" ${NAME}_BUILD_DEF) + target_compile_definitions(${NAME} + PRIVATE MODULE_NAME=${NAME} + PRIVATE ${${NAME}_BUILD_DEF} + PUBLIC ${NODEJS_DEFINITIONS} + ) + # This properly defines includes for the module + target_include_directories(${NAME} PUBLIC ${NODEJS_INCLUDE_DIRS}) + + # Add link flags to the module + target_link_libraries(${NAME} ${NODEJS_LIBRARIES}) + + # Set required properties for the module to build properly + # Correct naming, symbol visiblity and C++ standard + set_target_properties(${NAME} PROPERTIES + OUTPUT_NAME ${NAME} + PREFIX "" + SUFFIX ".node" + MACOSX_RPATH ON + C_VISIBILITY_PRESET hidden + CXX_VISIBILITY_PRESET hidden + POSITION_INDEPENDENT_CODE TRUE + CMAKE_CXX_STANDARD_REQUIRED TRUE + CXX_STANDARD 11 + ) + + # Handle link flag cases properly + # When there are link flags, they should be appended to LINK_FLAGS with space separation + # If the list is emtpy (true for most *NIX platforms), this is a no-op + foreach(NODEJS_LINK_FLAG IN LISTS NODEJS_LINK_FLAGS) + set_property(TARGET ${NAME} APPEND_STRING PROPERTY LINK_FLAGS " ${NODEJS_LINK_FLAG}") + endforeach() + + # Make sure we're buiilding in a build specific output directory + # Only necessary on single-target generators (Make, Ninja) + # Multi-target generators do this automatically + # This (luckily) mirrors node-gyp conventions + if(NOT CMAKE_CONFIGURATION_TYPES) + set_property(TARGET ${NAME} PROPERTY + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BUILD_TYPE} + ) + endif() +endfunction() diff --git a/native/codec/.gitignore b/native/codec/.gitignore new file mode 100644 index 0000000..aed917c --- /dev/null +++ b/native/codec/.gitignore @@ -0,0 +1,14 @@ +# Default ignored files +/.idea/shelf/ +/.idea/workspace.xml + +# Datasource local storage ignored files +/.idea/dataSources/ +dataSources.local.xml + +# Editor-based HTTP Client requests +/.idea/httpRequests/ +rest-client.private.env.json +http-client.private.env.json + +cmake-build-*/ \ No newline at end of file diff --git a/native/codec/CMakeLists.txt b/native/codec/CMakeLists.txt new file mode 100644 index 0000000..43def4f --- /dev/null +++ b/native/codec/CMakeLists.txt @@ -0,0 +1,60 @@ +set(MODULE_NAME "teaclient_codec") +set(CMAKE_MODULE_DIR "${CMAKE_SOURCE_DIR}/codec") + +set(SOURCE_FILES + binding.cc + codec/NativeCodec.cpp + codec/OpusCodec.cpp + codec/SpeexCodec.cpp + codec/CeltCodec.cpp +) + +add_nodejs_module(${MODULE_NAME} ${SOURCE_FILES}) + +if(MSVC) + set(OPUS_LIBRARY_PATH "${CMAKE_MODULE_DIR}/libraries/generated/opus/lib/opus.lib") + set(SPEEX_LIBRARY_PATH "${CMAKE_MODULE_DIR}/libraries/generated/speex/lib/libspeex.lib") +else() + set(OPUS_LIBRARY_PATH "${CMAKE_MODULE_DIR}/libraries/generated/opus/lib/libopus.a") + set(SPEEX_LIBRARY_PATH "${CMAKE_MODULE_DIR}/libraries/generated/speex/lib/libspeex.a") + set(CELT_LIBRARY_PATH "${CMAKE_MODULE_DIR}/libraries/generated/celt/lib/libcelt0.a") +endif() + +#Detect opus +if(EXISTS "${CMAKE_MODULE_DIR}/libraries/generated/opus/include" AND EXISTS ${OPUS_LIBRARY_PATH}) + set(HAVE_OPUS ON) + + add_definitions(-DHAVE_OPUS) + include_directories(${CMAKE_MODULE_DIR}/libraries/generated/opus/include) + target_link_libraries(${MODULE_NAME} ${OPUS_LIBRARY_PATH}) +else() + message(WARNING "Missing opus libraries. Building without opus support!\n" "Build opus with the build script given within the libraries foulder") +endif() + +#Detect speex +if(EXISTS "${CMAKE_MODULE_DIR}/libraries/generated/speex/include" AND EXISTS ${SPEEX_LIBRARY_PATH}) + set(HAVE_SPEEX ON) + + add_definitions(-DHAVE_SPEEX) + include_directories(${CMAKE_MODULE_DIR}/libraries/generated/speex/include) + target_link_libraries(${MODULE_NAME} ${SPEEX_LIBRARY_PATH}) +else() + message(WARNING "Missing speex libraries. Building without speex support!\n" "Build speex with the build script given within the libraries foulder") +endif() + +#Detect celt +set(BUILD_CELT OFF) +if(EXISTS "${CMAKE_MODULE_DIR}/libraries/generated/celt/include" AND EXISTS "${CELT_LIBRARY_PATH}" AND BUILD_CELT) + set(HAVE_CELT ON) + + add_definitions(-DHAVE_CELT) + include_directories(${CMAKE_MODULE_DIR}/libraries/generated/celt/include) + + target_link_libraries(${MODULE_NAME} ${CELT_LIBRARY_PATH}) +else() + message(WARNING "Missing celt libraries. Building without celt support!\n" "Build celt with the build script given within the libraries foulder") +endif() + +if(HAVE_OPUS AND HAVE_CELT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-no-whole-archive,--allow-multiple-definition") +endif() \ No newline at end of file diff --git a/native/codec/binding.cc b/native/codec/binding.cc new file mode 100644 index 0000000..1495a86 --- /dev/null +++ b/native/codec/binding.cc @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include "codec/NativeCodec.h" + +using namespace std; + + +tc::WorkerPool* tc::codec_workers = nullptr; + +NAN_METHOD(finalize) { + auto pool = tc::codec_workers; + if(!pool) return; + + tc::codec_workers = nullptr; + + pool->finalize(); + delete pool; +} + +NAN_MODULE_INIT(init) { + tc::codec_workers = new tc::WorkerPool(); + tc::codec_workers->initialize(); + + Nan::Set(target, Nan::New("new_instance").ToLocalChecked(), Nan::GetFunction(Nan::New(tc::NativeCodec::NewInstance)).ToLocalChecked()); + tc::NativeCodec::Init(target); + tc::NativeCodec::CodecType::Init(target); +} + +NODE_MODULE(MODULE_NAME, init) \ No newline at end of file diff --git a/native/codec/codec/CeltCodec.cpp b/native/codec/codec/CeltCodec.cpp new file mode 100644 index 0000000..60e0703 --- /dev/null +++ b/native/codec/codec/CeltCodec.cpp @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include "CeltCodec.h" +#include "NativeCodec.h" +#include "NanException.h" +#include "NanEventCallback.h" + +using namespace std; +using namespace std::chrono; +using namespace tc; +using namespace v8; +using namespace Nan; + +bool CeltCodec::supported() { +#ifdef HAVE_CELT + return true; +#endif + return false; +} + +#ifdef HAVE_CELT + +CeltCodec::CeltCodec(NativeCodec::CodecType::value type) : NativeCodec(type) { + cout << "Allocate celt instance" << endl; + +} + +CeltCodec::~CeltCodec() { + cout << "Free celt instance" << endl; + + if(this->decoder || this->encoder) { + NAN_THROW_EXCEPTION(Error, "please finalize before releasing!"); + return; + } +} + +NAN_METHOD(CeltCodec::initialize) { + lock_guard lock(this->coder_lock); + + //(≥20kHz; sample rates from 8 kHz to 48 kHz) + int error = 0; + + int sample_rate = 48000; + this->encoder = celt_encoder_create(sample_rate, this->channels, &error); + if(!this->encoder || error) { + cout << this->encoder << " - " << error << endl; + if(this->encoder) + celt_encoder_destroy(this->encoder); + this->encoder = nullptr; + + NAN_THROW_EXCEPTION(Error, ("Failed to create encoder (" + to_string(error) + ")").c_str()); + return; + } + + this->decoder = celt_decoder_create(sample_rate, this->channels, &error); + if(!this->decoder || error) { + if(this->decoder) + celt_decoder_destroy(this->decoder); + this->decoder = nullptr; + if(this->encoder) + celt_encoder_destroy(this->encoder); + + this->encoder = nullptr; + NAN_THROW_EXCEPTION(Error, ("Failed to create decoder (" + to_string(error) + ")").c_str()); + return; + } +} + +NAN_METHOD(CeltCodec::finalize) { + lock_guard lock(this->coder_lock); + + if(this->encoder) { + celt_encoder_destroy(this->encoder); + this->encoder = nullptr; + } + + if(this->decoder) { + celt_decoder_destroy(this->decoder); + this->decoder = nullptr; + } +} + + +NAN_METHOD(CeltCodec::encode) { + Nan::HandleScope scope; + + if(!info[0]->IsArrayBuffer()) { + NAN_THROW_EXCEPTION(Error, "First argument isn't an array buffer!"); + return; + } + + auto js_buffer = info[0].As()->GetContents(); + auto buffer = make_unique(max(js_buffer.ByteLength(), 256UL)); + buffer->length = js_buffer.ByteLength(); + memcpy(buffer->memory, js_buffer.Data(), js_buffer.ByteLength()); + + auto callback_success = make_unique(info[1].As()); + auto callback_error = make_unique(info[2].As()); + + auto codec = make_unique>(info.GetIsolate(), info.Holder()); + auto callback = Nan::async_callback([callback_success = move(callback_success), callback_error = move(callback_error), codec = move(codec)](std::unique_ptr result, std::string error) { + Nan::HandleScope scope; + if(result) { + auto _buffer = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), result->length); + memcpy(_buffer->GetContents().Data(), result->memory, result->length); + + Local argv[] = { _buffer }; //_buffer + callback_success->Call(1, argv); + } else { + Local argv[] = { Nan::New(error).ToLocalChecked() }; //error + callback_error->Call(1, argv); + } + codec->Reset(); + }).option_destroyed_execute(true); + + auto frame_size = buffer->length / sizeof(float) / this->channels; + if(frame_size != 64 && frame_size != 128 && frame_size != 256 && frame_size != 512) { + NAN_THROW_EXCEPTION(Error, ("Invalid frame size (" + to_string(frame_size) + "). Only allow 64, 128, 256, 512bytes").c_str()); + return; + } + + tc::codec_workers->enqueue_task( + [this, callback, buffer = move(buffer)]() mutable { + { + lock_guard lock(this->coder_lock); + if(!this->encoder) { + callback(nullptr, "Please initialize first!"); + return; + } + + auto nbytes = celt_encode_float(this->encoder, (float*) buffer->memory, buffer->length / sizeof(float) / this->channels, (u_char*) buffer->memory, buffer->allocated_length); + if(nbytes < 0) { + callback(nullptr, "Invalid encode return code (" + to_string(nbytes) + ")"); + return; + } + + buffer->length = nbytes; + } + callback(move(buffer), ""); + } + ); +} + +NAN_METHOD(CeltCodec::decode) { + Nan::HandleScope scope; + + if(!info[0]->IsArrayBuffer()) { + NAN_THROW_EXCEPTION(Error, "First argument isn't an array buffer!"); + return; + } + + auto js_buffer = info[0].As()->GetContents(); + auto buffer = make_unique(max(js_buffer.ByteLength(), this->max_frame_size * this->channels * sizeof(float))); + buffer->length = js_buffer.ByteLength(); + memcpy(buffer->memory, js_buffer.Data(), js_buffer.ByteLength()); + + auto callback_success = make_unique(info[1].As()); + auto callback_error = make_unique(info[2].As()); + + auto codec = make_unique>(info.GetIsolate(), info.Holder()); + auto callback = Nan::async_callback([callback_success = move(callback_success), callback_error = move(callback_error), codec = move(codec)](std::unique_ptr result, std::string error) { + Nan::HandleScope scope; + if(result) { + auto _buffer = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), result->length); + memcpy(_buffer->GetContents().Data(), result->memory, result->length); + Local argv[] = { _buffer }; + callback_success->Call(1, argv); + } else { + Local argv[] = { Nan::New(error).ToLocalChecked() }; + callback_error->Call(1, argv); + } + codec->Reset(); + }).option_destroyed_execute(true); + + tc::codec_workers->enqueue_task( + [this, callback, buffer = move(buffer)]() mutable { + int result; + + { + lock_guard lock(this->coder_lock); + if(!this->decoder) { + callback(nullptr, "Please initialize first!"); + return; + } + + auto code = celt_decode_float(this->decoder, (u_char*) buffer->memory, buffer->length, (float*) buffer->memory, buffer->allocated_length / sizeof(float) / this->channels); + if(code < 0) { + callback(nullptr, "Invalid decode return code (" + to_string(code) + ")"); + return; + } + cout << code << endl; + + buffer->length = this->channels * this->max_frame_size * sizeof(float); + } + + callback(move(buffer), ""); + } + ); +} + +#endif \ No newline at end of file diff --git a/native/codec/codec/CeltCodec.h b/native/codec/codec/CeltCodec.h new file mode 100644 index 0000000..137dab6 --- /dev/null +++ b/native/codec/codec/CeltCodec.h @@ -0,0 +1,34 @@ +#pragma once + +#include "NativeCodec.h" + +#ifdef HAVE_CELT + #include +#endif + +namespace tc { + class NativeCodec; + + + class CeltCodec : public NativeCodec { + public: + static bool supported(); + +#ifdef HAVE_CELT + explicit CeltCodec(CodecType::value type); + virtual ~CeltCodec(); + + virtual NAN_METHOD(initialize); + virtual NAN_METHOD(finalize); + virtual NAN_METHOD(encode); + virtual NAN_METHOD(decode); + private: + std::mutex coder_lock; + int max_frame_size = 512; + int channels = 1; /* fixed */ + + CELTEncoder* encoder = nullptr; + CELTDecoder* decoder = nullptr; +#endif + }; +} \ No newline at end of file diff --git a/native/codec/codec/NativeCodec.cpp b/native/codec/codec/NativeCodec.cpp new file mode 100644 index 0000000..a54838f --- /dev/null +++ b/native/codec/codec/NativeCodec.cpp @@ -0,0 +1,205 @@ +#include +#include +#include +#include "NativeCodec.h" +#include "OpusCodec.h" +#include "SpeexCodec.h" +#include "CeltCodec.h" +#include "NanException.h" +#include + +using namespace std; +using namespace std::chrono; +using namespace tc; +using namespace v8; +using namespace Nan; + +#define DEFINE_ENUM_ENTRY(name, value) \ + Nan::ForceSet(types, Nan::New(name).ToLocalChecked(), Nan::New(value), static_cast(ReadOnly|DontDelete)); \ + //Nan::ForceSet(types, Nan::New(value), Nan::New(name).ToLocalChecked(), static_cast(ReadOnly|DontDelete)); + +NAN_MODULE_INIT(NativeCodec::CodecType::Init) { + auto types = Nan::New(); + + DEFINE_ENUM_ENTRY("OPUS_VOICE", CodecType::OPUS_VOICE); + DEFINE_ENUM_ENTRY("OPUS_MUSIC", CodecType::OPUS_MUSIC); + DEFINE_ENUM_ENTRY("SPEEX_NARROWBAND", CodecType::SPEEX_NARROWBAND); + DEFINE_ENUM_ENTRY("SPEEX_WIDEBAND", CodecType::SPEEX_WIDEBAND); + DEFINE_ENUM_ENTRY("SPEEX_ULTRA_WIDEBAND", CodecType::SPEEX_ULTRA_WIDEBAND); + DEFINE_ENUM_ENTRY("CELT_MONO", CodecType::CELT_MONO); + + Nan::Set(target, Nan::New("CodecTypes").ToLocalChecked(), types); + Nan::Set(target, Nan::New("codec_supported").ToLocalChecked(), Nan::New(NativeCodec::CodecType::supported)); +} + +NAN_METHOD(NativeCodec::CodecType::supported) { + if(!info[0]->IsNumber()) { + NAN_THROW_EXCEPTION(Error, "Argument 0 shall be a number!"); + return; + } + + auto type = (CodecType::value) Nan::To(info[0]).FromJust(); + if(type == CodecType::OPUS_MUSIC || type == CodecType::OPUS_VOICE) { + info.GetReturnValue().Set(OpusCodec::supported()); + } else if(type == CodecType::SPEEX_NARROWBAND || type == CodecType::SPEEX_WIDEBAND || type == CodecType::SPEEX_ULTRA_WIDEBAND) { + info.GetReturnValue().Set(SpeexCodec::supported()); + } else if(type == CodecType::CELT_MONO) { + info.GetReturnValue().Set(CeltCodec::supported()); + } else { + NAN_THROW_EXCEPTION(Error, "Invalid type!"); + return; + } +} + +NAN_MODULE_INIT(NativeCodec::Init) { + auto klass = New(NewInstance); + klass->SetClassName(Nan::New("NativeCodec").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "decode", NativeCodec::function_decode); + Nan::SetPrototypeMethod(klass, "encode", NativeCodec::function_encode); + Nan::SetPrototypeMethod(klass, "initialize", NativeCodec::function_initialize); + Nan::SetPrototypeMethod(klass, "finalize", NativeCodec::function_finalize); + + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); + //Nan::Set(target, Nan::New("NativeCodec").ToLocalChecked(), Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(NativeCodec::NewInstance) { + if (info.IsConstructCall()) { + if(!info[0]->IsNumber()) { + NAN_THROW_EXCEPTION(Error, "Argument 0 shall be a number!"); + return; + } + + auto type = (CodecType::value) Nan::To(info[0]).FromJust(); + std::unique_ptr instance; + if(type == CodecType::OPUS_MUSIC || type == CodecType::OPUS_VOICE) { + #ifdef HAVE_OPUS + instance = make_unique(type); + #endif + } else if(type == CodecType::SPEEX_NARROWBAND || type == CodecType::SPEEX_WIDEBAND || type == CodecType::SPEEX_ULTRA_WIDEBAND) { + #ifdef HAVE_SPEEX + instance = make_unique(type); + #endif + } else if(type == CodecType::CELT_MONO) { + #ifdef HAVE_CELT + instance = make_unique(type); + #endif + } else { + NAN_THROW_EXCEPTION(Error, "Invalid type!"); + return; + } + if(!instance) { + NAN_THROW_EXCEPTION(Error, "Target codec isn't supported!"); + return; + } + instance.release()->Wrap(info.This()); + + Nan::Set(info.This(), New("type").ToLocalChecked(), New(type)); + info.GetReturnValue().Set(info.This()); + } else { + const int argc = 1; + v8::Local argv[argc] = {info[0]}; + v8::Local cons = Nan::New(constructor()); + + Nan::TryCatch try_catch; + auto result = Nan::NewInstance(cons, argc, argv); + if(try_catch.HasCaught()) { + try_catch.ReThrow(); + return; + } + info.GetReturnValue().Set(result.ToLocalChecked()); + } +} + +NAN_METHOD(NativeCodec::function_decode) { + if(info.Length() != 3) { + NAN_THROW_EXCEPTION(Error, "Invalid argument count!"); + return; + } + if(!info[0]->IsArrayBuffer() || !info[1]->IsFunction() || !info[2]->IsFunction()) { + NAN_THROW_EXCEPTION(Error, "Invalid argument types!"); + return; + } + + auto codec = ObjectWrap::Unwrap(info.Holder()); + codec->decode(info); +} + +NAN_METHOD(NativeCodec::function_encode) { + if(info.Length() != 3) { + NAN_THROW_EXCEPTION(Error, "Invalid argument count!"); + return; + } + if(!info[0]->IsArrayBuffer() || !info[1]->IsFunction() || !info[2]->IsFunction()) { + NAN_THROW_EXCEPTION(Error, "Invalid argument types!"); + return; + } + + auto codec = ObjectWrap::Unwrap(info.Holder()); + codec->encode(info); +} + +NAN_METHOD(NativeCodec::function_initialize) { + auto codec = ObjectWrap::Unwrap(info.Holder()); + codec->initialize(info); +} +NAN_METHOD(NativeCodec::function_finalize) { + auto codec = ObjectWrap::Unwrap(info.Holder()); + codec->finalize(info); +} + +NativeCodec::NativeCodec(tc::NativeCodec::CodecType::value type) : type(type) {} +NativeCodec::~NativeCodec() {} + + +WorkerPool::WorkerPool() {} +WorkerPool::~WorkerPool() {} + +void WorkerPool::initialize() { + assert(!this->_running); + + this->_running = true; + this->worker = thread([&]{ + while(this->_running) { + function worker; + { + unique_lock lock(this->worker_lock); + this->worker_wait.wait_for(lock, minutes(1), [&]{ return !this->_running || !this->tasks.empty(); }); + if(!this->_running) break; + if(this->tasks.empty()) continue; + + worker = move(this->tasks.front()); + this->tasks.pop_front(); + } + + try { + worker(); + } catch(std::exception& ex) { + cerr << "failed to invoke opus worker! message: " << ex.what() << endl; + } catch (...) { + cerr << "failed to invoke opus worker!" << endl; + } + } + }); +#ifndef WIN32 + auto worker_handle = this->worker.native_handle(); + pthread_setname_np(worker_handle, "Codec Worker"); +#endif +} + +void WorkerPool::finalize() { + this->_running = false; + this->worker_wait.notify_all(); + this->tasks.clear(); + + if(this->worker.joinable()) + this->worker.join(); +} + +void WorkerPool::enqueue_task(std::function task) { + lock_guard lock(this->worker_lock); + this->tasks.push_back(std::move(task)); + this->worker_wait.notify_one(); +} \ No newline at end of file diff --git a/native/codec/codec/NativeCodec.h b/native/codec/codec/NativeCodec.h new file mode 100644 index 0000000..9ba2a50 --- /dev/null +++ b/native/codec/codec/NativeCodec.h @@ -0,0 +1,95 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace tc { + struct WorkerPool { + public: + WorkerPool(); + virtual ~WorkerPool(); + + void initialize(); + void finalize(); + + void enqueue_task(std::function /* function */); + + template + void enqueue_task(T&& closure) { + auto handle = std::make_shared(std::forward(closure)); + this->enqueue_task(std::function([handle]{ (*handle)(); })); + } + + private: + bool _running = false; + + std::thread worker; + std::mutex worker_lock; + std::condition_variable worker_wait; + + std::deque> tasks; + }; + extern WorkerPool* codec_workers; + + struct Chunk { + char* memory; + size_t length; + size_t allocated_length; + + Chunk(size_t length) { + memory = (char*) malloc(length); + this->allocated_length = length; + this->length = 0; + } + + ~Chunk() { + free(memory); + } + }; + + class NativeCodec : public Nan::ObjectWrap { + public: + struct CodecType { + enum value { + SPEEX_NARROWBAND, + SPEEX_WIDEBAND, + SPEEX_ULTRA_WIDEBAND, + CELT_MONO, + OPUS_VOICE, + OPUS_MUSIC + }; + + static NAN_MODULE_INIT(Init); + static NAN_METHOD(supported); + }; + + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + explicit NativeCodec(CodecType::value type); + virtual ~NativeCodec(); + + virtual NAN_METHOD(initialize) = 0; + virtual NAN_METHOD(finalize) = 0; + + virtual NAN_METHOD(encode) = 0; + virtual NAN_METHOD(decode) = 0; + + static NAN_METHOD(function_encode); + static NAN_METHOD(function_decode); + static NAN_METHOD(function_initialize); + static NAN_METHOD(function_finalize); + + protected: + CodecType::value type; + + }; +} \ No newline at end of file diff --git a/native/codec/codec/OpusCodec.cpp b/native/codec/codec/OpusCodec.cpp new file mode 100644 index 0000000..af9c34a --- /dev/null +++ b/native/codec/codec/OpusCodec.cpp @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include "OpusCodec.h" +#include "NativeCodec.h" +#include "NanException.h" +#include "NanEventCallback.h" + +using namespace std; +using namespace std::chrono; +using namespace tc; +using namespace v8; +using namespace Nan; + +bool OpusCodec::supported() { +#ifdef HAVE_OPUS + return true; +#endif + return false; +} + +#ifdef HAVE_OPUS +OpusCodec::OpusCodec(NativeCodec::CodecType::value type) : NativeCodec(type) { + cout << "New opus instance" << endl; + + this->sampling_rate = 48000; + this->frames = 960; + if(type == CodecType::OPUS_MUSIC) { + this->channels = 2; + } else { + this->channels = 1; + } +} + +OpusCodec::~OpusCodec() { + cout << "Free opus instance" << endl; + + if(this->decoder || this->encoder) { + NAN_THROW_EXCEPTION(Error, "please finalize before releasing!"); + return; + } +} + +NAN_METHOD(OpusCodec::initialize) { + int error = 0; + lock_guard lock(this->coder_lock); + + this->encoder = opus_encoder_create(this->sampling_rate, this->channels, this->type == CodecType::OPUS_MUSIC ? OPUS_APPLICATION_AUDIO : OPUS_APPLICATION_VOIP, &error); + if(!this->encoder || error) { + NAN_THROW_EXCEPTION(Error, ("Failed to create encoder (" + to_string(error) + ")").c_str()); + return; + } + + this->decoder = opus_decoder_create(this->sampling_rate, this->channels, &error); + if(!this->encoder || error) { + opus_encoder_destroy(this->encoder); + this->encoder = nullptr; + + NAN_THROW_EXCEPTION(Error, ("Failed to create decoder (" + to_string(error) + ")").c_str()); + return; + } +} + +NAN_METHOD(OpusCodec::finalize) { + lock_guard lock(this->coder_lock); + + opus_encoder_destroy(this->encoder); + this->encoder = nullptr; + + opus_decoder_destroy(this->decoder); + this->decoder = nullptr; +} + +NAN_METHOD(OpusCodec::encode) { + Nan::HandleScope scope; + + if(info.Length() != 3 || !info[0]->IsArrayBuffer()) { + NAN_THROW_EXCEPTION(Error, "Invalid arguments"); + return; + } + + auto js_buffer = info[0].As()->GetContents(); + auto buffer = make_unique(max(js_buffer.ByteLength(), 256UL)); + buffer->length = js_buffer.ByteLength(); + memcpy(buffer->memory, js_buffer.Data(), js_buffer.ByteLength()); + + auto callback_success = make_unique(info[1].As()); + auto callback_error = make_unique(info[2].As()); + + auto codec = make_unique>(info.GetIsolate(), info.Holder()); + auto callback = Nan::async_callback([callback_success = move(callback_success), callback_error = move(callback_error), codec = move(codec)](std::unique_ptr result, std::string error) { + if(result) { + auto _buffer = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), result->length); + memcpy(_buffer->GetContents().Data(), result->memory, result->length); + + Local argv[] = { _buffer }; //_buffer + callback_success->Call(1, argv); + } else { + Local argv[] = { Nan::New(error).ToLocalChecked() }; //error + callback_error->Call(1, argv); + } + codec->Reset(); + }).option_destroyed_execute(true); + + tc::codec_workers->enqueue_task( + [this, callback, buffer = move(buffer)]() mutable { + int result; + { + lock_guard lock(this->coder_lock); + if(!this->encoder) { + callback(nullptr, "Please initialize first!"); + return; + } + + if(this->channels == 1) { + result = opus_encode_float(this->encoder, (float*) buffer->memory, (int) (buffer->length / sizeof(float) / this->channels), (u_char*) buffer->memory, (opus_int32) buffer->allocated_length); + } else { + auto samples = buffer->length / sizeof(float) / this->channels; + float* local_buffer = new float[samples * this->channels]; + for(size_t channel = 0; channel < this->channels; channel++) + for(size_t sample = 0; sample < samples; sample++) + local_buffer[sample * this->channels + channel] = ((float*) buffer->memory)[channel * samples + sample]; + + result = opus_encode_float(this->encoder, local_buffer, samples, (u_char*) buffer->memory, (opus_int32) buffer->allocated_length); + delete[] local_buffer; + } + } + + if(result <= 0) { + callback(nullptr, "Invalid return code (" + to_string(result) + ")"); + } else { + buffer->length = result; + callback(move(buffer), ""); + } + } + ); +} + +NAN_METHOD(OpusCodec::decode) { + Nan::HandleScope scope; + + if(!info[0]->IsArrayBuffer()) { + NAN_THROW_EXCEPTION(Error, "First argument isn't an array buffer!"); + return; + } + + auto js_buffer = info[0].As()->GetContents(); + auto buffer = make_unique(max(js_buffer.ByteLength(), this->channels * this->frames * sizeof(float))); + buffer->length = js_buffer.ByteLength(); + memcpy(buffer->memory, js_buffer.Data(), js_buffer.ByteLength()); + + auto callback_success = make_unique(info[1].As()); + auto callback_error = make_unique(info[2].As()); + + auto codec = make_unique>(info.GetIsolate(), info.Holder()); + auto callback = Nan::async_callback([callback_success = move(callback_success), callback_error = move(callback_error), codec = move(codec)](std::unique_ptr result, std::string error) { + Nan::HandleScope scope; + if(result) { + auto _buffer = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), result->length); + memcpy(_buffer->GetContents().Data(), result->memory, result->length); + Local argv[] = { _buffer }; + callback_success->Call(1, argv); + } else { + Local argv[] = { Nan::New(error).ToLocalChecked() }; + callback_error->Call(1, argv); + } + codec->Reset(); + }).option_destroyed_execute(true); + + tc::codec_workers->enqueue_task( + [this, buffer = move(buffer), callback]() mutable { + int result; + + { + lock_guard lock(this->coder_lock); + if(!this->decoder) { + callback(nullptr, "Please initialize first!"); + return; + } + + if(this->channels == 1) { + result = opus_decode_float(this->decoder, (u_char*) buffer->memory, (opus_int32) buffer->length, (float*) buffer->memory, this->frames, 0); + } else { + float* local_buffer = new float[this->frames * this->channels]; + result = opus_decode_float(this->decoder, (u_char*) buffer->memory, (opus_int32) buffer->length, (float*) local_buffer, this->frames, 0); + + for(size_t channel = 0; channel < this->channels; channel++) + for(size_t sample = 0; sample < result; sample++) + ((float*) buffer->memory)[channel * this->frames + sample] = local_buffer[sample * this->channels + channel]; + delete[] local_buffer; + } + } + + if(result <= 0) { + callback(nullptr, "Invalid return code (" + to_string(result) + ")"); + } else { + buffer->length = result * sizeof(float) * this->channels; + callback(move(buffer), ""); + } + } + ); +} +#endif \ No newline at end of file diff --git a/native/codec/codec/OpusCodec.h b/native/codec/codec/OpusCodec.h new file mode 100644 index 0000000..c432705 --- /dev/null +++ b/native/codec/codec/OpusCodec.h @@ -0,0 +1,33 @@ +#pragma once + +#include "NativeCodec.h" + +#ifdef HAVE_OPUS + #include +#endif + +namespace tc { + class NativeCodec; + + class OpusCodec : public NativeCodec { + public: + static bool supported(); +#ifdef HAVE_OPUS + explicit OpusCodec(CodecType::value type); + virtual ~OpusCodec(); + + virtual NAN_METHOD(initialize); + virtual NAN_METHOD(finalize); + virtual NAN_METHOD(encode); + virtual NAN_METHOD(decode); + private: + uint16_t sampling_rate = 0; + uint16_t frames = 0; + uint32_t channels = 0; + + std::mutex coder_lock; + OpusDecoder* decoder = nullptr; + OpusEncoder* encoder = nullptr; +#endif + }; +} \ No newline at end of file diff --git a/native/codec/codec/SpeexCodec.cpp b/native/codec/codec/SpeexCodec.cpp new file mode 100644 index 0000000..a8e2eaa --- /dev/null +++ b/native/codec/codec/SpeexCodec.cpp @@ -0,0 +1,234 @@ +#include +#include +#include +#include +#include "SpeexCodec.h" +#include "NativeCodec.h" +#include "NanException.h" +#include "NanEventCallback.h" + +using namespace std; +using namespace std::chrono; +using namespace tc; +using namespace v8; +using namespace Nan; + +bool SpeexCodec::supported() { +#ifdef HAVE_SPEEX + return true; +#endif + return false; +} + +#ifdef HAVE_SPEEX + +SpeexCodec::SpeexCodec(NativeCodec::CodecType::value type) : NativeCodec(type) { + cout << "Allocate speex instance" << endl; + +} + +SpeexCodec::~SpeexCodec() { + cout << "Free speex instance" << endl; + + if(this->decoder || this->encoder) { + NAN_THROW_EXCEPTION(Error, "please finalize before releasing!"); + return; + } +} + +NAN_METHOD(SpeexCodec::initialize) { + lock_guard lock(this->coder_lock); + + const SpeexMode* speex_mode = nullptr; + + if(this->type == CodecType::SPEEX_NARROWBAND) + speex_mode = &speex_nb_mode; + else if(this->type == CodecType::SPEEX_WIDEBAND) + speex_mode = &speex_wb_mode; + else if(this->type == CodecType::SPEEX_ULTRA_WIDEBAND) + speex_mode = &speex_uwb_mode; + + assert(speex_mode); + { + + this->encoder = speex_encoder_init(speex_mode); + if(!this->encoder) { + NAN_THROW_EXCEPTION(Error, "Failed to create encoder"); + return; + } + + /*Set the quality to 8 (15 kbps)*/ + int tmp = 8; //FIXME configurable + speex_encoder_ctl(this->encoder, SPEEX_SET_QUALITY, &tmp); + + speex_encoder_ctl(this->encoder, SPEEX_GET_FRAME_SIZE, &this->frame_size); + } + { + this->decoder = speex_decoder_init(speex_mode); + if(!this->decoder) { + speex_encoder_destroy(this->encoder); + this->encoder = nullptr; + + NAN_THROW_EXCEPTION(Error, "Failed to create decoder"); + return; + } + + int tmp = 1; //TODO What is this? + speex_decoder_ctl(this->decoder, SPEEX_SET_ENH, &tmp); + + + int tmp_frame_size; + speex_encoder_ctl(this->encoder, SPEEX_GET_FRAME_SIZE, &tmp_frame_size); + if(tmp_frame_size != this->frame_size) { + NAN_THROW_EXCEPTION(Error, "Decoder and encoder have different frame sizes!"); + return; + } + } + + speex_bits_init(&this->encoder_bits); + speex_bits_init(&this->decoder_bits); +} + +NAN_METHOD(SpeexCodec::finalize) { + lock_guard lock(this->coder_lock); + + if(this->encoder) { + speex_encoder_destroy(this->encoder); + this->encoder = nullptr; + + speex_bits_destroy(&this->encoder_bits); + } + + if(this->decoder) { + speex_decoder_destroy(this->decoder); + this->decoder = nullptr; + + speex_bits_destroy(&this->decoder_bits); + } +} + + +NAN_METHOD(SpeexCodec::encode) { + Nan::HandleScope scope; + + if(!info[0]->IsArrayBuffer()) { + NAN_THROW_EXCEPTION(Error, "First argument isn't an array buffer!"); + return; + } + + auto js_buffer = info[0].As()->GetContents(); + auto buffer = make_unique(max(js_buffer.ByteLength(), 256UL)); + buffer->length = js_buffer.ByteLength(); + memcpy(buffer->memory, js_buffer.Data(), js_buffer.ByteLength()); + + auto callback_success = make_unique(info[1].As()); + auto callback_error = make_unique(info[2].As()); + + auto codec = make_unique>(info.GetIsolate(), info.Holder()); + auto callback = Nan::async_callback([callback_success = move(callback_success), callback_error = move(callback_error), codec = move(codec)](std::unique_ptr result, std::string error) { + Nan::HandleScope scope; + if(result) { + auto _buffer = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), result->length); + memcpy(_buffer->GetContents().Data(), result->memory, result->length); + + Local argv[] = { _buffer }; //_buffer + callback_success->Call(1, argv); + } else { + Local argv[] = { Nan::New(error).ToLocalChecked() }; //error + callback_error->Call(1, argv); + } + codec->Reset(); + }).option_destroyed_execute(true); + + tc::codec_workers->enqueue_task( + [this, callback, buffer = move(buffer)]() mutable { + { + lock_guard lock(this->coder_lock); + if(!this->encoder) { + callback(nullptr, "Please initialize first!"); + return; + } + + if(buffer->length < this->frame_size * sizeof(float)) { + callback(nullptr, "Input buffer to short! Received " + to_string(buffer->length) + ", Expected " + to_string(this->frame_size * sizeof(float))); + return; + } + + for(size_t frame = 0; frame < this->frame_size; frame++) + ((float*) buffer->memory)[frame] *= 8000; //We want a range between 0 and 8000 + + speex_bits_reset(&this->encoder_bits); + speex_encode(this->encoder, (float*) buffer->memory, &this->encoder_bits); + auto nbytes = speex_bits_write(&this->encoder_bits, buffer->memory, buffer->allocated_length); + + if(nbytes < 0) { + callback(nullptr, "Invalid write?"); + return; + } + buffer->length = nbytes; + } + callback(move(buffer), ""); + } + ); +} + +NAN_METHOD(SpeexCodec::decode) { + Nan::HandleScope scope; + + if(!info[0]->IsArrayBuffer()) { + NAN_THROW_EXCEPTION(Error, "First argument isn't an array buffer!"); + return; + } + + auto js_buffer = info[0].As()->GetContents(); + auto buffer = make_unique(max(js_buffer.ByteLength(), this->frame_size * sizeof(float))); + buffer->length = js_buffer.ByteLength(); + memcpy(buffer->memory, js_buffer.Data(), js_buffer.ByteLength()); + + auto callback_success = make_unique(info[1].As()); + auto callback_error = make_unique(info[2].As()); + + auto codec = make_unique>(info.GetIsolate(), info.Holder()); + auto callback = Nan::async_callback([callback_success = move(callback_success), callback_error = move(callback_error), codec = move(codec)](std::unique_ptr result, std::string error) { + Nan::HandleScope scope; + if(result) { + auto _buffer = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), result->length); + memcpy(_buffer->GetContents().Data(), result->memory, result->length); + Local argv[] = { _buffer }; + callback_success->Call(1, argv); + } else { + Local argv[] = { Nan::New(error).ToLocalChecked() }; + callback_error->Call(1, argv); + } + codec->Reset(); + }).option_destroyed_execute(true); + + tc::codec_workers->enqueue_task( + [this, callback, buffer = move(buffer)]() mutable { + int result; + + { + lock_guard lock(this->coder_lock); + if(!this->decoder) { + callback(nullptr, "Please initialize first!"); + return; + } + + speex_bits_reset(&this->decoder_bits); + speex_bits_read_from(&this->decoder_bits, buffer->memory, buffer->length); + auto state = speex_decode(this->decoder, &this->decoder_bits, (float*) buffer->memory); + if(state != 0) { + callback(nullptr, "decode failed (" + to_string(state) + ")"); + return; + } + buffer->length = this->frame_size * sizeof(float); + for(size_t frame = 0; frame < this->frame_size; frame++) + ((float*) buffer->memory)[frame] /= 8000; //We want a range between 0 and 1 + } + + callback(move(buffer), ""); + } + ); +} + +#endif \ No newline at end of file diff --git a/native/codec/codec/SpeexCodec.h b/native/codec/codec/SpeexCodec.h new file mode 100644 index 0000000..80f1798 --- /dev/null +++ b/native/codec/codec/SpeexCodec.h @@ -0,0 +1,36 @@ +#pragma once + +#include "NativeCodec.h" + +#ifdef HAVE_SPEEX + #include +#endif + +namespace tc { + class NativeCodec; + + + class SpeexCodec : public NativeCodec { + public: + static bool supported(); + +#ifdef HAVE_SPEEX + explicit SpeexCodec(CodecType::value type); + virtual ~SpeexCodec(); + + virtual NAN_METHOD(initialize); + virtual NAN_METHOD(finalize); + virtual NAN_METHOD(encode); + virtual NAN_METHOD(decode); + private: + int frame_size = 0; + + //TODO are two bits really necessary? + std::mutex coder_lock; + SpeexBits encoder_bits; + void* encoder = nullptr; + SpeexBits decoder_bits; + void* decoder = nullptr; +#endif + }; +} \ No newline at end of file diff --git a/native/codec/libraries/.gitignore b/native/codec/libraries/.gitignore new file mode 100644 index 0000000..879fc2d --- /dev/null +++ b/native/codec/libraries/.gitignore @@ -0,0 +1,2 @@ +generated/ +opus/build \ No newline at end of file diff --git a/native/codec/libraries/build_celt.sh b/native/codec/libraries/build_celt.sh new file mode 100644 index 0000000..a0c846d --- /dev/null +++ b/native/codec/libraries/build_celt.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +cd $(dirname "$0") +install_directory="$(pwd)/generated/celt/" + +machine="$(uname -s)" +case "${machine}" in + Linux*) machine=Linux;; +# Darwin*) machine=Mac;; + MINGW*) machine=MinGW;; + *) machine="UNKNOWN:${machine}" +esac + +if [[ ${machine} == "UNKNOWN"* ]]; then + echo "Unknown platform ${machine}" + exit 1 +fi + +cd celt + +if [[ ${machine} == "Linux" ]]; then + if [[ ! -e configure ]]; then + echo "Generating configure file" + ./autogen.sh + if [[ $? -ne 0 ]]; then + echo "Failed to generate configure file" + exit 1 + fi + fi +fi + +windows_build="win32/VS2015/" +windows_build_type="x64" +if [[ ( ! -d build ) && ( ! -d "${windows_build}/${windows_build_type}" ) ]] || [[ "$1" == "rebuild" ]]; then + if [[ ${machine} == "Linux" ]]; then + if [[ -e build ]]; then + rm -r build + fi + mkdir build && cd build + + export CFLAGS="-fPIC" + ../configure --prefix="${install_directory}" --with-pic + if [[ $? -ne 0 ]]; then + echo "Failed to configure project!" + exit 1 + fi + + cd .. + elif [[ ${machine} == "MinGW" ]]; then + #Only cleanup last shit + if [[ -e "${windows_build}/${windows_build_type}" ]]; then + rm -r "${windows_build}/${windows_build_type}" + fi + fi +fi + +if [[ -e "${install_directory}" ]]; then + echo "deleting old install directory!" + rm -r "${install_directory}" + echo "rm -r '${install_directory}'" +fi + +if [[ ${machine} == "MinGW" ]]; then + saved_pwd=$(pwd) + cd "${windows_build}" + MSBuild.exe -p:Platform=x64 -property:Configuration=Release opus.vcxproj + if [[ $? -ne 0 ]]; then + echo "Failed to build celt!" + exit 1 + fi + cd ${saved_pwd} + + mkdir -p "${install_directory}/include/celt" + mkdir -p "${install_directory}/lib/" + + cp -r include/* "${install_directory}/include/celt/" + cp -r ${windows_build}/${windows_build_type}/Release/*.lib "${install_directory}/lib/" +elif [[ ${machine} == "Linux" ]]; then + cd build + + make -j 12 + if [[ $? -ne 0 ]]; then + echo "Failed to build celt!" + exit 1 + fi + + make install + if [[ $? -ne 0 ]]; then + echo "Failed to install celt!" + exit 1 + fi +fi + +echo "Celt build successfully" \ No newline at end of file diff --git a/native/codec/libraries/build_opus.sh b/native/codec/libraries/build_opus.sh new file mode 100644 index 0000000..52a077b --- /dev/null +++ b/native/codec/libraries/build_opus.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +cd $(dirname "$0") +install_directory="$(pwd)/generated/opus/" + +machine="$(uname -s)" +case "${machine}" in + Linux*) machine=Linux;; +# Darwin*) machine=Mac;; + MINGW*) machine=MinGW;; + *) machine="UNKNOWN:${machine}" +esac + +if [[ ${machine} == "UNKNOWN"* ]]; then + echo "Unknown platform ${machine}" + exit 1 +fi + +cd opus +#if [ ! -e CMakeLists.txt ]; then +# echo "Linking CMakeLists" +# ln -s ../cmake/opus/CMakeLists.txt . +#fi + +if [[ ${machine} == "Linux" ]]; then + if [[ ! -e configure ]]; then + echo "Generating configure file" + ./autogen.sh + if [[ $? -ne 0 ]]; then + echo "Failed to generate configure file" + exit 1 + fi + fi +fi + +windows_build="win32/VS2015/" +windows_build_type="x64" +if [[ ( ! -d build ) && ( ! -d "${windows_build}/${windows_build_type}" ) ]] || [[ "$1" == "rebuild" ]]; then + if [[ ${machine} == "Linux" ]]; then + if [[ -e build ]]; then + rm -r build + fi + mkdir build && cd build + + export CFLAGS="-fPIC" + ../configure --prefix="${install_directory}" --with-pic + if [[ $? -ne 0 ]]; then + echo "Failed to configure project!" + exit 1 + fi + + cd .. + elif [[ ${machine} == "MinGW" ]]; then + #Only cleanup last shit + if [[ -e "${windows_build}/${windows_build_type}" ]]; then + rm -r "${windows_build}/${windows_build_type}" + fi + fi +fi + +if [[ -e "${install_directory}" ]]; then + echo "deleting old install directory!" + rm -r "${install_directory}" + echo "rm -r '${install_directory}'" +fi + +if [[ ${machine} == "MinGW" ]]; then + saved_pwd=$(pwd) + cd "${windows_build}" + MSBuild.exe -p:Platform=x64 -property:Configuration=Release opus.vcxproj + if [[ $? -ne 0 ]]; then + echo "Failed to build opus!" + exit 1 + fi + cd ${saved_pwd} + + mkdir -p "${install_directory}/include/opus" + mkdir -p "${install_directory}/lib/" + + cp -r include/* "${install_directory}/include/opus/" + cp -r ${windows_build}/${windows_build_type}/Release/*.lib "${install_directory}/lib/" +elif [[ ${machine} == "Linux" ]]; then + cd build + + make -j 12 + if [[ $? -ne 0 ]]; then + echo "Failed to build opus!" + exit 1 + fi + + make install + if [[ $? -ne 0 ]]; then + echo "Failed to install opus!" + exit 1 + fi +fi + +echo "Opus build successfully" \ No newline at end of file diff --git a/native/codec/libraries/build_speex.sh b/native/codec/libraries/build_speex.sh new file mode 100644 index 0000000..b7f2aec --- /dev/null +++ b/native/codec/libraries/build_speex.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +cd $(dirname "$0") +install_directory="$(pwd)/generated/speex/" + +machine="$(uname -s)" +case "${machine}" in + Linux*) machine=Linux;; +# Darwin*) machine=Mac;; + MINGW*) machine=MinGW;; + *) machine="UNKNOWN:${machine}" +esac + +if [[ ${machine} == "UNKNOWN"* ]]; then + echo "Unknown platform ${machine}" + exit 1 +fi + +cd speex +if [[ ${machine} == "Linux" ]]; then + if [[ ! -e configure ]]; then + echo "Generating configure file" + ./autogen.sh + if [[ $? -ne 0 ]]; then + echo "Failed to generate configure file" + exit 1 + fi + fi +fi + +windows_build="win32/VS2015/" +windows_build_type="x64" +if [[ ( ! -d build ) && ( ! -d "${windows_build}/${windows_build_type}" ) ]] || [[ "$1" == "rebuild" ]]; then + if [[ ${machine} == "Linux" ]]; then + if [[ -e build ]]; then + rm -r build + fi + mkdir build && cd build + + export CFLAGS="-fPIC" + ../configure --prefix="${install_directory}" --with-pic + if [[ $? -ne 0 ]]; then + echo "Failed to configure project!" + exit 1 + fi + + cd .. + elif [[ ${machine} == "MinGW" ]]; then + #Only cleanup last shit + if [[ -e "${windows_build}" ]]; then + rm -r "${windows_build}" + fi + + mkdir -p ${windows_build} + cp -r ../template/speex_VS2015/* ${windows_build}/ + fi +fi + +if [[ -e "${install_directory}" ]]; then + echo "deleting old install directory!" + rm -r "${install_directory}" + echo "rm -r '${install_directory}'" +fi + +if [[ ${machine} == "MinGW" ]]; then + saved_pwd=$(pwd) + cd "${windows_build}" + MSBuild.exe -p:Platform=x64 -property:Configuration=Release libspeex/libspeex.vcxproj + + if [[ $? -ne 0 ]]; then + echo "Failed to build speex!" + exit 1 + fi + cd ${saved_pwd} + + mkdir -p "${install_directory}/include/speex" + mkdir -p "${install_directory}/lib/" + + cp -r include/speex/*.h "${install_directory}/include/speex/" + cp -r ${windows_build}/libspeex/${windows_build_type}/Release/*.lib "${install_directory}/lib/" +elif [[ ${machine} == "Linux" ]]; then + cd build + + make -j 12 + if [[ $? -ne 0 ]]; then + echo "Failed to build speex!" + exit 1 + fi + + make install + if [[ $? -ne 0 ]]; then + echo "Failed to install speex!" + exit 1 + fi +fi + +echo "Speex build successfully" \ No newline at end of file diff --git a/native/codec/libraries/celt/.gitignore b/native/codec/libraries/celt/.gitignore new file mode 100644 index 0000000..cabeba6 --- /dev/null +++ b/native/codec/libraries/celt/.gitignore @@ -0,0 +1,33 @@ +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +*.kdevelop.pcs +*.kdevses +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +.deps +.libs +*.la +testcelt +libtool +ltmain.sh +missing +stamp-h1 +*.sw +*.o +*.lo +*~ +tests/*test +tools/celtdec +tools/celtenc +celt.pc +libcelt.spec +libcelt/dump_modes diff --git a/native/codec/libraries/celt/AUTHORS b/native/codec/libraries/celt/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/native/codec/libraries/celt/COPYING b/native/codec/libraries/celt/COPYING new file mode 100644 index 0000000..843f927 --- /dev/null +++ b/native/codec/libraries/celt/COPYING @@ -0,0 +1,25 @@ +Copyright 2001-2009 Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, and other contributors + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/native/codec/libraries/celt/ChangeLog b/native/codec/libraries/celt/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/native/codec/libraries/celt/Doxyfile b/native/codec/libraries/celt/Doxyfile new file mode 100644 index 0000000..2f3ef1e --- /dev/null +++ b/native/codec/libraries/celt/Doxyfile @@ -0,0 +1,283 @@ +# Doxyfile 1.5.3 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = CELT +PROJECT_NUMBER = 0.11.4 +OUTPUT_DIRECTORY = doc/API +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class " \ + "The $name widget " \ + "The $name file " \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text " +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = libcelt/celt.h \ + libcelt/celt_types.h \ + libcelt/celt_header.h +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = *.c +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/native/codec/libraries/celt/Doxyfile.devel b/native/codec/libraries/celt/Doxyfile.devel new file mode 100644 index 0000000..e447ef1 --- /dev/null +++ b/native/codec/libraries/celt/Doxyfile.devel @@ -0,0 +1,281 @@ +# Doxyfile 1.5.3 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = CELT +PROJECT_NUMBER = 0.11.4 +OUTPUT_DIRECTORY = doc/devel +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class " \ + "The $name widget " \ + "The $name file " \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text " +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = libcelt +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/native/codec/libraries/celt/INSTALL b/native/codec/libraries/celt/INSTALL new file mode 100644 index 0000000..4b0336c --- /dev/null +++ b/native/codec/libraries/celt/INSTALL @@ -0,0 +1,5 @@ +To compile: + +./configure +make + diff --git a/native/codec/libraries/celt/Makefile.am b/native/codec/libraries/celt/Makefile.am new file mode 100644 index 0000000..3221818 --- /dev/null +++ b/native/codec/libraries/celt/Makefile.am @@ -0,0 +1,18 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# To disable automatic dependency tracking if using other tools than +# gcc and gmake, add the option 'no-dependencies' +AUTOMAKE_OPTIONS = 1.6 + +#Fools KDevelop into including all files +SUBDIRS = libcelt tests @tools@ + +DIST_SUBDIRS = libcelt tests tools + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = celt.pc + +EXTRA_DIST = celt.pc.in Doxyfile Doxyfile.devel msvc/config.h + +rpm: dist + rpmbuild -ta ${PACKAGE}-${VERSION}.tar.gz diff --git a/native/codec/libraries/celt/NEWS b/native/codec/libraries/celt/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/native/codec/libraries/celt/README b/native/codec/libraries/celt/README new file mode 100644 index 0000000..73a2292 --- /dev/null +++ b/native/codec/libraries/celt/README @@ -0,0 +1,88 @@ +CELT is a very low delay audio codec designed for high-quality communications. + +Traditional full-bandwidth codecs such as Vorbis and AAC can offer high +quality but they require codec delays of hundreds of milliseconds, which +makes them unsuitable for real-time interactive applications like tele- +conferencing. Speech targeted codecs, such as Speex or G.722, have lower +20-40ms delays but their speech focus and limited sampling rates +restricts their quality, especially for music. + +Additionally, the other mandatory components of a full network audio system— +audio interfaces, routers, jitter buffers— each add their own delay. For lower +speed networks the time it takes to serialize a packet onto the network cable +takes considerable time, and over the long distances the speed of light +imposes a significant delay. + +In teleconferencing— it is important to keep delay low so that the participants +can communicate fluidly without talking on top of each other and so that their +own voices don't return after a round trip as an annoying echo. + +For network music performance— research has show that the total one way delay +must be kept under 25ms to avoid degrading the musicians performance. + +Since many of the sources of delay in a complete system are outside of the +user's control (such as the speed of light) it is often only possible to +reduce the total delay by reducing the codec delay. + +Low delay has traditionally been considered a challenging area in audio codec +design, because as a codec is forced to work on the smaller chunks of audio +required for low delay it has access to less redundancy and less perceptual +information which it can use to reduce the size of the transmitted audio. + +CELT is designed to bridge the gap between "music" and "speech" codecs, +permitting new very high quality teleconferencing applications, and to go +further, permitting latencies much lower than speech codecs normally provide +to enable applications such as remote musical collaboration even over long +distances. + +In keeping with the Xiph.Org mission— CELT is also designed to accomplish +this without copyright or patent encumbrance. Only by keeping the formats +that drive our Internet communication free and unencumbered can we maximize +innovation, collaboration, and interoperability. Fortunately, CELT is ahead +of the adoption curve in its target application space, so there should be +no reason for someone who needs what CELT provides to go with a proprietary +codec. + +CELT has been tested on x86, x86_64, ARM, and the TI C55x DSPs, and should +be portable to any platform with a working C compiler and on the order of +100 MIPS of processing power. + +The code is still in early stage, so it may be broken from time to time, and +the bit-stream is not frozen yet, so it is different from one version to +another. Oh, and don't complain if it sets your house on fire. + +Complaints and accolades can be directed to the CELT mailing list: +http://lists.xiph.org/mailman/listinfo/celt-dev/ + +To compile: +% ./configure +% make + +For platforms without fast floating point support (such as ARM) use the +--enable-fixed argument to configure to build a fixed-point version of CELT. + +There are Ogg-based encode/decode tools in tools/. These are quite similar to +the speexenc/speexdec tools. Use the --help option for details. + +There is also a basic tool for testing the encoder and decoder called +"testcelt" located in libcelt/: + +% testcelt input.sw output.sw + +where input.sw is a 16-bit (machine endian) audio file sampled at 32000 Hz to +96000 Hz. The output file is already decompressed. + +For example, for a 44.1 kHz mono stream at ~64kbit/sec and with 256 sample +frames: + +% testcelt 44100 1 256 46 intput.sw output.sw + +Since 44100/256*46*8 = 63393.74 bits/sec. + +All even frame sizes from 64 to 512 are currently supported, although +power-of-two sizes are recommended and most CELT development is done +using a size of 256. The delay imposed by CELT is 1.25x - 1.5x the +frame duration depending on the frame size and some details of CELT's +internal operation. For 256 sample frames the delay is 1.5x or 384 +samples, so the total codec delay in the above example is 8.70ms +(1000/(44100/384)). diff --git a/native/codec/libraries/celt/README.Win32 b/native/codec/libraries/celt/README.Win32 new file mode 100644 index 0000000..4694994 --- /dev/null +++ b/native/codec/libraries/celt/README.Win32 @@ -0,0 +1,10 @@ +Here are a few tips for building on Windows: + +1) Create a config.h file that defines out things that defines out all the + features that your compiler doesn't understand (e.g. inline, restrict). + It also needs to define the CELT_BUILD macro + +2) Define the HAVE_CONFIG_H macro in the project build options (NOT in config.h) + +3) If you want things to be a lot easier, just use a compiler that supports + C99, such as gcc diff --git a/native/codec/libraries/celt/REPOSITORY_HAS_MOVED b/native/codec/libraries/celt/REPOSITORY_HAS_MOVED new file mode 100644 index 0000000..f791090 --- /dev/null +++ b/native/codec/libraries/celt/REPOSITORY_HAS_MOVED @@ -0,0 +1,10 @@ +The celt codec design and implementation have been merged into +the IETF Codec Working Group's "Opus" codec. As such, this +repository is no longer under active development. + +Please see https://git.xiph.org/?p=opus.git +and https://git.xiph.org/?p=users/jm/opus-tools.git for more +current work. Visit http://opus-codec.org/ for more +information. + +We apologize for any inconvenience this has caused. diff --git a/native/codec/libraries/celt/TODO b/native/codec/libraries/celt/TODO new file mode 100644 index 0000000..4c48482 --- /dev/null +++ b/native/codec/libraries/celt/TODO @@ -0,0 +1,20 @@ +- Check minimum width of bands +- Revisit energy resolution based on the bit-rate +- Revisit static bit allocation (as a function of frame size and channels) +- Dynamic adjustment of energy quantisation +- Psychacoustics + * Error shaping within each band + * Decisions on the rate +- Intensity stereo decisions +- Dynamic (intra-frame) bit allocation +- Joint encoding of stereo energy + +- Encode band shape (or just tilt)? +- Make energy encoding more robust to losses? + + +Misc: +Detect uint decoding and flag them in the decoder directly +If we attempt to write too many bits on the encoder side, set a flag instead of +aborting +Save "raw bytes" at the end of the stream diff --git a/native/codec/libraries/celt/autogen.sh b/native/codec/libraries/celt/autogen.sh new file mode 100755 index 0000000..9abad56 --- /dev/null +++ b/native/codec/libraries/celt/autogen.sh @@ -0,0 +1,111 @@ +#!/bin/sh +# Run this to set up the build system: configure, makefiles, etc. +# (based on the version in enlightenment's cvs) + +package="celt" + +olddir=`pwd` +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +cd "$srcdir" +DIE=0 + +echo "checking for autoconf... " +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile $package." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +VERSIONGREP="sed -e s/.*[^0-9\.]\([0-9]\.[0-9]*\).*/\1/" +VERSIONMKINT="sed -e s/[^0-9]//" + +# do we need automake? +if test -r Makefile.am; then + AM_NEEDED=`fgrep AUTOMAKE_OPTIONS Makefile.am | $VERSIONGREP` + if test -z $AM_NEEDED; then + echo -n "checking for automake... " + AUTOMAKE=automake + ACLOCAL=aclocal + if ($AUTOMAKE --version < /dev/null > /dev/null 2>&1); then + echo "no" + AUTOMAKE= + else + echo "yes" + fi + else + echo -n "checking for automake $AM_NEEDED or later... " + for am in automake-$AM_NEEDED automake$AM_NEEDED automake; do + ($am --version < /dev/null > /dev/null 2>&1) || continue + ver=`$am --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT` + verneeded=`echo $AM_NEEDED | $VERSIONMKINT` + if test $ver -ge $verneeded; then + AUTOMAKE=$am + echo $AUTOMAKE + break + fi + done + test -z $AUTOMAKE && echo "no" + echo -n "checking for aclocal $AM_NEEDED or later... " + for ac in aclocal-$AM_NEEDED aclocal$AM_NEEDED aclocal; do + ($ac --version < /dev/null > /dev/null 2>&1) || continue + ver=`$ac --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT` + verneeded=`echo $AM_NEEDED | $VERSIONMKINT` + if test $ver -ge $verneeded; then + ACLOCAL=$ac + echo $ACLOCAL + break + fi + done + test -z $ACLOCAL && echo "no" + fi + test -z $AUTOMAKE || test -z $ACLOCAL && { + echo + echo "You must have automake installed to compile $package." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + exit 1 + } +fi + +echo -n "checking for libtool... " +for LIBTOOLIZE in libtoolize glibtoolize nope; do + ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 && break +done +if test x$LIBTOOLIZE = xnope; then + echo "nope." + LIBTOOLIZE=libtoolize +else + echo $LIBTOOLIZE +fi +($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have libtool installed to compile $package." + echo "Download the appropriate package for your system," + echo "or get the source from one of the GNU ftp sites" + echo "listed in http://www.gnu.org/order/ftp.html" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +echo "Generating configuration files for $package, please wait...." + +echo " $ACLOCAL $ACLOCAL_FLAGS" +$ACLOCAL $ACLOCAL_FLAGS || exit 1 +echo " autoheader" +autoheader || exit 1 +echo " $LIBTOOLIZE --automake" +$LIBTOOLIZE --automake || exit 1 +echo " $AUTOMAKE --add-missing $AUTOMAKE_FLAGS" +$AUTOMAKE --add-missing $AUTOMAKE_FLAGS || exit 1 +echo " autoconf" +autoconf || exit 1 + +cd $olddir +#$srcdir/configure "$@" && echo diff --git a/native/codec/libraries/celt/celt.kdevelop b/native/codec/libraries/celt/celt.kdevelop new file mode 100644 index 0000000..2a30000 --- /dev/null +++ b/native/codec/libraries/celt/celt.kdevelop @@ -0,0 +1,205 @@ + + + + Jean-Marc Valin + Jean-Marc.Valin@USherbrooke.ca + $VERSION + KDevAutoProject + C + + celt + . + false + + + + + + default + libcelt/libcelt.la + + + + + + + true + false + false + false + false + + + + + optimized + GccOptions + GppOptions + G77Options + -O2 -g0 + + + --enable-debug=full + debug + GccOptions + GppOptions + G77Options + -O0 -g3 + + + + + + + + true + true + 4 + false + + 0 + + + + + libtool + + + + + true + false + false + false + + + false + true + 10 + + + + + ada + ada_bugs_gcc + bash + bash_bugs + clanlib + fortran_bugs_gcc + gnome1 + gnustep + gtk + gtk_bugs + haskell + haskell_bugs_ghc + java_bugs_gcc + java_bugs_sun + kde2book + libstdc++ + opengl + pascal_bugs_fp + php + php_bugs + perl + perl_bugs + python + python_bugs + qt-kdev3 + ruby + ruby_bugs + sdl + stl + sw + w3c-dom-level2-html + w3c-svg + w3c-uaag10 + wxwidgets_bugs + + + Guide to the Qt Translation Tools + Qt Assistant Manual + Qt Designer Manual + Qt Reference Documentation + qmake User Guide + + + KDE Libraries (Doxygen) + + + + + + + + + + + + false + 3 + 3 + + EmbeddedKDevDesigner + + + + + + false + true + true + 250 + 400 + 250 + false + 0 + true + true + false + std=_GLIBCXX_STD;__gnu_cxx=std + true + false + false + false + false + true + true + false + .; + + + + set + m_,_ + theValue + true + true + + + true + true + Horizontal + + + + + + .h + .cpp + + + + + + *.o,*.lo,CVS + false + + + + + + + + + + diff --git a/native/codec/libraries/celt/celt.pc.in b/native/codec/libraries/celt/celt.pc.in new file mode 100644 index 0000000..8a89064 --- /dev/null +++ b/native/codec/libraries/celt/celt.pc.in @@ -0,0 +1,15 @@ +# libcelt pkg-config source file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: celt +Description: CELT is a low-delay audio codec +Version: @CELT_VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -lcelt@LIBCELT_SUFFIX@ +Libs.private: -lm +Cflags: -I${includedir} diff --git a/native/codec/libraries/celt/configure.ac b/native/codec/libraries/celt/configure.ac new file mode 100644 index 0000000..86c99d1 --- /dev/null +++ b/native/codec/libraries/celt/configure.ac @@ -0,0 +1,241 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- + +AC_INIT(libcelt/arch.h) + +AM_CONFIG_HEADER([config.h]) + +CELT_MAJOR_VERSION=0 +CELT_MINOR_VERSION=11 +CELT_MICRO_VERSION=4 +CELT_EXTRA_VERSION= +CELT_VERSION=$CELT_MAJOR_VERSION.$CELT_MINOR_VERSION.$CELT_MICRO_VERSION$CELT_EXTRA_VERSION +LIBCELT_SUFFIX=0 + +CELT_LT_CURRENT=2 +CELT_LT_REVISION=0 +CELT_LT_AGE=0 + +AC_SUBST(CELT_LT_CURRENT) +AC_SUBST(CELT_LT_REVISION) +AC_SUBST(CELT_LT_AGE) +AC_SUBST(LIBCELT_SUFFIX) + +# For automake. +VERSION=$CELT_VERSION +PACKAGE=celt + +AC_SUBST(CELT_VERSION) + +AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define) +AM_MAINTAINER_MODE + +AC_CANONICAL_HOST +AM_PROG_LIBTOOL + +AC_PROG_CC_C99 +AC_C_BIGENDIAN +AC_C_CONST +AC_C_INLINE +AC_C_RESTRICT + +AC_DEFINE([CELT_BUILD], [], [This is a build of CELT]) + +AC_MSG_CHECKING(for C99 variable-size arrays) +AC_TRY_COMPILE( , [ +int foo=10; +int array[foo]; +], +[has_var_arrays=yes;AC_DEFINE([VAR_ARRAYS], [], [Use C99 variable-size arrays]) +], +has_var_arrays=no +) +AC_MSG_RESULT($has_var_arrays) + +AC_CHECK_HEADERS([alloca.h getopt.h]) +AC_MSG_CHECKING(for alloca) +AC_TRY_COMPILE( [#include ], [ +int foo=10; +int *array = alloca(foo); +], +[ +has_alloca=yes; +if test x$has_var_arrays = "xno" ; then +AC_DEFINE([USE_ALLOCA], [], [Make use of alloca]) +fi +], +has_alloca=no +) +AC_MSG_RESULT($has_alloca) + +AC_CHECK_HEADERS(sys/soundcard.h sys/audioio.h) + +AS_IF([test "x$with_ogg" != xno], + [XIPH_PATH_OGG([tools="tools"], [tools=""])], + [tools=""]) +AC_SUBST(tools) + +AC_CHECK_LIB(m, sin) + +# Check for getopt_long; if not found, use included source. +AC_CHECK_FUNCS([getopt_long],, +[# FreeBSD has a gnugetopt library. + AC_CHECK_LIB([gnugetopt],[getopt_long], +[AC_DEFINE([HAVE_GETOPT_LONG])], +[# Use the GNU replacement. +AC_LIBOBJ(getopt) +AC_LIBOBJ(getopt1)])]) + +AC_CHECK_LIB(winmm, main) + +AC_DEFINE_UNQUOTED(CELT_VERSION, "${CELT_VERSION}", [Complete version string]) +AC_DEFINE_UNQUOTED(CELT_MAJOR_VERSION, ${CELT_MAJOR_VERSION}, [Version major]) +AC_DEFINE_UNQUOTED(CELT_MINOR_VERSION, ${CELT_MINOR_VERSION}, [Version minor]) +AC_DEFINE_UNQUOTED(CELT_MICRO_VERSION, ${CELT_MICRO_VERSION}, [Version micro]) +AC_DEFINE_UNQUOTED(CELT_EXTRA_VERSION, "${CELT_EXTRA_VERSION}", [Version extra]) + +has_float_approx=no +#case "$host_cpu" in +#i[[3456]]86 | x86_64 | powerpc64 | powerpc32 | ia64) +# has_float_approx=yes +# ;; +#esac + +ac_enable_fixed="no"; +AC_ARG_ENABLE(fixed-point, [ --enable-fixed-point compile as fixed-point], +[if test "$enableval" = yes; then + ac_enable_fixed="yes"; + AC_DEFINE([FIXED_POINT], , [Compile as fixed-point]) +else + AC_DEFINE([FLOATING_POINT], , [Compile as floating-point]) +fi], +AC_DEFINE([FLOATING_POINT], , [Compile as floating-point])) + +ac_enable_fixed_debug="no" +AC_ARG_ENABLE(fixed-point-debug, [ --enable-fixed-point-debug debug fixed-point implementation], +[if test "$enableval" = yes; then + ac_enable_fixed_debug="yes" + AC_DEFINE([FIXED_DEBUG], , [Debug fixed-point implementation]) +fi]) + +ac_enable_experimental_postfilter="no" +AC_ARG_ENABLE(experimental-postfilter, [ --enable-experimental-postfilter Enable this for testing only if you know what you're doing ], +[if test "$enableval" = yes; then + ac_enable_experimental_postfilter="yes" + AC_DEFINE([ENABLE_POSTFILTER], , [Postfilter]) +fi]) + +ac_enable_custom_modes="no" +AC_ARG_ENABLE(custom-modes, [ --enable-custom-modes Enable non-Opus modes, like 44.1 kHz and powers of two ], +[if test "$enableval" = yes; then + ac_enable_custom_modes="yes" + AC_DEFINE([CUSTOM_MODES], , [Custom modes]) +fi]) + +float_approx=$has_float_approx +AC_ARG_ENABLE(float-approx, [ --enable-float-approx enable fast approximations for floating point], + [ if test "$enableval" = yes; then + AC_WARN([Floating point approximations are not supported on all platforms.]) + float_approx=yes + else + float_approx=no + fi], [ float_approx=$has_float_approx ]) + +if test "x${float_approx}" = "xyes"; then + AC_DEFINE([FLOAT_APPROX], , [Float approximations]) +fi + +ac_enable_assertions="no" +AC_ARG_ENABLE(assertions, [ --enable-assertions enable additional software error checking], +[if test "$enableval" = yes; then + ac_enable_assertions="yes" + AC_DEFINE([ENABLE_ASSERTIONS], , [Assertions]) +fi]) + +if test "$OPUS_BUILD" != "true" ; then +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING([if ${CXX} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([char foo;], + [ AC_MSG_RESULT([yes]) + SYMBOL_VISIBILITY="-fvisibility=hidden" ], + AC_MSG_RESULT([no])) +CFLAGS="$saved_CFLAGS $SYMBOL_VISIBILITY" +AC_SUBST(SYMBOL_VISIBILITY) +fi + +if test $ac_cv_c_compiler_gnu = yes ; then + CFLAGS="$CFLAGS -W -Wstrict-prototypes -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wno-parentheses -Wno-unused-parameter -Wno-sign-compare" +fi + +AC_CHECK_FUNCS([lrintf]) +AC_CHECK_FUNCS([lrint]) + +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(long long) + +if test x$has_char16 = "xyes" ; then + case 1 in + $ac_cv_sizeof_short) SIZE16="short";; + $ac_cv_sizeof_int) SIZE16="int";; + esac +else + case 2 in + $ac_cv_sizeof_short) SIZE16="short";; + $ac_cv_sizeof_int) SIZE16="int";; + esac +fi + +if test x$has_char16 = "xyes" ; then + case 2 in + $ac_cv_sizeof_int) SIZE32="int";; + $ac_cv_sizeof_long) SIZE32="long";; + $ac_cv_sizeof_short) SIZE32="short";; + esac +else + case 4 in + $ac_cv_sizeof_int) SIZE32="int";; + $ac_cv_sizeof_long) SIZE32="long";; + $ac_cv_sizeof_short) SIZE32="short";; + esac +fi + +AC_SUBST(SIZE16) +AC_SUBST(SIZE32) + +if test "$OPUS_BUILD" = "true" ; then +AC_DEFINE(OPUS_BUILD, [], [We're part of Opus]) +fi + +AC_OUTPUT([Makefile libcelt/Makefile tests/Makefile + celt.pc tools/Makefile libcelt.spec ]) + +AC_MSG_RESULT([ +------------------------------------------------------------------------ + $PACKAGE $VERSION: Automatic configuration OK. + + Compiler support: + + C99 var arrays: ................ ${has_var_arrays} + C99 lrintf: .................... ${ac_cv_func_lrintf} + Alloca: ........................ ${has_alloca} + + General configuration: + + Fast float approximations: ..... ${float_approx} + Fixed point support: ........... ${ac_enable_fixed} + Fixed point debugging: ......... ${ac_enable_fixed_debug} + Custom modes: .................. ${ac_enable_custom_modes} + Assertion checking: ............ ${ac_enable_assertions} +------------------------------------------------------------------------ +]) + +if test "x$tools" = "x"; then +echo "**IMPORTANT**" +echo "You don't seem to have the development package for libogg (libogg-devel) available. Only the library will be built (no encoder/decoder executable)" +echo "You can download libogg from http://www.vorbis.com/download.psp" +fi + +echo "Type \"make; make install\" to compile and install"; +echo "Type \"make check\" to run the test suite"; diff --git a/native/codec/libraries/celt/doc/ietf/Makefile.ietf b/native/codec/libraries/celt/doc/ietf/Makefile.ietf new file mode 100644 index 0000000..6574835 --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/Makefile.ietf @@ -0,0 +1,16 @@ +CC = gcc +CFLAGS = -c -O2 -g +LIBS = -lm + +OBJS = bands.o celt.o cwrs.o entcode.o entdec.o entenc.o kiss_fft.o \ + kiss_fftr.o laplace.o mdct.o modes.o pitch.o \ + quant_bands.o rangedec.o rangeenc.o rate.o testcelt.o vq.o plc.o + +.c.o: + $(CC) $(CFLAGS) $< + +testcelt: $(OBJS) + $(CC) -o $@ $(OBJS) $(LIBS) + +clean: + rm -f testcelt *.o diff --git a/native/codec/libraries/celt/doc/ietf/arch.h b/native/codec/libraries/celt/doc/ietf/arch.h new file mode 100644 index 0000000..8e6f9ab --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/arch.h @@ -0,0 +1,77 @@ +/* Copyright (C) 2003-2008 Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions for CELT +*/ +/* +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#include "celt_types.h" + +#define CELT_SIG_SCALE 32768. + +#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__); +#ifdef ENABLE_ASSERTIONS +#define celt_assert(cond) {if (!(cond)) \ + {celt_fatal("assertion failed: " #cond);}} +#define celt_assert2(cond, message) {if (!(cond)) \ + {celt_fatal("assertion failed: " #cond "\n" message);}} +#else +#define celt_assert(cond) +#define celt_assert2(cond, message) +#endif + + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) + +#define float2int(flt) ((int)(floor(.5+flt))) + +#define SCALEIN(a) ((a)*CELT_SIG_SCALE) +#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) + +#ifndef GLOBAL_STACK_SIZE +#ifdef FIXED_POINT +#define GLOBAL_STACK_SIZE 25000 +#else +#define GLOBAL_STACK_SIZE 40000 +#endif +#endif + +#endif /* ARCH_H */ diff --git a/native/codec/libraries/celt/doc/ietf/build_drafts.sh b/native/codec/libraries/celt/doc/ietf/build_drafts.sh new file mode 100755 index 0000000..0665f33 --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/build_drafts.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +./convert_source.sh + +./ietf_source.sh + +#codec draft +xml2rfc draft-valin-celt-codec.xml draft-valin-celt-codec.html + +xml2rfc draft-valin-celt-codec.xml draft-valin-celt-codec.txt + +#RTP draft +xml2rfc draft-valin-celt-rtp-profile.xml draft-valin-celt-rtp-profile.html + +xml2rfc draft-valin-celt-rtp-profile.xml draft-valin-celt-rtp-profile.txt diff --git a/native/codec/libraries/celt/doc/ietf/celt_types.h b/native/codec/libraries/celt/doc/ietf/celt_types.h new file mode 100644 index 0000000..d1d9d60 --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/celt_types.h @@ -0,0 +1,11 @@ +#ifndef _CELT_TYPES_H +#define _CELT_TYPES_H + +typedef short celt_int16; +typedef unsigned short celt_uint16; +typedef int celt_int32; +typedef unsigned int celt_uint32; +typedef long long celt_int64; +typedef unsigned long long celt_uint64; + +#endif /* _CELT_TYPES_H */ diff --git a/native/codec/libraries/celt/doc/ietf/convert_source.sh b/native/codec/libraries/celt/doc/ietf/convert_source.sh new file mode 100755 index 0000000..707e2c8 --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/convert_source.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +mkdir -p source + +for i in `ls ../../libcelt | grep '\.[ch]$'` +do + +#echo "
    " > source/$i +#echo '' >> source/$i +#echo '
    > source/$i + +echo '#include "substitutions.h"' > tata.c +echo 'SOURCE_CODE_BEGIN' >> tata.c + +if echo $i | grep '\.h' > /dev/null; then + cat ../../libcelt/$i | sed -e 's/=\*/= \*/' -e 's/=-/= -/' -e 's/\t/ /g' -e 's/^#/\/\/PREPROCESS_REMOVE#/' >> tata.c +else + cat ../../libcelt/$i | sed -e 's/=\*/= \*/' -e 's/=-/= -/' -e 's/\t/ /g' -e 's/^#include/\/\/PREPROCESS_REMOVE#include/' | sed 's/^#define/\/\/PREPROCESS_REMOVE#define/'>> tata.c +fi + +#cat ../../libcelt/$i | sed 's/^#/\/\/PREPROCESS_REMOVE#/' >> tata.c +#cat ../../libcelt/$i | sed 's/^#include/\/\/PREPROCESS_REMOVE#include/' | sed 's/^#define/\/\/PREPROCESS_REMOVE#define/'>> tata.c +gcc -DHAVE_CONFIG_H -C -E -nostdinc tata.c | grep -v '^#' | sed 's/\/\/PREPROCESS_REMOVE//' | perl -ne 'if ($begin) {print $_} if (/SOURCE_CODE_BEGIN/) {$begin=1}' > tata2.c + +#cat ../../libcelt/$i >> tata.c +#gcc -C -E -nostdinc tata.c -fdirectives-only | perl -ne 'if ($begin) {print $_} if (/SOURCE_CODE_BEGIN/) {$begin=1}' > tata2.c + +indent -nsc -ncdb -original -sob -i2 -bl -bli0 --no-tabs -l69 --format-all-comments tata2.c -o tata.c +cat tata.c | grep -v 'include.*float_cast' | ./wrap_lines > source/$i +#cat tata.c > source/$i + + + +#indent --no-tabs -l72 --format-all-comments ../../libcelt/$i -o tata.c +#cat tata.c >> source/$i + + +#echo ']]>
    ' >> source/$i +#echo '
    ' >> source/$i +#echo '
    ' >> source/$i + +done + +cp arch.h source/arch.h +cp celt_types.h source/celt_types.h +cp config.h source/config.h +cp Makefile.ietf source/Makefile + +rm source/mfrng*.c +rm source/dump_modes* +rm source/header* +rm source/fixed* + diff --git a/native/codec/libraries/celt/doc/ietf/draft-valin-celt-codec.xml b/native/codec/libraries/celt/doc/ietf/draft-valin-celt-codec.xml new file mode 100644 index 0000000..91c91bd --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/draft-valin-celt-codec.xml @@ -0,0 +1,1383 @@ + + + + + + + +Constrained-Energy Lapped Transform (CELT) Codec + + + + +Octasic Semiconductor +
    + +4101, Molson Street, suite 300 +Montreal +Quebec +H1Y 3L1 +Canada + +jean-marc.valin@octasic.com +
    +
    + + +Xiph.Org Foundation +
    + + + + + + + +tterribe@xiph.org +
    +
    + + +Juniper Networks +
    + +2251 Corporate Park Drive, Suite 100 +Herndon +VA +20171-1817 +USA + +gmaxwell@juniper.net +
    +
    + + +Xiph.Org Foundation +
    + + + + + + + +xiphmont@xiph.org +
    +
    + + + +General + +AVT Working Group +audio codec +low delay +Internet-Draft +CELT + + + +CELT is an open-source voice codec suitable for use in very low delay +Voice over IP (VoIP) type applications. This document describes the encoding +and decoding process. + + +
    + + + +
    + +This document describes the CELT codec, which is designed for transmitting full-bandwidth +audio with very low delay. It is suitable for encoding both +speech and music at rates starting at 32 kbit/s. It is primarily designed for transmission +over the Internet and protocols such as RTP , but also includes +a certain amount of robustness to bit errors, where this could be done at no significant +cost. + + +The novel aspect of CELT compared to most other codecs is its very low delay, +below 10 ms. There are two main advantages to having a very low delay audio link. +The lower delay itself is important for some interactions, such as playing music +remotely. Another advantage is its behavior in the presence of acoustic echo. When +the round-trip audio delay is sufficiently low, acoustic echo is no longer +perceived as a distinct repetition, but rather as extra reverberation. Applications +of CELT include: + + +Collaborative network music performance +High-quality teleconferencing +Wireless audio equipment +Low-delay links for broadcast applications + + + +The source code for the reference implementation of the CELT codec is provided in . This source code is the normative specification +of the codec. The corresponding text description in this document is provided +for informative purposes. + + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this +document are to be interpreted as described in RFC 2119 . + + +
    + +
    + + +CELT stands for Constrained Energy Lapped Transform. This is +the fundamental principle of the codec: the quantization process is designed in such a way +as to preserve the energy in a certain number of bands. The theoretical aspects of the +codec are described in greater detail and +. Although these papers describe slightly older versions of +the codec (version 0.3.2 and 0.5.1, respectively), the principles remain the same. + + +CELT is a transform codec, based on the Modified Discrete Cosine Transform +(MDCT). The MDCT is derived from the DCT-IV by adding an overlap with time-domain +aliasing cancellation . +The main characteristics of CELT are as follows: + + +Ultra-low algorithmic delay (scalable, typically 4 to 9 ms) +Sampling rates from 32 kHz to 48 kHz and above (full audio bandwidth) +Applicability to both speech and music +Support for mono and stereo +Adaptive bit-rate from 32 kbit/s to 128 kbit/s per channel and above +Scalable complexity +Robustness to packet loss (scalable trade-off between quality and loss-robustness) +Open source implementation (floating-point and fixed-point) +No known intellectual property issues + + + +
    + + +This document contains a detailed description of both the encoder and the decoder, along with a reference implementation. In most circumstances, and unless otherwise stated, the calculations +do not need to produce results that are bit-identical with the reference implementation, so alternate algorithms can sometimes be used. However, there are a few (clearly identified) cases, such as the bit allocation, where bit-exactness with the reference +implementation is required. An implementation is considered to be compatible if, for any valid bit-stream, the decoder's output is perceptually indistinguishable from the output produced by the reference decoder. + + + +The CELT codec does not use a standard bit-packer, +but rather uses a range coder to pack both integers and entropy-coded symbols. +In mono mode, the bit-stream generated by the encoder contains the +following parameters (in order): + + + + +Feature flags I, P, S, F (2-4 bits) +if P=1 + + Pitch period + +if S=1 + + Transient scalefactor + if scalefactor=(1 or 2) AND more than 2 short MDCTs + + ID of block before transient + + if scalefactor=3 + + Transient time + + +Coarse energy encoding (for each band) +Fine energy encoding (for each band) +For each band + + if P=1 and band is at the beginning of a pitch band + + Pitch gain bit + + PVQ indices + +More fine energy (using all remaining bits) + + + +Note that due to the use of a range coder, all of the parameters have to be encoded and decoded in order. + + +The CELT bit-stream is "octet-based" in the sense that the encoder always produces an +integer number of octets when encoding a frame. Also, the bit-rate used by the CELT encoder can +only be determined by the number of octets produced. +In many cases (e.g. UDP/RTP), the transport layer already encodes the data length, so +no extra information is necessary to signal the bit-rate. In cases where this is not true, +or when there are multiple compressed frames per packet, the size of each compressed +frame MUST be signalled in some way. + + + +
    + +
    + +
    + +The operation of both the encoder and decoder depends on the mode data. A mode +definition can be created by celt_create_mode() (modes.c) +based on three parameters: + +frame size (number of samples) +sampling rate (samples per second) +number of channels (1 or 2) + + + +The frame size can be any even number of samples from 64 to 1024, inclusively. +The sampling rate must be between 32000 Hz and 96000 Hz. The mode data that is +created defines how the encoder and the decoder operate. More specifically, the +following information is contained in the mode object: + + +Frame size +Sampling rate +Windowing overlap +Number of channels +Definition of the bands +Definition of the pitch bands +Decay coefficients of the Laplace distributions for coarse energy +Bit allocation matrix + + + + +The windowing overlap is the amount of overlap between the frames. CELT uses a low-overlap window that is typically half of the frame size. For a frame size of 256 samples, the overlap is 128 samples, so the total algorithmic delay is 256+128=384. CELT divides the audio into frequency bands, for which the energy is preserved. These bands are chosen to follow the ear's critical bands, with the exception that each band has to contain at least 3 frequency bins. + + + +The energy bands are based on the Bark scale. The Bark band edges (in Hz) are defined as +[0, 100, 200, 300, 400, 510, 630, 770, 920, 1080, 1270, 1480, 1720, 2000, 2320, +2700, 3150, 3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500, 20000]. The actual bands used by the codec +depend on the sampling rate and the frame size being used. The mapping from Hz to MDCT bins is done by +multiplying by sampling_rate/(2*frame_size) and rounding to the nearest value. An exception is made for +the lower frequencies to ensure that all bands contain at least 3 MDCT bins. The definition of the Bark +bands is computed in compute_ebands() (modes.c). + + + +CELT includes a pitch predictor for which the gains are defined over +a set of pitch bands. The pitch bands are defined +(in Hz) as [0, 345, 689, 1034, 1378, 2067, 3273, 5340, 6374]. The Hz values +are mapped to MDCT bins in the same was as the energy bands. The pitch +band boundaries are aligned to energy band boundaries. The definition of the pitch +bands is computed in compute_pbands() (modes.c). + + + +The mode contains a bit allocation table that is derived from a prototype allocation table, +specified in the band_allocation matrix (modes.c). Each row of the table is a single prototype allocation, +in bits per Bark band, and assuming 256-sample frames. These rows must be projected onto the actual band layout in use at the +current frame size and sample rate, using exact integer calculations. The reference +implementation +pre-computes these projections in compute_allocation_table() (modes.c) and any other implementation +MUST produces bit-identical allocation results. + + + +Every entry in the allocation table is multiplied by the current number of channels and +the current frame size. Each prototype allocation is projected +independently using the following process: the upper band frequencies (in Hz) from the current Bark band and current CELT band are compared. (When the process begins, these will each be the first band, but will increment independently.) If the current Bark band's upper edge frequency +is less than the current CELT band's upper edge frequency, the entire value of the Bark band plus any carried remainder is assigned to the current CELT +band, and the process continues with the next +Bark band in sequence and zero remainder. If the current Bark band's upper edge frequency is equal to or greater than that of +the current CELT band, the CELT band will receive only part of this Bark band's allocation. +This portion allocated to the CELT band is then calculated by multiplying the Bark band's allocation by the +difference in Hz between the Bark band's upper frequency and the current +CELT band's lower frequency, adding the width of the current Bark band +divided by two, and then dividing this total by the width of the current Bark +band in Hz. The partial value plus any carried remainder is added to the current +CELT band, and the difference between the partial value and the Bark target is +taken as the new carried remainder. The process begins then again starting at the +next CELT band and next Bark band. Once all bands in a prototype allocation have been considered, any +remainder is added to the last CELT band. All of the resulting values are +rescaled by adding 128 and dividing by 256. + + +
    + +
    + + +The top-level function for encoding a CELT frame in the reference implementation is +celt_encode() (celt.c). +The basic block diagram of the CELT encoder is illustrated in . +The encoder contains most of the building blocks of the decoder and can, +with very little extra computation, compute the signal that would be decoded by the decoder. +CELT has three main quantizers denoted Q1, Q2 and Q3. These apply to band energies +(), pitch gains () +and normalized MDCT bins (), respectively. + + +
    + +|Q1|------+ + | |computation| | +--+ | + | +-----------+ | | + | +-----+ | + | v v + +------+ +-+--+ +-+ +-+ +-+ +--+ +---+ +-+ +-----+ +-+ +->|Window|->|MDCT|->|-|->|/|->|-|->|Q3|->|Mix|->|*|->|IMDCT|->|+|-+-> + +---+--+ +----+ +-+ +-+ +-+ +--+ +---+ +-+ +-----+ +-+ | + | ^ | + | +--------------------------+ | + +-+ | | + | +----------+ +--+ +-+-+ | + +------------->|pitch gain|-->|Q2|-->| * | | + | +----------+ +--+ +---+ | + | ^ ^ | + | +-----------------+ | + v | | + +------------+ +------+-----+ | + |Pitch period| |Delay, MDCT,| | + |estimation |----------------------->| Normalize | | + +------------+ +------------+ | + ^ ^ | + +--------------------------------------+-----------------+ +]]> + +Block diagram of the CELT encoder +
    + + +The input audio first goes through a pre-emphasis filter +(just before the windowing in ), which attenuates the +spectral tilt. The filter is has the transfer function A(z)=1-alpha_p*z^-1, with +alpha_p=0.8. The inverse of the pre-emphasis is applied at the decoder. + + +
    + +CELT uses an entropy coder based upon , +which is itself a rediscovery of the FIFO arithmetic code introduced by . +It is very similar to arithmetic encoding, except that encoding is done with +digits in any base instead of with bits, +so it is faster when using larger bases (i.e.: an octet). All of the +calculations in the range coder must use bit-exact integer arithmetic. + + + +The range coder also acts as the bit-packer for CELT. It is +used in three different ways, to encode: + +entropy-coded symbols with a fixed probability model using ec_encode(), (rangeenc.c) +integers from 0 to 2^M-1 using ec_enc_uint() or ec_enc_bits(), (entenc.c) +integers from 0 to N-1 (where N is not a power of two) using ec_enc_uint(). (entenc.c) + + + + +The range encoder maintains an internal state vector composed of the +four-tuple (low,rng,rem,ext), representing the low end of the current +range, the size of the current range, a single buffered output octet, +and a count of additional carry-propagating output octets. Both rng +and low are 32-bit unsigned integer values, rem is an octet value or +the special value -1, and ext is an integer with at least 16 bits. +This state vector is initialized at the start of each each frame to +the value (0,2^31,-1,0). + + + +Each symbol is drawn from a finite alphabet and coded in a separate +context which describes the size of the alphabet and the relative +frequency of each symbol in that alphabet. CELT only uses static +contexts; they are not adapted to the statistics of the data that is +coded. + + +
    + + The main encoding function is ec_encode() (rangeenc.c), + which takes as an argument a three-tuple (fl,fh,ft) + describing the range of the symbol to be encoded in the current + context, with 0 <= fl < fh <= ft <= 65535. The values of this tuple + are derived from the probability model for the symbol. Let f(i) be + the frequency of the ith symbol in the current context. Then the + three-tuple corresponding to the kth symbol is given by + + + + ec_encode() updates the state of the encoder as follows. If fl is + greater than zero, then low = low + rng - (rng/ft)*(ft-fl) and + rng = (rng/ft)*(fh-fl). Otherwise, low is unchanged and + rng = rng - (rng/ft)*(fh-fl). The divisions here are exact integer + division. After this update, the range is normalized. + + + To normalize the range, the following process is repeated until + rng > 2^23. First, the top 9 bits of low, (low>>23), are placed into + a carry buffer. Then, low is set to . This process is carried out by + ec_enc_normalize() (rangeenc.c). + + + The 9 bits produced in each iteration of the normalization loop + consist of 8 data bits and a carry flag. The final value of the + output bits is not determined until carry propagation is accounted + for. Therefore the reference implementation buffers a single + (non-propagating) output octet and keeps a count of additional + propagating (0xFF) output octets. An implementation MAY choose to use + any mathematically equivalent scheme to perform carry propagation. + + + The function ec_enc_carry_out() (rangeenc.c) performs + this buffering. It takes a 9-bit input value, c, from the normalization + 8-bit output and a carry bit. If c is 0xFF, then ext is incremented + and no octets are output. Otherwise, if rem is not the special value + -1, then the octet (rem+(c>>8)) is output. Then ext octets are output + with the value 0 if the carry bit is set, or 0xFF if it is not, and + rem is set to the lower 8 bits of c. After this, ext is set to zero. + + + In the reference implementation, a special version of ec_encode() + called ec_encode_bin() (rangeenc.c) is defined to + take a two-tuple (fl,ftb), where , but avoids using division. + + +
    + +
    + + Functions ec_enc_uint() or ec_enc_bits() are based on ec_encode() and + encode one of N equiprobable symbols, each with a frequency of 1, + where N may be as large as 2^32-1. Because ec_encode() is limited to + a total frequency of 2^16-1, this is done by encoding a series of + symbols in smaller contexts. + + + ec_enc_bits() (entenc.c) is defined, like + ec_encode_bin(), to take a two-tuple (fl,ftb), with >ftb-8&0xFF) using ec_encode_bin() and + subtracts 8 from ftb. Then, it encodes the remaining bits of fl, e.g., + (fl&(1<, again using ec_encode_bin(). + + + ec_enc_uint() (entenc.c) takes a two-tuple (fl,ft), + where ft is not necessarily a power of two. Let ftb be the location + of the highest 1 bit in the two's-complement representation of + (ft-1), or -1 if no bits are set. If ftb>8, then the top 8 bits of fl + are encoded using ec_encode() with the three-tuple + (fl>>ftb-8,(fl>>ftb-8)+1,(ft-1>>ftb-8)+1), and the remaining bits + are encoded with ec_enc_bits using the two-tuple + . + +
    + +
    + + After all symbols are encoded, the stream must be finalized by + outputting a value inside the current range. Let end be the integer + in the interval [low,low+rng) with the largest number of trailing + zero bits. Then while end is not zero, the top 9 bits of end, e.g., + >23), are sent to the carry buffer, and end is replaced by + (end<<8&0x7FFFFFFF). Finally, if the value in carry buffer, rem, is]]> + neither zero nor the special value -1, or the carry count, ext, is + greater than zero, then 9 zero bits are sent to the carry buffer. + After the carry buffer is finished outputting octets, the rest of the + output buffer is padded with zero octets. Finally, rem is set to the + special value -1. This process is implemented by ec_enc_done() + (rangeenc.c). + +
    + +
    + + The bit allocation routines in CELT need to be able to determine a + conservative upper bound on the number of bits that have been used + to encode the current frame thus far. This drives allocation + decisions and ensures that the range code will not overflow the + output buffer. This is computed in the reference implementation to + fractional bit precision by the function ec_enc_tell() + (rangeenc.c). + Like all operations in the range encoder, it must + be implemented in a bit-exact manner. + +
    + +
    + +
    + + +The CELT codec has several optional features that can be switched on or off in each frame, some of which are mutually exclusive. The four main flags are intra-frame energy (I), pitch (P), short blocks (S), and folding (F). Those are described in more detail below. There are eight valid combinations of these four features, and they are encoded into the stream first using a variable length code (). It is left to the implementor to choose when to enable each of the flags, with the only restriction that the combination of the four flags MUST correspond to a valid entry in . + + + + Encoding of the feature flags + I + P + S + F + Encoding + 000100 + 010101 + 1001110 + 1011111 + + 00001000 + 00111001 + 01001010 + 10001011 + + +
    + +CELT uses prediction to encode the energy in each frequency band. In order to make frames independent, however, it is possible to disable the part of the prediction that depends on previous frames. This is called intra-frame energy and requires around 12 more bits per frame. It is enabled with the I bit (Table. flags-encoding). The use of intra energy is OPTIONAL and the decision method is left to the implementor. The reference code describes one way of deciding which frames would benefit most from having their energy encoded without prediction. The intra_decision() (quant_bands.c) function looks for frames where the log-spectral distance between consecutive frames is more than 9 dB. When such a difference is found between two frames, the next frame (not the one for which the difference is detected) is marked encoded with intra energy. The one-frame delay is to ensure that when a frame containing a transient is lost, then the next frame will be decoded without accumulating error from the lost frame. + +
    + +
    + +CELT can use a pitch predictor (also known as long-term predictor) to improve the voice quality at lower bit-rates. When the P bit is set, the pitch period is encoded after the flag bits. The value encoded is an integer in the range [0, 1024-N-overlap-1]. + +
    + +
    + +To improve audio quality during transients, CELT can use a short block multiple-MDCT transform. Unlike other transform codecs, the multiple MDCTs are jointly quantized as if the coefficients were obtained from a single MDCT. For that reason, it is better to consider the short block case as using a different transform of the same length rather than as multiple independent MDCTs. In the reference implementation, the decision to use short blocks is made by transient_analysis() (celt.c) based on the pre-emphasized signal's peak values, but other methods can be used. When the S bit is set, a 2-bit transient scalefactor is encoded directly after the flag bits. If the scalefactor is 0, then the multiple-MDCT output is unmodified. If the scalefactor is 1 or 2, then the output of the MDCTs that follow the transient is scaled down by 2^scalefactor. If the scalefactor is equal to 3, then a time-domain pre-emphasis window is applied before computing the MDCTs and no further scaling is applied to the MDCTs output. The window value is 1 from the beginning of the frame to 16 samples before the transient time. It is a Hanning window from there to the transient time, and then the value is 1/8 up to the end of the frame. The Hanning window part is defined as: + + + +static const float transientWindow[16] = { + 0.0085135, 0.0337639, 0.0748914, 0.1304955, + 0.1986827, 0.2771308, 0.3631685, 0.4538658, + 0.5461342, 0.6368315, 0.7228692, 0.8013173, + 0.8695045, 0.9251086, 0.9662361, 0.9914865}; + + +When the scalefactor is 3, the transient time is the exact time of the transient +determined by the encoder and encoded as an integer number of samples with the range +[0, N+overlap-1] directly after the scalefactor. + + + +In the case where the scalefactor is 1 or 2 and the mode is defined to use more than 2 MDCTs, the last MDCT to which the scaling is not applied is encoded using an integer in the range [0, B-2], where B is the number of short MDCTs used for the mode. + +
    + +
    + +The last encoding feature in CELT is spectral folding. It is designed to prevent birdie artifacts caused by the sparse spectra often generated by low-bitrate transform codecs. When folding is enabled, a copy of the low-frequency spectrum is added to the higher-frequency bands (above ~6400 Hz). The folding operation is described in more detail in . + +
    + +
    + +
    + +The MDCT implementation has no special characteristics. The +input is a windowed signal (after pre-emphasis) of 2*N samples and the output is N +frequency-domain samples. A low-overlap window is used to reduce the algorithmic delay. +It is derived from a basic (full overlap) window that is the same as the one used in the Vorbis codec: W(n)=[sin(pi/2*sin(pi/2*(n+.5)/L))]^2. The low-overlap window is created by zero-padding the basic window and inserting ones in the middle, such that the resulting window still satisfies power complementarity. The MDCT is computed in mdct_forward() (mdct.c), which includes the windowing operation and a scaling of 2/N. + +
    + +
    + +The MDCT output is divided into bands that are designed to match the ear's critical bands, +with the exception that each band has to be at least 3 bins wide. For each band, the encoder +computes the energy that will later be encoded. Each band is then normalized by the +square root of the non-quantized energy, such that each band now forms a unit vector X. +The energy and the normalization are computed by compute_band_energies() +and normalise_bands() (bands.c), respectively. + +
    + +
    + + +It is important to quantize the energy with sufficient resolution because +any energy quantization error cannot be compensated for at a later +stage. Regardless of the resolution used for encoding the shape of a band, +it is perceptually important to preserve the energy in each band. CELT uses a +coarse-fine strategy for encoding the energy in the base-2 log domain, +as implemented in quant_bands.c + +
    + +The coarse quantization of the energy uses a fixed resolution of +6 dB and is the only place where entropy coding is used. +To minimize the bitrate, prediction is applied both in time (using the previous frame) +and in frequency (using the previous bands). The 2-D z-transform of +the prediction filter is: A(z_l, z_b)=(1-a*z_l^-1)*(1-z_b^-1)/(1-b*z_b^-1) +where b is the band index and l is the frame index. The prediction coefficients are +a=0.8 and b=0.7 when not using intra energy and a=b=0 when using intra energy. +The time-domain prediction is based on the final fine quantization of the previous +frame, while the frequency domain (within the current frame) prediction is based +on coarse quantization only (because the fine quantization has not been computed +yet). We approximate the ideal +probability distribution of the prediction error using a Laplace distribution. The +coarse energy quantization is performed by quant_coarse_energy() and +quant_coarse_energy() (quant_bands.c). + + + +The Laplace distribution for each band is defined by a 16-bit (Q15) decay parameter. +Thus, the value 0 has a frequency count of p[0]=2*(16384*(16384-decay)/(16384+decay)). The +values +/- i each have a frequency count p[i] = (p[i-1]*decay)>>14. The value of p[i] is always +rounded down (to avoid exceeding 32768 as the sum of all frequency counts), so it is possible +for the sum to be less than 32768. In that case additional values with a frequency count of 1 are encoded. The signed values corresponding to symbols 0, 1, 2, 3, 4, ... +are [0, +1, -1, +2, -2, ...]. The encoding of the Laplace-distributed values is +implemented in ec_laplace_encode() (laplace.c). + + +
    + +
    + +After the coarse energy quantization and encoding, the bit allocation is computed +() and the number of bits to use for refining the +energy quantization is determined for each band. Let B_i be the number of fine energy bits +for band i; the refinement is an integer f in the range [0,2^B_i-1]. The mapping between f +and the correction applied to the coarse energy is equal to (f+1/2)/2^B_i - 1/2. Fine +energy quantization is implemented in quant_fine_energy() +(quant_bands.c). + + + +If any bits are unused at the end of the encoding process, these bits are used to +increase the resolution of the fine energy encoding in some bands. Priority is given +to the bands for which the allocation () was rounded +down. At the same level of priority, lower bands are encoded first. Refinement bits +are added until there are no unused bits. This is implemented in quant_energy_finalise() +(quant_bands.c). + + +
    + + +
    + +
    +Bit allocation is performed based only on information available to both +the encoder and decoder. The same calculations are performed in a bit-exact +manner in both the encoder and decoder to ensure that the result is always +exactly the same. Any mismatch would cause an error in the decoded output. +The allocation is computed by compute_allocation() (rate.c), +which is used in both the encoder and the decoder. + +For a given band, the bit allocation is nearly constant across +frames that use the same number of bits for Q1, yielding a +pre-defined signal-to-mask ratio (SMR) for each band. Because the +bands each have a width of one Bark, this is equivalent to modeling the +masking occurring within each critical band, while ignoring inter-band +masking and tone-vs-noise characteristics. While this is not an +optimal bit allocation, it provides good results without requiring the +transmission of any allocation information. + + + + +For every encoded or decoded frame, a target allocation must be computed +using the projected allocation. In the reference implementation this is +performed by compute_allocation() (rate.c). +The target computation begins by calculating the available space as the +number of whole bits which can be fit in the frame after Q1 is stored according +to the range coder (ec_[enc/dec]_tell()) and then multiplying by 8. +Then the two projected prototype allocations whose sums multiplied by 8 are nearest +to that value are determined. These two projected prototype allocations are then interpolated +by finding the highest integer interpolation coefficient in the range 0-8 +such that the sum of the higher prototype times the coefficient, plus the +sum of the lower prototype multiplied by +the difference of 16 and the coefficient, is less than or equal to the +available sixteenth-bits. +The reference implementation performs this step using a binary search in +interp_bits2pulses() (rate.c). The target +allocation is the interpolation coefficient times the higher prototype, plus +the lower prototype multiplied by the difference of 16 and the coefficient, +for each of the CELT bands. + + + +Because the computed target will sometimes be somewhat smaller than the +available space, the excess space is divided by the number of bands, and this amount +is added equally to each band. Any remaining space is added to the target one +sixteenth-bit at a time, starting from the first band. The new target now +matches the available space, in sixteenth-bits, exactly. + + + +The allocation target is separated into a portion used for fine energy +and a portion used for the Spherical Vector Quantizer (PVQ). The fine energy +quantizer operates in whole-bit steps. For each band the number of bits per +channel used for fine energy is calculated by 50 minus the log2_frac(), with +1/16 bit precision, of the number of MDCT bins in the band. That result is multiplied +by the number of bins in the band and again by twice the number of +channels, and then the value is set to zero if it is less than zero. Added +to that result is 16 times the number of MDCT bins times the number of +channels, and it is finally divided by 32 times the number of MDCT bins times the +number of channels. If the result times the number of channels is greater than than the +target divided by 16, the result is set to the target divided by the number of +channels divided by 16. Then if the value is greater than 7 it is reset to 7 because a +larger amount of fine energy resolution was determined not to be make an improvement in +perceived quality. The resulting number of fine energy bits per channel is +then multiplied by the number of channels and then by 16, and subtracted +from the target allocation. This final target allocation is what is used for the +PVQ. + + +
    + +
    + +This section needs to be updated. + + +
    + +
    +CELT uses a Pyramid Vector Quantization (PVQ) +codebook for quantizing the details of the spectrum in each band that have not +been predicted by the pitch predictor. The PVQ codebook consists of all sums +of K signed pulses in a vector of N samples, where two pulses at the same position +are required to have the same sign. Thus the codebook includes +all integer codevectors y of N dimensions that satisfy sum(abs(y(j))) = K. + + + +In bands where neither pitch nor folding is used, the PVQ is used to encode +the unit vector that results from the normalization in + directly. Given a PVQ codevector y, +the unit vector X is obtained as X = y/||y||, where ||.|| denotes the +L2 norm. + + +
    + +Although the allocation is performed in 1/16 bit units, the quantization requires +an integer number of pulses K. To do this, the encoder searches for the value +of K that produces the number of bits that is the nearest to the allocated value +(rounding down if exactly half-way between two values), subject to not exceeding +the total number of bits available. The computation is performed in 1/16 of +bits using log2_frac() and ec_enc_tell(). The number of codebooks entries can +be computed as explained in . The difference +between the number of bits allocated and the number of bits used is accumulated to a +balance (initialised to zero) that helps adjusting the +allocation for the next bands. One third of the balance is subtracted from the +bit allocation of the next band to help achieving the target allocation. The only +exceptions are the band before the last and the last band, for which half the balance +and the whole balance are subtracted, respectively. + +
    + +
    + + +The search for the best codevector y is performed by alg_quant() +(vq.c). There are several possible approaches to the +search with a tradeoff between quality and complexity. The method used in the reference +implementation computes an initial codeword y1 by projecting the residual signal +R = X - p' onto the codebook pyramid of K-1 pulses: + + +y0 = round_towards_zero( (K-1) * R / sum(abs(R))) + + + +Depending on N, K and the input data, the initial codeword y0 may contain from +0 to K-1 non-zero values. All the remaining pulses, with the exception of the last one, +are found iteratively with a greedy search that minimizes the normalized correlation +between y and R: + + + +J = -R^T*y / ||y|| + + + +The search described above is considered to be a good trade-off between quality +and computational cost. However, there are other possible ways to search the PVQ +codebook and the implementors MAY use any other search methods. + +
    + + +
    + +The best PVQ codeword is encoded as a uniformly-distributed integer value +by encode_pulses() (cwrs.c). +The codeword is converted to a unique index in the same way as specified in +. The indexing is based on the calculation of V(N,K) (denoted N(L,K) in ), which is the number of possible combinations of K pulses +in N samples. The number of combinations can be computed recursively as +V(N,K) = V(N+1,K) + V(N,K+1) + V(N+1,K+1), with V(N,0) = 1 and V(0,K) = 0, K != 0. +There are many different ways to compute V(N,K), including pre-computed tables and direct +use of the recursive formulation. The reference implementation applies the recursive +formulation one line (or column) at a time to save on memory use, +along with an alternate, +univariate recurrence to initialise an arbitrary line, and direct +polynomial solutions for small N. All of these methods are +equivalent, and have different trade-offs in speed, memory usage, and +code size. Implementations MAY use any methods they like, as long as +they are equivalent to the mathematical definition. + + + +The indexing computations are performed using 32-bit unsigned integers. For large codebooks, +32-bit integers are not sufficient. Instead of using 64-bit integers (or more), the encoding +is made slightly sub-optimal by splitting each band into two equal (or near-equal) vectors of +size (N+1)/2 and N/2, respectively. The number of pulses in the first half, K1, is first encoded as an +integer in the range [0,K]. Then, two codebooks are encoded with V((N+1)/2, K1) and V(N/2, K-K1). +The split operation is performed recursively, in case one (or both) of the split vectors +still requires more than 32 bits. For compatibility reasons, the handling of codebooks of more +than 32 bits MUST be implemented with the splitting method, even if 64-bit arithmetic is available. + +
    + +
    + + +
    + +When encoding a stereo stream, some parameters are shared across the left and right channels, while others are transmitted separately for each channel, or jointly encoded. Only one copy of the flags for the features, transients and pitch (pitch period and gains) are transmitted. The coarse and fine energy parameters are transmitted separately for each channel. Both the coarse energy and fine energy (including the remaining fine bits at the end of the stream) have the left and right bands interleaved in the stream, with the left band encoded first. + + + +The main difference between mono and stereo coding is the PVQ coding of the normalized vectors. In stereo mode, a normalized mid-side (M-S) encoding is used. Let L and R be the normalized vector of a certain band for the left and right channels, respectively. The mid and side vectors are computed as M=L+R and S=L-R and no longer have unit norm. + + + +From M and S, an angular parameter theta=2/pi*atan2(||S||, ||M||) is computed. The theta parameter is converted to a Q14 fixed-point parameter itheta, which is quantized on a scale from 0 to 1 with an interval of 2^-qb, where qb = (b-2*(N-1)*(40-log2_frac(N,4)))/(32*(N-1)), b is the number of bits allocated to the band, and log2_frac() is defined in cwrs.c. From here on, the value of itheta MUST be treated in a bit-exact manner since +both the encoder and decoder rely on it to infer the bit allocation. + + +Let m=M/||M|| and s=S/||S||; m and s are separately encoded with the PVQ encoder described in . The number of bits allocated to m and s depends on the value of itheta. The number of bits allocated to coding m is obtained by: + + + + +imid = bitexact_cos(itheta); +iside = bitexact_cos(16384-itheta); +delta = (N-1)*(log2_frac(iside,6)-log2_frac(imid,6))>>2; +qalloc = log2_frac((1<<qb)+1,4); +mbits = (b-qalloc/2-delta)/2; + + + +where bitexact_cos() is a fixed-point cosine approximation that MUST be bit-exact with the reference implementation +in mathops.h. The spectral folding operation is performed independently for the mid and side vectors. +
    + + +
    + +After all the quantization is completed, the quantized energy is used along with the +quantized normalized band data to resynthesize the MDCT spectrum. The inverse MDCT () and the weighted overlap-add are applied and the signal is stored in the synthesis buffer so it can be used for pitch prediction. +The encoder MAY omit this step of the processing if it knows that it will not be using +the pitch predictor for the next few frames. If the de-emphasis filter () is applied to this resynthesized +signal, then the output will be the same (within numerical precision) as the decoder's output. + +
    + +
    + +Each CELT frame can be encoded in a different number of octets, making it possible to vary the bitrate at will. This property can be used to implement source-controlled variable bitrate (VBR). Support for VBR is OPTIONAL for the encoder, but a decoder MUST be prepared to decode a stream that changes its bit-rate dynamically. The method used to vary the bit-rate in VBR mode is left to the implementor, as long as each frame can be decoded by the reference decoder. + +
    + +
    + +
    + + +Like most audio codecs, the CELT decoder is less complex than the encoder, as can be +observed in the decoder block diagram in . In +fact, most of the operations performed by the decoder are also performed by the +encoder. + + +
    + +| Mix |->| * |->|IMDCT|-+-> output + +--+ +-----+ +---+ +-----+ | + ^ ^ | + +------+ | + | | + +--+ +-+-+ | + |Q2|-->| * | | + +--+ +---+ | + ^ | + | | + +------+-----+ | + +------------+ |Delay, MDCT,| | + |Pitch period|->| Normalize | | + +------------+ +------------+ | + ^ | + +--------------------+ +]]> + +Block diagram of the CELT decoder +
    + + +The decoder extracts information from the range-coded bit-stream in the same order +as it was encoded by the encoder. In some circumstances, it is +possible for a decoded value to be out of range due to a very small amount of redundancy +in the encoding of large integers by the range coder. +In that case, the decoder should assume there has been an error in the coding, +decoding, or transmission and SHOULD take measures to conceal the error and/or report +to the application that a problem has occurred. + + +
    + +The range decoder extracts the symbols and integers encoded using the range encoder in +. The range decoder maintains an internal +state vector composed of the two-tuple (dif,rng), representing the +difference between the high end of the current range and the actual +coded value, and the size of the current range, respectively. Both +dif and rng are 32-bit unsigned integer values. rng is initialized to +2^7. dif is initialized to rng minus the top 7 bits of the first +input octet. Then the range is immediately normalized, using the +procedure described in the following section. + + +
    + + Decoding symbols is a two-step process. The first step determines + a value fs that lies within the range of some symbol in the current + context. The second step updates the range decoder state with the + three-tuple (fl,fh,ft) corresponding to that symbol, as defined in + . + + + The first step is implemented by ec_decode() + (rangedec.c), + and computes fs = ft-min((dif-1)/(rng/ft)+1,ft), where ft is + the sum of the frequency counts in the current context, as described + in . The divisions here are exact integer division. + + + In the reference implementation, a special version of ec_decode() + called ec_decode_bin() (rangeenc.c) is defined using + the parameter ftb instead of ft. It is mathematically equivalent to + calling ec_decode() with ft = (1<<ftb), but avoids one of the + divisions. + + + The decoder then identifies the symbol in the current context + corresponding to fs; i.e., the one whose three-tuple (fl,fh,ft) + satisfies fl <= fs < fh. This tuple is used to update the decoder + state according to dif = dif - (rng/ft)*(ft-fh), and if fl is greater + than zero, rng = (rng/ft)*(fh-fl), or otherwise rng = rng - (rng/ft)*(ft-fh). After this update, the range is normalized. + + + To normalize the range, the following process is repeated until + rng > 2^23. First, rng is set to (rng<8)&0xFFFFFFFF. Then the next + 8 bits of input are read into sym, using the remaining bit from the + previous input octet as the high bit of sym, and the top 7 bits of the + next octet for the remaining bits of sym. If no more input octets + remain, zero bits are used instead. Then, dif is set to + (dif<<8)-sym&0xFFFFFFFF (i.e., using wrap-around if the subtraction + overflows a 32-bit register). Finally, if dif is larger than 2^31, + dif is then set to dif - 2^31. This process is carried out by + ec_dec_normalize() (rangedec.c). + +
    + +
    + + Functions ec_dec_uint() or ec_dec_bits() are based on ec_decode() and + decode one of N equiprobable symbols, each with a frequency of 1, + where N may be as large as 2^32-1. Because ec_decode() is limited to + a total frequency of 2^16-1, this is done by decoding a series of + symbols in smaller contexts. + + + ec_dec_bits() (entdec.c) is defined, like + ec_decode_bin(), to take a single parameter ftb, with ftb < 32. + and ftb < 32, and produces an ftb-bit decoded integer value, t, + initialized to zero. While ftb is greater than 8, it decodes the next + 8 most significant bits of the integer, s = ec_decode_bin(8), updates + the decoder state with the 3-tuple (s,s+1,256), adds those bits to + the current value of t, t = t<<8 | s, and subtracts 8 from ftb. Then + it decodes the remaining bits of the integer, s = ec_decode_bin(ftb), + updates the decoder state with the 3 tuple (s,s+1,1<<ftb), and adds + those bits to the final values of t, t = t<<ftb | s. + + + ec_dec_uint() (entdec.c) takes a single parameter, + ft, which is not necessarily a power of two, and returns an integer, + t, with a value between 0 and ft-1, inclusive, which is initialized to zero. Let + ftb be the location of the highest 1 bit in the two's-complement + representation of (ft-1), or -1 if no bits are set. If ftb>8, then + the top 8 bits of t are decoded using t = ec_decode((ft-1>>ftb-8)+1), + the decoder state is updated with the three-tuple + (s,s+1,(ft-1>>ftb-8)+1), and the remaining bits are decoded with + t = t<<ftb-8|ec_dec_bits(ftb-8). If, at this point, t >= ft, then + the current frame is corrupt, and decoding should stop. If the + original value of ftb was not greater than 8, then t is decoded with + t = ec_decode(ft), and the decoder state is updated with the + three-tuple (t,t+1,ft). + +
    + +
    + + The bit allocation routines in CELT need to be able to determine a + conservative upper bound on the number of bits that have been used + to decode from the current frame thus far. This drives allocation + decisions which must match those made in the encoder. This is + computed in the reference implementation to fractional bit precision + by the function ec_dec_tell() (rangedec.c). Like all + operations in the range decoder, it must be implemented in a + bit-exact manner, and must produce exactly the same value returned by + ec_enc_tell() after encoding the same symbols. + +
    + +
    + +
    + +The energy of each band is extracted from the bit-stream in two steps according +to the same coarse-fine strategy used in the encoder. First, the coarse energy is +decoded in unquant_coarse_energy() (quant_bands.c) +based on the probability of the Laplace model used by the encoder. + + + +After the coarse energy is decoded, the same allocation function as used in the +encoder is called (). This determines the number of +bits to decode for the fine energy quantization. The decoding of the fine energy bits +is performed by unquant_fine_energy() (quant_bands.c). +Finally, like the encoder, the remaining bits in the stream (that would otherwise go unused) +are decoded using unquant_energy_finalise() (quant_bands.c). + +
    + +
    + +If the pitch bit is set, then the pitch period is extracted from the bit-stream. The pitch +gain bits are extracted within the PVQ decoding as encoded by the encoder. When the folding +bit is set, the folding prediction is computed in exactly the same way as the encoder, +with the same gain, by the function intra_fold() (vq.c). + + +
    + +
    + +In order to correctly decode the PVQ codewords, the decoder must perform exactly the same +bits to pulses conversion as the encoder (see ). + + +
    + +The decoding of the codeword from the index is performed as specified in +, as implemented in function +decode_pulses() (cwrs.c). + +
    + +
    + +The spherical codebook is decoded by alg_unquant() (vq.c). +The index of the PVQ entry is obtained from the range coder and converted to +a pulse vector by decode_pulses() (cwrs.c). + + +The decoded normalized vector for each band is equal to +X' = y/||y||, + + +This operation is implemented in mix_pitch_and_residual() (vq.c), +which is the same function as used in the encoder. + +
    + + +
    + +
    + +Just like each band was normalized in the encoder, the last step of the decoder before +the inverse MDCT is to denormalize the bands. Each decoded normalized band is +multiplied by the square root of the decoded energy. This is done by denormalise_bands() +(bands.c). + +
    + +
    +The inverse MDCT implementation has no special characteristics. The +input is N frequency-domain samples and the output is 2*N time-domain +samples, while scaling by 1/2. The output is windowed using the same +low-overlap window +as the encoder. The IMDCT and windowing are performed by mdct_backward +(mdct.c). If a time-domain pre-emphasis +window was applied in the encoder, the (inverse) time-domain de-emphasis window +is applied on the IMDCT result. After the overlap-add process, +the signal is de-emphasized using the inverse of the pre-emphasis filter +used in the encoder: 1/A(z)=1/(1-alpha_p*z^-1). + + +
    + +
    + +Packet loss concealment (PLC) is an optional decoder-side feature which +SHOULD be included when transmitting over an unreliable channel. Because +PLC is not part of the bit-stream, there are several possible ways to +implement PLC with different complexity/quality trade-offs. The PLC in +the reference implementation finds a periodicity in the decoded +signal and repeats the windowed waveform using the pitch offset. The windowed +waveform is overlapped in such a way as to preserve the time-domain aliasing +cancellation with the previous frame and the next frame. This is implemented +in celt_decode_lost() (mdct.c). + +
    + +
    + + + +
    + + +A potential denial-of-service threat exists for data encodings using +compression techniques that have non-uniform receiver-end +computational load. The attacker can inject pathological datagrams +into the stream which are complex to decode and cause the receiver to +become overloaded. However, this encoding does not exhibit any +significant non-uniformity. + + + +With the exception of the first four bits, the bit-stream produced by +CELT for an unknown audio stream is not easily predictable, due to the +use of entropy coding. This should make CELT less vulnerable to attacks +based on plaintext guessing when encryption is used. Also, since almost +all possible bit combinations can be interpreted as a valid bit-stream, +it is likely more difficult to determine from the decrypted bit-stream +whether a guessed decryption key is valid. + + + +When operating CELT in variable-bitrate (VBR) mode, some of the +properties described above no longer hold. More specifically, the size +of the packet leaks a very small, but non-zero, amount of information +about both the original signal and the bit-stream plaintext. + +
    + + +
    + +This document has no actions for IANA. + +
    + + +
    + + +The authors would also like to thank the CELT users who contributed patches, bug reports, feature requests, suggestions or comments. + +
    + +
    + + + + + + + +Key words for use in RFCs to Indicate Requirement Levels + + + + + + + +RTP: A Transport Protocol for real-time applications + + + + + + + + + + + + + + + +A High-Quality Speech and Audio Codec With Less Than 10 ms delay + + + + + + + + + + +A Full-Bandwidth Audio Codec with Low Complexity and Very Low Delay + + + + + + + + + +The CELT ultra-low delay audio codec + + + + + + + +Modified Discrete Cosine Transform + + + + + + + +Range encoding: An algorithm for removing redundancy from a digitised message + + + + + + + + + +Source coding algorithms for fast data compression + + + + + + + + +A Pyramid Vector Quantizer + + + + + + + + +
    + +This appendix contains the complete source code for a floating-point +reference implementation of the CELT codec written in C. This +implementation is derived from version 0.8.1 of the implementation available on the +, which can be compiled for +either floating-point or fixed-point architectures. + + +The implementation can be compiled with either a C89 or a C99 +compiler. It is reasonably optimized for most platforms such that +only architecture-specific optimizations are likely to be useful. +The FFT used is a slightly modified version of the KISS-FFT package, +but it is easy to substitute any other FFT library. + + + +The testcelt executable can be used to test the encoding and decoding +process: + + + [ [packet loss rate]] +]]> + +where "rate" is the sampling rate in Hz, "channels" is the number of +channels (1 or 2), "frame size" is the number of samples in a frame +(64 to 1024) and "octets per packet" is the number of octets desired for each +compressed frame. The input and output files are assumed to be a 16-bit +PCM file in the machine native endianness. The optional "complexity" argument +can select the quality vs complexity tradeoff (0-10) and the "packet loss rate" +argument simulates random packet loss (argument is in tenths or a percent). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    diff --git a/native/codec/libraries/celt/doc/ietf/draft-valin-celt-rtp-profile-01.txt b/native/codec/libraries/celt/doc/ietf/draft-valin-celt-rtp-profile-01.txt new file mode 100644 index 0000000..cfdfddc --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/draft-valin-celt-rtp-profile-01.txt @@ -0,0 +1,1120 @@ + + + +AVT Working Group J-M. Valin +Internet-Draft Octasic Semiconductor +Expires: November 12, 2009 G. Maxwell + Juniper Networks + May 11, 2009 + + + draft-valin-celt-rtp-profile-01 + RTP Payload Format for the CELT Codec + +Status of this Memo + + This Internet-Draft is submitted to IETF in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on November 12, 2009. + +Copyright Notice + + Copyright (c) 2009 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents in effect on the date of + publication of this document (http://trustee.ietf.org/license-info). + Please review these documents carefully, as they describe your rights + and restrictions with respect to this document. + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 1] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +Abstract + + CELT is an open-source voice codec suitable for use in very low delay + audio communication applications, including Voice over IP (VoIP). + This document describes the payload format for CELT generated bit + streams within an RTP packet. Also included here are the necessary + details for the use of CELT with the Session Description Protocol + (SDP). At the time of this writing, the CELT bit-stream has NOT been + finalized yet, and compatibility is usually broken with every new + release of the codec. + + +Table of Contents + + 1. Conventions used in this document . . . . . . . . . . . . . . 3 + 2. Overview of the CELT Codec . . . . . . . . . . . . . . . . . . 4 + 3. RTP payload format for CELT . . . . . . . . . . . . . . . . . 5 + 3.1. RTP Header . . . . . . . . . . . . . . . . . . . . . . . . 5 + 3.2. CELT payload . . . . . . . . . . . . . . . . . . . . . . . 6 + 3.3. Multiple CELT frames in a RTP packet . . . . . . . . . . . 7 + 3.4. Multiple channels . . . . . . . . . . . . . . . . . . . . 8 + 4. MIME registration of CELT . . . . . . . . . . . . . . . . . . 10 + 5. SDP usage of CELT . . . . . . . . . . . . . . . . . . . . . . 12 + 5.1. Multichannel Mapping . . . . . . . . . . . . . . . . . . . 13 + 5.2. Low-Overhead Mode . . . . . . . . . . . . . . . . . . . . 15 + 6. Congestion Control . . . . . . . . . . . . . . . . . . . . . . 16 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 17 + 8. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 18 + 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 19 + 9.1. Normative References . . . . . . . . . . . . . . . . . . . 19 + 9.2. Informative References . . . . . . . . . . . . . . . . . . 19 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 20 + + + + + + + + + + + + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 2] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +1. Conventions used in this document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [rfc2119]. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 3] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +2. Overview of the CELT Codec + + CELT stands for "Constrained Energy Lapped Transform". It applies + some of the CELP principles, but does everything in the frequency + domain, which removes some of the limitations of CELP. CELT is + suitable for both speech and music and currently features: + + o Ultra-low algorithmic delay (as low as 2 ms) + + o Full audio bandwidth (up to 20 kHz audio bandwidth) + + o Support for both voice and music + + o Stereo support + + o Packet loss concealment + + o Constant bitrates from under 32 kbps to 128 kbps and above + + o Free software/open-source + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 4] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +3. RTP payload format for CELT + + For RTP based transportation of CELT encoded audio the standard RTP + header [rfc3550] is followed by one or more payload data blocks. An + optional padding terminator may also be used. + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | one or more frames of CELT .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +3.1. RTP Header + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The RTP header is defined in the RTP specification [rfc3550]. This + section defines how fields in the RTP header are used. + + Padding (P): 1 bit + + If the padding bit is set, the packet contains one or more additional + padding octets at the end which are not part of the payload. The + last octet of the padding contains a count of how many padding octets + should be ignored, including itself. Padding may be needed by some + encryption algorithms with fixed block sizes or for carrying several + RTP packets in a lower-layer protocol data unit. + + Extension (X): 1 bit + + If the extension, X, bit is set, the fixed header MUST be followed by + + + +Valin & Maxwell Expires November 12, 2009 [Page 5] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + + exactly one header extension, with a format defined in Section 5.3.1. + of [rfc3550]. + + Marker (M): 1 bit + + The M bit MUST be set to zero in all packets. The receiver MUST + ignore the M bit. + + Payload Type (PT): 7 bits + + Payload Type (PT): The assignment of an RTP payload type for this + packet format is outside the scope of this document; it is specified + by the RTP profile under which this payload format is used, or + signaled dynamically out-of-band (e.g., using SDP). + + Timestamp: 32 bits + + A timestamp representing the sampling time of the first sample of the + first CELT frame in the RTP payload. The clock frequency MUST be set + to the sample rate of the encoded audio data and is conveyed out-of- + band (e.g., as an SDP parameter). + +3.2. CELT payload + + For the purposes of packetizing the bit stream in RTP, it is only + necessary to consider the sequence of bits as output by the CELT + encoder [celt-website], and present the same sequence to the decoder. + The payload format described here maintains this sequence. + + A typical CELT frame, encoded at a high bitrate, is approx. 128 + octets and the total size of the CELT frames SHOULD be kept below the + path MTU to prevent fragmentation. CELT frames MUST NOT be split + across multiple RTP packets, + + An RTP packet MAY contain CELT frames of the same bit rate or of + varying bit rates, since the bitrate for the frames is explicitly + conveyed in band with the signal. The encoding and decoding + algorithm can change the bit rate at any frame boundary, with the bit + rate change notification provided in-band. No out-of-band + notification is required for the decoder to process changes in the + bit rate sent by the encoder. + + It is RECOMMENDED that sampling rates 32000, 44100, or 48000 Hz be + used for most applications, unless a specific reason exists -- such + as requirements for a very specific packetization time. For example, + 51200 Hz sampling may be useful to obtain a 5 ms packetization time + with 256-sample frames. For compatibility reasons, the sender and + receiver MUST support 48000 Hz sampling rate. + + + +Valin & Maxwell Expires November 12, 2009 [Page 6] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + + The CELT codec always produces an integer number of bytes and can + produce any integer number of bytes, so no padding is ever required. + Bitrate adjustment SHOULD be used instead of padding. + +3.3. Multiple CELT frames in a RTP packet + + The bitrate used by CELT is implicitly determined by the size of the + compressed data. When more than one frame is encoded in the same + packet, it is not possible to determine the size of each encoded + frame, so the information MUST be explicitly encoded. If N frames + are present in a packet, N compressed frame sizes need to be encoded + at the beginning of the packet. Each size that is less than 255 + bytes is encoded in one byte (unsigned 8-bit integer). For sizes + greater or equal to 255, a 0xff byte is encoded, followed by the + size-255. Multiple 0xff bytes are allowed if there are more than 510 + bytes transmitted. The length is always the size of the CELT frame + excluding the length byte itself. The payload MUST NOT be padded, + except in accordance with the padding bit definition in the RTP + header. + + Below is an example of two CELT frames contained within one RTP + packet. + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | length frame 1| length frame 2| CELT frame 1... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | (frame 1) | CELT frame 2... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | (frame 2) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The following is an example of C code that interprets the length + bytes: + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 7] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + + int i, N, pos; + int sizes[MAX_FRAMES][channels]; + unsigned int total_size; + total_size=0; + N = 0; + pos = 0; + while (total_size < payload_size) { + for (i=0;i + + Intended usage: COMMON + + Author/Change controller: + + Author: Jean-Marc Valin + + Change controller: Jean-Marc Valin + + Change controller: IETF AVT Working Group + + This transport type signifies that the content is to be interpreted + according to this document if the contents are transmitted over RTP. + Should this transport type appear over a lossless streaming protocol + such as TCP, the content encapsulation should be interpreted as an + Ogg Stream in accordance with [rfc3534], with the exception that the + content of the Ogg Stream may be assumed to be CELT audio and CELT + + + +Valin & Maxwell Expires November 12, 2009 [Page 10] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + + audio only. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 11] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +5. SDP usage of CELT + + When conveying information by SDP [rfc4566], the encoding name MUST + be set to "CELT". The sampling frequency is typically between 32000 + and 48000 Hz. Implementations MUST support 48000 Hz and SHOULD also + support 44100 Hz. + + The SDP parameters have the following interpretation with respect to + CELT: + + ptime: The desired packetization time. The sender SHOULD choose a + number of frames per packet that corresponds to the smallest + packetization time greater or equal to the specified ptime for the + selected frame size. The default is 20 ms as specified in + [rfc3551] + + maxptime: The maximum packetization time desired. As specified in + [rfc4566], if the maximum is lower than the smallest packetization + time determined from the chosen frame size (as described above), + then that packtization time SHOULD be used despite the maxptime + value. The default is "no maximum". + + CELT-specific parameters can be given via the "a=fmtp:" directive. + Several parameters can be given in a single a=fmtp line provided that + they are separated by a semi-colon. The following parameters are + defined for use in this way: + + bitrate: The desired bit-rate in kbit/s for the codec only + (excluding headers and the length bytes). The value MUST be + rounded to an integer number of bytes per frame. The round-to- + nearest method is RECOMMENDED. The default bit-rate value is 64 + kbit/s per channel. + + frame-size: The frame size is the duration of each frame in + samples and has to be even. The default is 480. + + mapping: Optional string describing the multi-channel mapping. + + The selected frame-size values MUST be even. For quality and + complexity reasons, they SHOULD also be divisible by 8 and have a + prime factorization which consists only of 2, 3, or 5 factors. For + example, powers-of-two and values such as 160, 320, 240, and 480 are + recommended. Implementations MUST support receiving and sending the + default value of 480. Implementations SHOULD also support frame + sizes of 256 and 512 since these are the ones that lead to the lowest + complexity. When frame sizes that are powers-of-two are supported, + they SHOULD be listed first in the offer and chosen over non-powers- + of-two in the answer. + + + +Valin & Maxwell Expires November 12, 2009 [Page 12] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + + Care must be taken when setting the value of ptime: and bitrate: so + that the RTP packet size does not exceed the path MTU. + + An example of the media representation in SDP for offering a single + channel of CELT at 48000 samples per second might be: + + + m=audio 8088 RTP/AVP 97 + + a=rtpmap:97 CELT/48000/1 + + Note that the RTP payload type code of 97 is defined in this media + definition to be 'mapped' to the CELT codec at a 48 kHz sampling + frequency using the 'a=rtpmap' line. Any number from 96 to 127 could + have been chosen (the allowed range for dynamic types). If there is + more than one channel being encoded the rtpmap MUST specify the + channel count. When no channel count is included, the default is one + channel. + + The following example demonstrates the use of the a=fmtp: parameters: + + + m=audio 8008 RTP/AVP 97 + + a=ptime: 25 + + a=rtpmap:97 CELT/44100 + + a=fmtp:97 frame-size=512;bitrate=48 + + This examples illustrate an offerer that wishes to receive a CELT + stream at 44100 Hz, by packing two 512-sample frames in each packet + (less than 25 ms) at around 48 kbps (70 bytes per frame). + +5.1. Multichannel Mapping + + When more than two channels are used, a mapping parameter MUST be + provided. The mapping parameter is defined as comma separated list + of integers which specify the number of channels contained in each + CELT stream, OPTIONALLY followed by a '/' and a comma separated list + of channel identifiers, then OPTIONALLY another '/' and a string + which provides an application specific elaboration on any speaker- + feed definitions. The channels per stream entries MUST be either 1 + or 2. The total number of channels is indicated by the sum of the + channels per stream entries. The sum of the channel counts MUST be + equal to the total number of channels. + + Channel identifiers are short alphanumeric strings. Each identifier + + + +Valin & Maxwell Expires November 12, 2009 [Page 13] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + + MUST begin with a letter indicating the type of channel. 'A' MUST be + used to indicate an ambisonic channel, 'S' to indicate a speaker-feed + channel, or 'O' indicating other usage. + + A channel identifier MAY be repeated, but the meaning of such + repetition is application specific. Applications SHOULD attempt to + utilize channel identifiers such that mixing all identical + identifiers would produce a reasonable result. + + Non-surround usage such as individual performer tracks, effect send, + "order wire", or other administrative channels may be given + application specific identifiers which MUST not conflict with the + identifiers defined in this draft. These identifiers SHOULD begin + with S if it would be sensible to include them in a mono-downmix, or + O if it would be most sensible to exclude them from a mono-downmix. + An example usage might be mapping=2,1,2,1,1/ + SLguitar,SRguitar,OheadsetG,SLkeyboard,SRkeyboard,OheadsetK,SMbass,Oh + eadsetB" + + Ambisonic channels MUST follow the Furse-Malham naming and weighing + conventions for up to third order spherical[Ambisonic]. Higher order + ambisonic support is application defined but MUST NOT reuse any of + WXYZRSTUVKLMNOPQ for higher order components. For example, second + order spherical ambisonics SHOULD use the mapping + "mapping=1,1,1,1,1,1,1,1,1/AW,AX,AY,AZ,AR,AS,AT,AU,AV". Any set of + Ambisonic channels MUST contain at least one "AW" channel. + + Speaker-feed identifiers are named based on the intended speaker + locations. "L", "R" for the left and right speakers, respectively, + in conventional stereo or the front left and right in 4, 5, 5.1, or + 7.1 channel surround. "LR", "RR" for the left and right rear + speakers in 4,5 or 5.1 channel surround. C" is used for a center + channel, "MLFE" for a low frequency extension channel. "LS", "RS" + for the side channels in 7.1 channel surround. Additional speaker- + feeds are application specific but should not reuse the prior + identifiers. For 5.1 surround in non-ambisonic form the mapping + SHOULD be "mapping=2,2,1,1/L,R,LR,RR,C,MLFE/ITU-RBS.775-1". When + only one or two channels are used, the mapping parameter MAY be + omitted, in which case the default mapping is used. For one channel, + the default is "mapping=1/C", while for two channels, the default is + "mapping=2/L,R". + + For example a stereo configuration might signal: + + + m=audio 8008 RTP/AVP 97 + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 14] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + + a=ptime: 5 + + a=rtpmap:97 CELT/44100/2 + + a=fmtp:97 frame-size=256 + + Which specifies a single two-channel CELT stream according to the + default mapping. + +5.2. Low-Overhead Mode + + A low-overhead mode is defined to make more efficient use of + bandwidth when transmitting CELT frames. In that mode none of the + length values need to be transmitted. One the a=fmtp: parameter low- + overhead: is defined and contains a single frame size, followed by a + '/', followed by a comma-separated list of the number of bytes per + frame for each stream defined in the channel mapping. The number of + frames per channel can thus be computed as the payload size divided + by the sum of the bytes-per-frame values. The frame-size: parameter + MUST not be specified and SHOULD be ignored if encountered in an SDP + offer or answer. The bitrate: parameter MUST also be ignored since + the low-overhead: parameter makes it redundant. When the low- + overhead: parameter is specified, the length of each frame MUST NOT + be encoded in the payload and the bit-rate MUST NOT be changed during + the session. + + For example a low-overhead surround configuration could be signaled + as: + + m=audio 8008 RTP/AVP 97 + + a=ptime: 5 + + a=rtpmap:97 CELT/48000/6 + + a=fmtp:97 low-overhead=256/1/86,86,43,30;mapping=2,2,1,1/ + L,R,LR,RR,C,MLFE/ITU-RBS.775-1 + + In this example, 4 bytes per packet would be saved. This corresponds + to a 6 kbit/s reduction in the overhead, although the 60 kbit/s + overhead of the IP, UDP and RTP headers is still present. + + + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 15] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +6. Congestion Control + + CELT allows any bitrate, with a one byte per frame resolution, + without any signaling requirement or overhead. Applications SHOULD + utilize congestion control to regulate the transmitted bitrate. In + some applications it may make sense to increase the packetization + interval rather than decreasing the codec bitrate. Congestion + control implementations should consider the users differential + tolerance for high latency and low quality. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 16] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +7. Security Considerations + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification [rfc3550], and in any applicable RTP profile. The main + security considerations for the RTP packet carrying the RTP payload + format defined within this memo are confidentiality, integrity and + source authenticity. Confidentiality is achieved by encryption of + the RTP payload. Integrity of the RTP packets through suitable + cryptographic integrity protection mechanism. Cryptographic system + may also allow the authentication of the source of the payload. A + suitable security mechanism for this RTP payload format should + provide confidentiality, integrity protection and at least source + authentication capable of determining if an RTP packet is from a + member of the RTP session or not. + + Note that the appropriate mechanism to provide security to RTP and + payloads following this memo may vary. It is dependent on the + application, the transport, and the signalling protocol employed. + Therefore a single mechanism is not sufficient, although if suitable + the usage of SRTP [rfc3711] is recommended. Other mechanism that may + be used are IPsec [rfc4301] and TLS [rfc5246] (RTP over TCP), but + also other alternatives may exist. + + This RTP payload format and its media decoder do not exhibit any + significant non-uniformity in the receiver-side computational + complexity for packet processing, and thus are unlikely to pose a + denial-of-service threat due to the receipt of pathological data. + Nor does the RTP payload format contain any active content. + + Because this format supports VBR operation small amounts of + information about the transmitted audio may be leaked by a length + preserving cryptographic transport. Accordingly, when CELT is used + inside a secure transport the sender SHOULD restrict the use of VBR + to congestion control purposes. + + CELT implementations will typically exhibit tiny content-sensitive + encoding time variances. Since transmission is usually triggered by + an accurate hardware clock and the encoded data is typically + transmitted as soon as encoding is complete this variance may result + in a small amount of additional frame to frame jitter which could be + measured by a third-party. Encrypted implementations SHOULD transmit + packets at fixed intervals to avoid the possible information leak. + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 17] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +8. Acknowledgments + + The authors would also like to thank the following people for their + input: Timothy B. Terriberry, Ben Schwartz, Alexander Carot, Thorvald + Natvig, Brian West, Steve Underwood, and Anthony Minessale. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 18] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +9. References + +9.1. Normative References + + [rfc2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", RFC 2119. + + [rfc3550] Schulzrinne, H., Casner, S., Frederick, R., and V. + Jacobson, "RTP: A Transport Protocol for real-time + applications", RFC 3550. + + [rfc2045] "Multipurpose Internet Mail Extensions (MIME) Part One: + Format of Internet Message Bodies", RFC 2045, + November 1998. + + [rfc4566] Handley, M., Jacobson, V., and C. Perkins, "SDP: Session + Description Protocol", RFC 4566, July 2006. + + [rfc3551] Schulzrinne, H. and S. Casner, "RTP Profile for Audio and + Video Conferences with Minimal Control.", RFC 3551, + July 2003. + + [rfc3534] Walleij, L., "The application/ogg Media Type", RFC 3534, + May 2003. + + [rfc3711] Baugher, M., McGrew, D., Naslund, M., Carrara, E., and K. + Norrman, "The Secure Real-time Transport Protocol (SRTP)", + RFC 3711, March 2004. + + [rfc4301] Kent, S. and K. Seo, "Security Architecture for the + Internet Protocol", RFC 4301, December 2005. + + [rfc5246] Dierks, T. and E. Rescorla, "The Transport Layer Security + (TLS) Protocol Version 1.2", RFC 5246, August 2008. + +9.2. Informative References + + [celt-website] + Xiph.Org Foundation, "The CELT ultra-low delay audio + codec", CELT website http://www.celt-codec.org/. + + [Ambisonic] + Malham, D., "Higher order Ambisonic systems", Paper http:/ + /www.york.ac.uk/inst/mustech/3d_audio/ + higher_order_ambisonics.pdf, December 2003. + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 19] + +Internet-Draft draft-valin-celt-rtp-profile-01 May 2009 + + +Authors' Addresses + + Jean-Marc Valin + Octasic Semiconductor + 4101, Molson Street, suite 300 + Montreal, Quebec H1Y 3L1 + Canada + + Email: jean-marc.valin@octasic.com + + + Gregory Maxwell + Juniper Networks + 2251 Corporate Park Drive, Suite 100 + Herndon, VA 20171-1817 + USA + + Email: gmaxwell@juniper.net + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Valin & Maxwell Expires November 12, 2009 [Page 20] + diff --git a/native/codec/libraries/celt/doc/ietf/draft-valin-celt-rtp-profile.xml b/native/codec/libraries/celt/doc/ietf/draft-valin-celt-rtp-profile.xml new file mode 100644 index 0000000..3caff42 --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/draft-valin-celt-rtp-profile.xml @@ -0,0 +1,816 @@ + + + + + + + +draft-valin-celt-rtp-profile-02 + + + + +Octasic Semiconductor +
    + +4101, Molson Street, suite 300 +Montreal +Quebec +H1Y 3L1 +Canada + +jean-marc.valin@octasic.com +
    +
    + + + +Juniper Networks +
    + +2251 Corporate Park Drive, Suite 100 +Herndon +VA +20171-1817 +USA + +gmaxwell@juniper.net +
    +
    + + + +General +AVT Working Group +I-D + +Internet-Draft +CELT +RTP + + +CELT is an open-source voice codec suitable for use in very low delay +audio communication applications, including Voice over IP (VoIP). +This document describes the payload format for CELT generated bit +streams within an RTP packet. Also included here are the necessary +details for the use of CELT with the Session Description Protocol +(SDP). At the time of this writing, the CELT bit-stream has NOT +been finalized yet, and compatibility is usually broken with +every new release of the codec. + + +
    + + + +
    + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this +document are to be interpreted as described in RFC 2119 . + +
    + +
    + + +CELT stands for "Constrained Energy Lapped Transform". It applies some of the CELP principles, but does everything in the frequency domain, which removes some of the limitations of CELP. CELT is suitable for both speech and music and currently features: + + + + +Ultra-low algorithmic delay (as low as 2 ms) +Full audio bandwidth (up to 20 kHz audio bandwidth) +Support for both voice and music +Stereo support +Packet loss concealment +Constant bitrates from under 32 kbps to 128 kbps and above +Free software/open-source + + + +
    + +
    + + +For RTP based transportation of CELT encoded audio the standard +RTP header is followed by one or more payload data blocks. +An optional padding terminator may also be used. + + +
    + + +
    + +
    +
    + + +The RTP header is defined in the RTP specification . This + section defines how fields in the RTP header are used. + + +Padding (P): 1 bit + If the padding bit is set, the packet contains one or more + additional padding octets at the end which are not part of the + payload. The last octet of the padding contains a count of how + many padding octets should be ignored, including itself. Padding + may be needed by some encryption algorithms with fixed block sizes + or for carrying several RTP packets in a lower-layer protocol data + unit. + + +Extension (X): 1 bit + If the extension, X, bit is set, the fixed header MUST be + followed by exactly one header extension, with a format defined + in Section 5.3.1. of . + + +Marker (M): 1 bit + The M bit MUST be set to zero in all packets. The receiver MUST + ignore the M bit. + + +Payload Type (PT): 7 bits + Payload Type (PT): The assignment of an RTP payload type for this + packet format is outside the scope of this document; it is + specified by the RTP profile under which this payload format is + used, or signaled dynamically out-of-band (e.g., using SDP). + + +Timestamp: 32 bits + A timestamp representing the sampling time of the first sample of + the first CELT frame in the RTP payload. The clock frequency + MUST be set to the sample rate of the encoded audio data and is + conveyed out-of-band (e.g., as an SDP parameter). + + + +
    + +
    + + +For the purposes of packetizing the bit stream in RTP, it is only +necessary to consider the sequence of bits as output by the CELT +encoder , and present the same +sequence to the decoder. The payload format described here maintains +this sequence. + + + +A typical CELT frame, encoded at a high bitrate, is approx. +128 octets and the total size of the CELT frames SHOULD be kept +below the path MTU to prevent fragmentation. CELT frames MUST +NOT be split across multiple RTP packets, + + + +An RTP packet MAY contain CELT frames of the same bit rate or of +varying bit rates, since the bitrate for the frames is explicitly +conveyed in band with the signal. The encoding and decoding algorithm +can change the bit rate at any frame boundary, with the bit rate +change notification provided in-band. No out-of-band notification +is required for the decoder to process changes in the bit rate +sent by the encoder. + + + +More than one frame may be encoded in the same RTP packet, and for +the decoder it is not possible to determine the compressed size (bit-rate) +of each encoded frame. Thus the compressed size information MUST be explicitly +transmitted. There are two modes for conveying this information: +either the compressed size(s) are encoded for each frame at the +beginning of the RTP payload , or it is conveyed in the +signaling and then fixed for the duration of the session +(Low-Overhead Mode, ). Note that the compressed frame size +information must be present either way even if only single frames +are transmitted per RTP packet. + + + +It is RECOMMENDED that sampling rates 32000, 44100, or 48000 Hz be used +for most applications, unless a specific reason exists -- such as +requirements for a very specific packetization time. For example, +51200 Hz sampling may be useful to obtain a 5 ms packetization time +with 256-sample frames. For compatibility reasons, the sender and +receiver MUST support 48000 Hz sampling rate. + + + +The CELT codec always produces an integer number of bytes and can +produce any integer number of bytes, so no padding is ever required. +Bitrate adjustment SHOULD be used instead of padding. + + +
    + +
    + + +The bitrate used by CELT is implicitly determined by the size of the +compressed data. When more than one frame is encoded in the same packet, +it is not possible to determine the size of each encoded frame, so the +information MUST be explicitly encoded. If N frames are present in a +packet, N compressed frame sizes need to be encoded at the beginning of +the packet. Each size that is less than 255 bytes is encoded in one byte +(unsigned 8-bit integer). For sizes greater or equal to 255, a 0xff byte +is encoded, followed by the size-255. Multiple 0xff bytes are allowed if +there are more than 510 bytes transmitted. The length is always the size +of the CELT frame excluding the length byte itself. The payload MUST NOT +be padded, except in accordance with the padding bit definition in the +RTP header. + + + +Below is an example of two CELT frames contained within one RTP +packet. + + +
    + +
    + +The following is an example of C code that interprets the length bytes: + + +
    + +
    + +
    + +
    + +CELT supports both mono streams and stereo streams. If more than two channels are desired, it is possible to use transmit multiple streams in the same packet. In this case, the number of streams S and the pairing must be agreed with out-of-band negotiation such as SDP. Each stream can be either mono or stereo, depending on whether the channels are assumed to be correlated. For example, a 5.1 surround could have the front-left and front-right channels in a stereo stream, the rear-left and rear-right channels in a separate stereo stream, while the center and low-frequency channels would be in separate mono streams. In that example, the RTP packet would be: + +
    + +
    + +In the case where streams for multiple channels are used with multiple frames of the same streams per packet, then all streams for a certain timestamp are encoded before all streams for the following timestamp. In the case of the 5.1 example above with two frames per packet, the number of compressed length fields would be S*N = 8. + +
    + +
    + +
    + + +Full definition of the MIME type for CELT will be part of the Ogg +Vorbis MIME type definition application . + + +MIME media type name: audio + +MIME subtype: celt + +Optional parameters: + +Required parameters: to be included in the Ogg MIME specification. + +Encoding considerations: + +Security Considerations: +See Section 6 of RFC 3047. + +Interoperability considerations: none + +Published specification: + +Applications which use this media type: + +Additional information: none + +Person & email address to contact for further information: + +Jean-Marc Valin <jean-marc.valin@octasic.com> + + + +Intended usage: COMMON + +Author/Change controller: + + + +Author: Jean-Marc Valin <jean-marc.valin@octasic.com> +Change controller: Jean-Marc Valin <jean-marc.valin@octasic.com> +Change controller: IETF AVT Working Group + + + + +This transport type signifies that the content is to be interpreted +according to this document if the contents are transmitted over RTP. +Should this transport type appear over a lossless streaming protocol +such as TCP, the content encapsulation should be interpreted as an +Ogg Stream in accordance with , with the exception that the +content of the Ogg Stream may be assumed to be CELT audio and +CELT audio only. + + +
    + +
    + + +When conveying information by SDP , the encoding name MUST be +set to "CELT". The sampling frequency is typically between 32000 and 48000 Hz. +Implementations MUST support 48000 Hz and SHOULD also support 44100 Hz. + + + +The SDP parameters have the following interpretation with respect to CELT: + + + + +ptime: The desired packetization time. The sender SHOULD choose a number of frames per packet that corresponds to the smallest packetization time greater or equal to the specified ptime for the selected frame size. The default is 20 ms as specified in + +maxptime: The maximum packetization time desired. As specified in , if the maximum is lower than the smallest packetization time determined from the chosen frame size (as described above), then that packtization time SHOULD be used despite the maxptime value. The default is "no maximum". + + + + + +CELT-specific parameters can be given via the "a=fmtp:" directive. +Several parameters can be given in a single a=fmtp line provided +that they are separated by a semi-colon. The following parameters +are defined for use in this way: + + + + +bitrate: The desired bit-rate in kbit/s for the codec only (excluding +headers and the length bytes). The value MUST be rounded to an integer number +of bytes per frame. The round-to-nearest method is RECOMMENDED. The default +bit-rate value is 64 kbit/s per channel. + +frame-size: The frame size is the duration of each frame in samples and has to be even. +The default is 480. + +mapping: Optional string describing the multi-channel mapping. + + + + +The selected frame-size values MUST be even. For quality and complexity +reasons, they SHOULD also be divisible by 8 and have a prime factorization +which consists only of 2, 3, or 5 factors. +For example, powers-of-two and values such as 160, 320, 240, and 480 are +recommended. Implementations MUST support receiving and sending the default +value of 480. Implementations +SHOULD also support frame sizes of 256 and 512 since these are the ones that lead +to the lowest complexity. When frame sizes that are powers-of-two are supported, +they SHOULD be listed first in the offer and chosen over non-powers-of-two in the +answer. + + + +Care must be taken when setting the value of ptime: and bitrate: so that the +RTP packet size does not exceed the path MTU. + + +An example of the media representation in SDP for offering a single +channel of CELT at 48000 samples per second might be: + + + + + +m=audio 8088 RTP/AVP 97 +a=rtpmap:97 CELT/48000/1 + + + + +Note that the RTP payload type code of 97 is defined in this media +definition to be 'mapped' to the CELT codec at a 48 kHz sampling +frequency using the 'a=rtpmap' line. Any number from 96 to 127 +could have been chosen (the allowed range for dynamic types). If there +is more than one channel being encoded the rtpmap MUST specify the channel +count. When no channel count is included, the default is one channel. + + + +The following example demonstrates the use of the a=fmtp: parameters: + + + + + m=audio 8008 RTP/AVP 97 + a=ptime: 25 + a=rtpmap:97 CELT/44100 + a=fmtp:97 frame-size=512;bitrate=48 + + + + +This examples illustrate an offerer that wishes to receive a CELT stream at +44100 Hz, by packing two 512-sample frames in each packet (less than 25 ms) +at around 48 kbps (70 bytes per frame). + + +
    + +When more than two channels are used, a mapping parameter MUST be provided. +The mapping parameter is defined as comma separated list of integers which specify the +number of channels contained in each CELT stream, OPTIONALLY followed by a '/' and a +comma separated list of channel identifiers, then OPTIONALLY another '/' and a string +which provides an application specific elaboration on any speaker-feed definitions. +The channels per stream entries MUST be either 1 or 2. The total number of +channels is indicated by the sum of the channels per stream entries. The sum +of the channel counts MUST be equal to the total number of channels. + + + +Channel identifiers are short alphanumeric strings. +Each identifier MUST begin with a letter indicating the type of channel. 'A' MUST be +used to indicate an ambisonic channel, 'S' to indicate a speaker-feed channel, or 'O' +indicating other usage. + + + +A channel identifier MAY be repeated, but the meaning of such repetition is application specific. +Applications SHOULD attempt to utilize channel identifiers such that mixing all identical identifiers +would produce a reasonable result. + + + +Non-surround usage such as individual performer tracks, effect send, "order wire", or +other administrative channels may be given application specific identifiers +which MUST not conflict with the identifiers defined in this draft. These +identifiers SHOULD begin with S if it would be sensible to include them in a +mono-downmix, or O if it would be most sensible to exclude them from a +mono-downmix. +An example usage might be +mapping=2,1,2,1,1/SLguitar,SRguitar,OheadsetG,SLkeyboard,SRkeyboard,OheadsetK,SMbass,OheadsetB" + + + +Ambisonic channels MUST follow the Furse-Malham naming and weighing +conventions for up to third order spherical. +Higher order ambisonic support is application defined but MUST NOT reuse any of WXYZRSTUVKLMNOPQ +for higher order components. For example, second order spherical ambisonics SHOULD use the +mapping "mapping=1,1,1,1,1,1,1,1,1/AW,AX,AY,AZ,AR,AS,AT,AU,AV". Any set of Ambisonic channels +MUST contain at least one "AW" channel. + + + +Speaker-feed identifiers are named based on the intended speaker locations. "L", "R" for the left and +right speakers, respectively, in conventional stereo or the front left and right in 4, 5, +5.1, or 7.1 channel surround. "LR", "RR" for the left and right rear speakers in 4,5 or 5.1 channel surround. C" is used for a center channel, "MLFE" for a low frequency extension channel. "LS", "RS" for the side +channels in 7.1 channel surround. Additional speaker-feeds are application specific but should not +reuse the prior identifiers. +For 5.1 surround in non-ambisonic form the mapping SHOULD be "mapping=2,2,1,1/L,R,LR,RR,C,MLFE/ITU-RBS.775-1". +When only one or two channels are used, the mapping parameter MAY be omitted, in which case the +default mapping is used. For one channel, the default is "mapping=1/C", while for two channels, +the default is "mapping=2/L,R". + + + +For example a stereo configuration might signal: + + +m=audio 8008 RTP/AVP 97 +a=ptime: 5 +a=rtpmap:97 CELT/44100/2 +a=fmtp:97 frame-size=256 + +Which specifies a single two-channel CELT stream according to the default +mapping. + + +
    + +
    + +A low-overhead mode is defined to make more efficient use of bandwidth +when transmitting CELT frames. In that mode none of the length values need to be transmitted. +One the a=fmtp: parameter low-overhead: +is defined and contains a single frame size, followed by a '/', followed by a comma-separated +list of the number of bytes per frame for each stream defined in the channel mapping. The number of frames per channel can thus be computed as the payload size divided by the sum of the bytes-per-frame values. +The frame-size: parameter MUST not be specified and SHOULD be ignored if encountered +in an SDP offer or answer. The bitrate: parameter MUST also be +ignored since the low-overhead: parameter makes it redundant. When the low-overhead: +parameter is specified, the length of each frame MUST NOT be encoded in the payload and +the bit-rate MUST NOT be changed during the session. + + + +For example a low-overhead 64 kbit/s mono stream could be signaled as: + +m=audio 8008 RTP/AVP 97 +a=ptime: 5 +a=rtpmap:97 CELT/48000/1 +a=fmtp:97 low-overhead=256/43 + + +and a low-overhead 360 kbit/s 5.1 surround configuration could be signaled as: + +m=audio 8008 RTP/AVP 97 +a=ptime: 5 +a=rtpmap:97 CELT/48000/6 +a=fmtp:97 low-overhead=256/86,86,43,25;mapping=2,2,1,1/L,R,LR,RR,C,MLFE/ITU-RBS.775-1 + + +In this last example, 4 bytes per packet would be saved. This corresponds to a 6 kbit/s +reduction in the overhead, although the 60 kbit/s overhead of the IP, UDP and RTP +headers is still present. + + +
    + +
    + +
    + + +CELT allows any bitrate, with a one byte per frame +resolution, without any signaling requirement or overhead. +Applications SHOULD utilize congestion control to regulate the transmitted bitrate. +In some applications it may make sense to increase the packetization +interval rather than decreasing the codec bitrate. Congestion control +implementations should consider the users differential tolerance for high +latency and low quality. + +
    + +
    + + +RTP packets using the payload format defined in this specification +are subject to the security considerations discussed in the RTP +specification , and in any applicable RTP profile. The +main security considerations for the RTP packet carrying the RTP +payload format defined within this memo are confidentiality, +integrity and source authenticity. Confidentiality is achieved by +encryption of the RTP payload. Integrity of the RTP packets through +suitable cryptographic integrity protection mechanism. Cryptographic +system may also allow the authentication of the source of the +payload. A suitable security mechanism for this RTP payload format +should provide confidentiality, integrity protection and at least +source authentication capable of determining if an RTP packet is from +a member of the RTP session or not. + + + +Note that the appropriate mechanism to provide security to RTP and +payloads following this memo may vary. It is dependent on the +application, the transport, and the signalling protocol employed. +Therefore a single mechanism is not sufficient, although if suitable +the usage of SRTP is recommended. Other mechanism that may +be used are IPsec and TLS (RTP over TCP), but also other alternatives may exist. + + + +This RTP payload format and its media decoder do not exhibit any +significant non-uniformity in the receiver-side computational +complexity for packet processing, and thus are unlikely to pose a +denial-of-service threat due to the receipt of pathological data. +Nor does the RTP payload format contain any active content. + + + +Because this format supports VBR operation small amounts of information +about the transmitted audio may be leaked by a length preserving +cryptographic transport. Accordingly, when CELT is used inside a secure +transport the sender SHOULD restrict the use of VBR to congestion control purposes. + + + +CELT implementations will typically exhibit tiny content-sensitive encoding +time variances. Since transmission is usually triggered by an accurate +hardware clock and the encoded data is typically transmitted as soon as +encoding is complete this variance may result in a small amount of +additional frame to frame jitter which could be measured by a third-party. +Encrypted implementations SHOULD transmit packets at fixed intervals to +avoid the possible information leak. + + +
    + +
    + + +The authors would also like to thank the following people for their input: +Timothy B. Terriberry, Ben Schwartz, Alexander Carot, Thorvald Natvig, +Brian West, Steve Underwood, and Anthony Minessale. + + +
    + +
    + + + + + + + +Key words for use in RFCs to Indicate Requirement Levels + + + + + + + +RTP: A Transport Protocol for real-time applications + + + + + + + + + + +Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies + + + + + + + + +SDP: Session Description Protocol + + + + + + + + + + +RTP Profile for Audio and Video Conferences with Minimal Control. + + + + + + + + + +The application/ogg Media Type + + + + + + + + +The Secure Real-time Transport Protocol (SRTP) + + + + + + + + + + + + +Security Architecture for the Internet Protocol + + + + + + + + + +The Transport Layer Security (TLS) Protocol Version 1.2 + + + + + + + + + + + + + + +The CELT ultra-low delay audio codec + + + + + + + +Higher order Ambisonic systems + + + + + + + + + +
    diff --git a/native/codec/libraries/celt/doc/ietf/ietf_source.sh b/native/codec/libraries/celt/doc/ietf/ietf_source.sh new file mode 100755 index 0000000..34a0fe8 --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/ietf_source.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +mkdir -p xml_source + +for i in `ls source/ | grep '\.[ch]$'` Makefile +do + +echo "
    " > xml_source/$i +echo '' >> xml_source/$i +echo '
    > xml_source/$i + +cat source/$i >> xml_source/$i + +echo ']]>
    ' >> xml_source/$i +echo '
    ' >> xml_source/$i +echo '
    ' >> xml_source/$i + +done \ No newline at end of file diff --git a/native/codec/libraries/celt/doc/ietf/substitutions.h b/native/codec/libraries/celt/doc/ietf/substitutions.h new file mode 100644 index 0000000..3920225 --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/substitutions.h @@ -0,0 +1,99 @@ +#define IMUL32(a,b) ((a)*(b)) +#define UMUL32(a,b) ((a)*(b)) +#define UMUL16_16(a,b) ((a)*(b)) + +#define celt_word16 float +#define celt_word32 float + +#define celt_sig float +#define celt_norm float +#define celt_ener float +#define celt_pgain float +#define celt_mask float + +#define UADD32(a,b) ((a)+(b)) +#define USUB32(a,b) ((a)-(b)) + + +#define Q15ONE 1.0f +#define Q30ONE 1.0f + +#define NORM_SCALING 1.f +#define NORM_SCALING_1 1.f +#define ENER_SCALING 1.f +#define ENER_SCALING_1 1.f +#define PGAIN_SCALING 1.f +#define PGAIN_SCALING_1 1.f + +#define DB_SCALING 1.f +#define DB_SCALING_1 1.f + +#define EPSILON 1e-15f +#define VERY_SMALL 1e-15f +#define VERY_LARGE32 1e15f +#define VERY_LARGE16 1e15f +#define Q15_ONE 1.f +#define Q15_ONE_1 1.f + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR16(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) +#define SATURATE16(x,a) (x) +#define SATURATE32(x,a) (x) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ROUND16(a,shift) (a) +#define HALF32(x) (.5f*(x)) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((a)*(b)) +#define MAC16_16(c,a,b) ((c)+(a)*(b)) + +#define MULT16_32_Q11(a,b) ((a)*(b)) +#define MULT16_32_Q13(a,b) ((a)*(b)) +#define MULT16_32_Q14(a,b) ((a)*(b)) +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_Q16(a,b) ((a)*(b)) +#define MULT16_32_P15(a,b) ((a)*(b)) + +#define MULT32_32_Q31(a,b) ((a)*(b)) + +#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) + +#define DIV32_16(a,b) ((a)/(b)) +#define PDIV32_16(a,b) ((a)/(b)) +#define DIV32(a,b) ((a)/(b)) +#define PDIV32(a,b) ((a)/(b)) + +#define PRINT_MIPS(x) diff --git a/native/codec/libraries/celt/doc/ietf/wrap_lines.c b/native/codec/libraries/celt/doc/ietf/wrap_lines.c new file mode 100644 index 0000000..c78fde5 --- /dev/null +++ b/native/codec/libraries/celt/doc/ietf/wrap_lines.c @@ -0,0 +1,34 @@ +#include +#include + +int main() +{ + int comment = 0; + int col = 0; + char c0, c1; + c0 = getchar(); + while (!feof(stdin)) + { + c1 = getchar(); + if (c1==9) + c1 = 32; + if (col < 71 || c0 == 10) { + putchar(c0); + } else { + if (c1 == 10 || c1 == 13) + { + putchar(c0); + } else { + putchar ('\\'); + /*printf ("%d %d %d", col, c0, c1);*/ + putchar (10); + putchar (c0); + col=0; + } + } + col++; + if (c0 == 10) + col=0; + c0 = c1; + } +} \ No newline at end of file diff --git a/native/codec/libraries/celt/libcelt.spec.in b/native/codec/libraries/celt/libcelt.spec.in new file mode 100644 index 0000000..64cb0e3 --- /dev/null +++ b/native/codec/libraries/celt/libcelt.spec.in @@ -0,0 +1,84 @@ +Summary: The CELT Low-Latency Audio Compression Codec. +Name: libcelt +Version: @CELT_VERSION@ +Release: 0%{?dist} +Epoch: 0 +Group: System Environment/Libraries +License: BSD +URL: http://www.xiph.org/ +Source: http://downloads.xiph.org/releases/celt/celt-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: libogg-devel >= 2:1.1 +Requires: pkg-config + +%description +CELT is a fully open, non-proprietary, patent- and royalty-free, +low-latency compressed audio format for voice and music. + +The libcelt package contains runtime libraries for use in programs +that support Ogg CELT. + +%package devel +Summary: Files for CELT application development. +Group: Development/Libraries +Requires: libogg-devel >= 2:1.1 +Requires: libcelt = %{epoch}:%{version}-%{release} + +%description devel +The libcelt-devel package contains the header files and documentation +needed to develop applications with Ogg CELT. + +%package utils +Summary: CELT codec utilities. +Group: Applications/Multimedia +Requires: libcelt = %{epoch}:%{version}-%{release} + +%description utils +Basic utilities for encoding, decoding and manipulating Ogg CELT streams. + +%prep + +%setup -q -n celt-%{version} + +%build +%configure --with-ogg-libraries=%{_libdir} +make + +%check +make check + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install + +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la +rm -f $RPM_BUILD_ROOT%{_libdir}/*.a + + +%files +%defattr(-,root,root) +%doc AUTHORS COPYING README +%{_libdir}/libcelt.so.* + +%files devel +%defattr(-,root,root) +%{_includedir}/celt +%{_libdir}/libcelt.so +%{_libdir}/pkgconfig/*.pc + +%files utils +%defattr(-,root,root) +%{_bindir}/celtenc +%{_bindir}/celtdec + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%changelog +* Mon Dec 22 2008 Monty Montgomery 0.5.1-0 +- initial spec file created diff --git a/native/codec/libraries/celt/libcelt/Makefile.am b/native/codec/libraries/celt/libcelt/Makefile.am new file mode 100644 index 0000000..2a2670a --- /dev/null +++ b/native/codec/libraries/celt/libcelt/Makefile.am @@ -0,0 +1,39 @@ +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + + +pkginclude_HEADERS = celt.h celt_types.h celt_header.h +EXTRA_DIST= match-test.sh libcelt.vcxproj libcelt.vcxproj.filters + +#INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_builddir) @OGG_CFLAGS@ + +TESTS = match-test.sh + +noinst_SCRIPTS = match-test.sh + +lib_LTLIBRARIES = libcelt@LIBCELT_SUFFIX@.la + +# Sources for compilation in the library +libcelt@LIBCELT_SUFFIX@_la_SOURCES = bands.c celt.c cwrs.c ecintrin.h entcode.c \ + entdec.c entenc.c header.c kiss_fft.c laplace.c mathops.c mdct.c \ + modes.c pitch.c plc.c quant_bands.c rate.c vq.c + +libcelt@LIBCELT_SUFFIX@_la_LDFLAGS = \ + -version-info @CELT_LT_CURRENT@:@CELT_LT_REVISION@:@CELT_LT_AGE@ \ + -no-undefined + +noinst_HEADERS = _kiss_fft_guts.h arch.h bands.h fixed_c5x.h fixed_c6x.h \ + cwrs.h ecintrin.h entcode.h entdec.h entenc.h fixed_generic.h float_cast.h \ + kiss_fft.h laplace.h mdct.h mfrngcod.h \ + mathops.h modes.h os_support.h pitch.h \ + quant_bands.h rate.h stack_alloc.h \ + static_modes_fixed.c static_modes_float.c vq.h plc.h + +noinst_PROGRAMS = testcelt dump_modes +testcelt_SOURCES = testcelt.c +testcelt_LDADD = libcelt@LIBCELT_SUFFIX@.la +INCLUDES = +#libcelt@LIBCELT_SUFFIX@_la_LIBADD = + +dump_modes_SOURCES = dump_modes.c +dump_modes_LDADD = libcelt@LIBCELT_SUFFIX@.la diff --git a/native/codec/libraries/celt/libcelt/_kiss_fft_guts.h b/native/codec/libraries/celt/libcelt/_kiss_fft_guts.h new file mode 100644 index 0000000..c469d35 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/_kiss_fft_guts.h @@ -0,0 +1,197 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef KISS_FFT_GUTS_H +#define KISS_FFT_GUTS_H + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" + + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" + +#define DOUBLE_PRECISION + +#ifdef DOUBLE_PRECISION + +# define FRACBITS 31 +# define SAMPPROD long long +#define SAMP_MAX 2147483647 +#define TWID_MAX 32767 +#define TRIG_UPSCALE 1 +#define EXT32(a) (a) + +#else /* DOUBLE_PRECISION */ + +# define FRACBITS 15 +# define SAMPPROD celt_int32 +#define SAMP_MAX 32767 +#define TRIG_UPSCALE 1 +#define EXT32(a) EXTEND32(a) + +#endif /* !DOUBLE_PRECISION */ + +#define SAMP_MIN -SAMP_MAX + +#if defined(CHECK_OVERFLOW) +# define CHECK_OVERFLOW_OP(a,op,b) \ + if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ + fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } +#endif + +# define smul(a,b) ( (SAMPPROD)(a)*(b) ) +# define sround( x ) (kiss_fft_scalar)( ( (x) + ((SAMPPROD)1<<(FRACBITS-1)) ) >> FRACBITS ) + + +# define S_MUL(a,b) MULT16_32_Q15(b, a) + +# define C_MUL(m,a,b) \ + do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0) + +# define C_MULC(m,a,b) \ + do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0) + +# define C_MUL4(m,a,b) \ + do{ (m).r = SHR(SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)),2); \ + (m).i = SHR(ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)),2); }while(0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = S_MUL( (c).r , s ) ;\ + (c).i = S_MUL( (c).i , s ) ; }while(0) + +# define DIVSCALAR(x,k) \ + (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +#define C_ADD( res, a,b)\ + do {(res).r=ADD32((a).r,(b).r); (res).i=ADD32((a).i,(b).i); \ + }while(0) +#define C_SUB( res, a,b)\ + do {(res).r=SUB32((a).r,(b).r); (res).i=SUB32((a).i,(b).i); \ + }while(0) +#define C_ADDTO( res , a)\ + do {(res).r = ADD32((res).r, (a).r); (res).i = ADD32((res).i,(a).i);\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {(res).r = ADD32((res).r,(a).r); (res).i = SUB32((res).i,(a).i); \ + }while(0) + + + + +#else /* not FIXED_POINT*/ + +#define EXT32(a) (a) + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +#define C_MULC(m,a,b) \ + do{ (m).r = (a).r*(b).r + (a).i*(b).i;\ + (m).i = (a).i*(b).r - (a).r*(b).i; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + + + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#ifndef C_ADD +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) +#endif /* C_ADD defined */ + +#ifdef FIXED_POINT +/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/ +# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5f)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5f) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\ + (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\ +}while(0) + + +#endif /* KISS_FFT_GUTS_H */ diff --git a/native/codec/libraries/celt/libcelt/arch.h b/native/codec/libraries/celt/libcelt/arch.h new file mode 100644 index 0000000..799aa27 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/arch.h @@ -0,0 +1,253 @@ +/* Copyright (c) 2003-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions for CELT +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#include "celt_types.h" + +#define CELT_SIG_SCALE 32768.f + +#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__); +#ifdef ENABLE_ASSERTIONS +#include +#include +static inline void _celt_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}} +#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}} +#else +#define celt_assert(cond) +#define celt_assert2(cond, message) +#endif + +#define IMUL32(a,b) ((a)*(b)) +#define UMUL32(a,b) ((celt_int32)(a)*(celt_int32)(b)) +#define UMUL16_16(a,b) ((celt_int32)(a)*(celt_int32)(b)) + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ +#define UADD32(a,b) ((a)+(b)) +#define USUB32(a,b) ((a)-(b)) + +#define PRINT_MIPS(file) + +#ifdef FIXED_POINT + +typedef celt_int16 celt_word16; +typedef celt_int32 celt_word32; + +typedef celt_word32 celt_sig; +typedef celt_word16 celt_norm; +typedef celt_word32 celt_ener; +typedef celt_word32 celt_mask; + +#define Q15ONE 32767 +#define Q30ONE 1073741823 + +#define SIG_SHIFT 12 + +#define NORM_SCALING 16384 +#define NORM_SCALING_1 (1.f/16384.f) +#define NORM_SHIFT 14 + +#define ENER_SCALING 16384.f +#define ENER_SCALING_1 (1.f/16384.f) +#define ENER_SHIFT 14 + +#define PGAIN_SCALING 32768.f +#define PGAIN_SCALING_1 (1.f/32768.f) +#define PGAIN_SHIFT 15 + +#define DB_SHIFT 10 + +#define EPSILON 1 +#define VERY_SMALL 0 +#define VERY_LARGE32 ((celt_word32)2147483647) +#define VERY_LARGE16 ((celt_word16)32767) +#define Q15_ONE ((celt_word16)32767) +#define Q15_ONE_1 (1.f/32768.f) + +#define SCALEIN(a) (a) +#define SCALEOUT(a) (a) + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef ARM5E_ASM +#include "fixed_arm5e.h" +#elif defined (ARM4_ASM) +#include "fixed_arm4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#elif defined (TI_C5X_ASM) +#include "fixed_c5x.h" +#elif defined (TI_C6X_ASM) +#include "fixed_c6x.h" +#endif + +#endif + + +#else /* FIXED_POINT */ + +typedef float celt_word16; +typedef float celt_word32; + +typedef float celt_sig; +typedef float celt_norm; +typedef float celt_ener; +typedef float celt_pgain; +typedef float celt_mask; + +#define Q15ONE 1.0f +#define Q30ONE 1.0f + +#define NORM_SCALING 1.f +#define NORM_SCALING_1 1.f +#define ENER_SCALING 1.f +#define ENER_SCALING_1 1.f +#define PGAIN_SCALING 1.f +#define PGAIN_SCALING_1 1.f + +#define EPSILON 1e-15f +#define VERY_SMALL 1e-15f +#define VERY_LARGE32 1e15f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((celt_word16)1.f) +#define Q15_ONE_1 ((celt_word16)1.f) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR16(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) +#define SATURATE16(x,a) (x) +#define SATURATE32(x,a) (x) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ROUND16(a,shift) (a) +#define HALF32(x) (.5f*(x)) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((celt_word32)(a)*(celt_word32)(b)) +#define MAC16_16(c,a,b) ((c)+(celt_word32)(a)*(celt_word32)(b)) + +#define MULT16_32_Q11(a,b) ((a)*(b)) +#define MULT16_32_Q13(a,b) ((a)*(b)) +#define MULT16_32_Q14(a,b) ((a)*(b)) +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_Q16(a,b) ((a)*(b)) +#define MULT16_32_P15(a,b) ((a)*(b)) + +#define MULT32_32_Q31(a,b) ((a)*(b)) + +#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((celt_word32)(a))/(celt_word16)(b)) +#define PDIV32_16(a,b) (((celt_word32)(a))/(celt_word16)(b)) +#define DIV32(a,b) (((celt_word32)(a))/(celt_word32)(b)) +#define PDIV32(a,b) (((celt_word32)(a))/(celt_word32)(b)) + +#define SCALEIN(a) ((a)*CELT_SIG_SCALE) +#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) + +#endif /* !FIXED_POINT */ + + +#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + +/* 2 on TI C5x DSP */ +#define BYTES_PER_CHAR 2 +#define BITS_PER_CHAR 16 +#define LOG2_BITS_PER_CHAR 4 + +#else /* CONFIG_TI_C54X */ + +#define BYTES_PER_CHAR 1 +#define BITS_PER_CHAR 8 +#define LOG2_BITS_PER_CHAR 3 + +#endif /* !CONFIG_TI_C54X */ + +#ifndef GLOBAL_STACK_SIZE +#ifdef FIXED_POINT +#define GLOBAL_STACK_SIZE 100000 +#else +#define GLOBAL_STACK_SIZE 100000 +#endif +#endif + +#endif /* ARCH_H */ diff --git a/native/codec/libraries/celt/libcelt/bands.c b/native/codec/libraries/celt/libcelt/bands.c new file mode 100644 index 0000000..d51feee --- /dev/null +++ b/native/codec/libraries/celt/libcelt/bands.c @@ -0,0 +1,1286 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2009 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "bands.h" +#include "modes.h" +#include "vq.h" +#include "cwrs.h" +#include "stack_alloc.h" +#include "os_support.h" +#include "mathops.h" +#include "rate.h" + +celt_uint32 lcg_rand(celt_uint32 seed) +{ + return 1664525 * seed + 1013904223; +} + +/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness + with this approximation is important because it has an impact on the bit allocation */ +static celt_int16 bitexact_cos(celt_int16 x) +{ + celt_int32 tmp; + celt_int16 x2; + tmp = (4096+((celt_int32)(x)*(x)))>>13; + if (tmp > 32767) + tmp = 32767; + x2 = tmp; + x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2))))); + if (x2 > 32766) + x2 = 32766; + return 1+x2; +} + +static int bitexact_log2tan(int isin,int icos) +{ + int lc; + int ls; + lc=EC_ILOG(icos); + ls=EC_ILOG(isin); + icos<<=15-lc; + isin<<=15-ls; + return (ls-lc<<11) + +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932) + -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932); +} + +#ifdef FIXED_POINT +/* Compute the amplitude (sqrt energy) in each of the bands */ +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bank, int end, int _C, int M) +{ + int i, c, N; + const celt_int16 *eBands = m->eBands; + const int C = CHANNELS(_C); + N = M*m->shortMdctSize; + c=0; do { + for (i=0;i 0) + { + int shift = celt_ilog2(maxval)-10; + j=M*eBands[i]; do { + sum = MAC16_16(sum, EXTRACT16(VSHR32(X[j+c*N],shift)), + EXTRACT16(VSHR32(X[j+c*N],shift))); + } while (++jnbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift); + } else { + bank[i+c*m->nbEBands] = EPSILON; + } + /*printf ("%f ", bank[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + const int C = CHANNELS(_C); + N = M*m->shortMdctSize; + c=0; do { + i=0; do { + celt_word16 g; + int j,shift; + celt_word16 E; + shift = celt_zlog2(bank[i+c*m->nbEBands])-13; + E = VSHR32(bank[i+c*m->nbEBands], shift); + g = EXTRACT16(celt_rcp(SHL32(E,3))); + j=M*eBands[i]; do { + X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g); + } while (++jeBands; + const int C = CHANNELS(_C); + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands] = celt_sqrt(sum); + /*printf ("%f ", bank[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + const int C = CHANNELS(_C); + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands]); + for (j=M*eBands[i];jeBands; + const int C = CHANNELS(_C); + N = M*m->shortMdctSize; + celt_assert2(C<=2, "denormalise_bands() not implemented for >2 channels"); + c=0; do { + celt_sig * restrict f; + const celt_norm * restrict x; + f = freq+c*N; + x = X+c*N; + for (i=0;inbEBands],1); + j=M*eBands[i]; + band_end = M*eBands[i+1]; + do { + *f++ = SHL32(MULT16_32_Q15(*x, g),2); + x++; + } while (++jeBands[i+1]-m->eBands[i]; + /* depth in 1/8 bits */ + depth = (1+pulses[i])/(m->eBands[i+1]-m->eBands[i]<>1; + t = SHL32(t, (7-shift)<<1); + sqrt_1 = celt_rsqrt_norm(t); + } +#else + thresh = .5f*celt_exp2(-.125f*depth); + sqrt_1 = celt_rsqrt(N0<nbEBands+i]; + prev2 = prev2logE[c*m->nbEBands+i]; + if (CnbEBands+i]); + prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]); + } + Ediff = logE[c*m->nbEBands+i]-MIN16(prev1,prev2); + Ediff = MAX16(0, Ediff); + +#ifdef FIXED_POINT + if (Ediff < 16384) + r = 2*MIN16(16383,SHR32(celt_exp2(-Ediff),1)); + else + r = 0; + if (LM==3) + r = MULT16_16_Q14(23170, MIN32(23169, r)); + r = SHR16(MIN16(thresh, r),1); + r = SHR32(MULT16_16_Q15(sqrt_1, r),shift); +#else + /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because + short blocks don't have the same energy as long */ + r = 2.f*celt_exp2(-Ediff); + if (LM==3) + r *= 1.41421356f; + r = MIN16(thresh, r); + r = r*sqrt_1; +#endif + X = _X+c*size+(m->eBands[i]<nbEBands]))-13; +#endif + left = VSHR32(bank[i],shift); + right = VSHR32(bank[i+m->nbEBands],shift); + norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); + a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); + a2 = DIV32_16(SHL32(EXTEND32(right),14),norm); + for (j=0;j>1; + kr = celt_ilog2(Er)>>1; +#endif + t = VSHR32(El, (kl-7)<<1); + lgain = celt_rsqrt_norm(t); + t = VSHR32(Er, (kr-7)<<1); + rgain = celt_rsqrt_norm(t); + +#ifdef FIXED_POINT + if (kl < 7) + kl = 7; + if (kr < 7) + kr = 7; +#endif + + for (j=0;jeBands; + int decision; + int hf_sum=0; + + N0 = M*m->shortMdctSize; + + if (M*(eBands[end]-eBands[end-1]) <= 8) + return SPREAD_NONE; + c=0; do { + for (i=0;im->nbEBands-4) + hf_sum += 32*(tcount[1]+tcount[0])/N; + tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N); + sum += tmp*256; + nbBands++; + } + } while (++cnbEBands+end); + *hf_average = (*hf_average+hf_sum)>>1; + hf_sum = *hf_average; + if (*tapset_decision==2) + hf_sum += 4; + else if (*tapset_decision==0) + hf_sum -= 4; + if (hf_sum > 22) + *tapset_decision=2; + else if (hf_sum > 18) + *tapset_decision=1; + else + *tapset_decision=0; + } + /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/ + sum /= nbBands; + /* Recursive averaging */ + sum = (sum+*average)>>1; + *average = sum; + /* Hysteresis */ + sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2; + if (sum < 80) + { + decision = SPREAD_AGGRESSIVE; + } else if (sum < 256) + { + decision = SPREAD_NORMAL; + } else if (sum < 384) + { + decision = SPREAD_LIGHT; + } else { + decision = SPREAD_NONE; + } + return decision; +} + +#ifdef MEASURE_NORM_MSE + +float MSE[30] = {0}; +int nbMSEBands = 0; +int MSECount[30] = {0}; + +void dump_norm_mse(void) +{ + int i; + for (i=0;inbEBands;i++) + { + int j; + int c; + float g; + if (bandE0[i]<10 || (C==2 && bandE0[i+m->nbEBands]<1)) + continue; + c=0; do { + g = bandE[i+c*m->nbEBands]/(1e-15+bandE0[i+c*m->nbEBands]); + for (j=M*m->eBands[i];jeBands[i+1];j++) + MSE[i] += (g*X[j+c*N]-X0[j+c*N])*(g*X[j+c*N]-X0[j+c*N]); + } while (++cnbEBands; +} + +#endif + +/* Indexing table for converting from natural Hadamard to ordery Hadamard + This is essentially a bit-reversed Gray, on top of which we've added + an inversion of the order because we want the DC at the end rather than + the beginning. The lines are for N=2, 4, 8, 16 */ +static const int ordery_table[] = { + 1, 0, + 3, 0, 2, 1, + 7, 0, 4, 3, 6, 1, 5, 2, + 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5, +}; + +static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard) +{ + int i,j; + VARDECL(celt_norm, tmp); + int N; + SAVE_STACK; + N = N0*stride; + ALLOC(tmp, N, celt_norm); + if (hadamard) + { + const int *ordery = ordery_table+stride-2; + for (i=0;i>= 1; + for (i=0;i>1)) { + qn = 1; + } else { + qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES)); + qn = (qn+1)>>1<<1; + } + celt_assert(qn <= 256); + return qn; +} + +/* This function is responsible for encoding and decoding a band for both + the mono and stereo case. Even in the mono case, it can split the band + in two and transmit the energy difference with the two half-bands. It + can be called recursively so bands can end up being split in 8 parts. */ +static unsigned quant_band(int encode, const CELTMode *m, int i, celt_norm *X, celt_norm *Y, + int N, int b, int spread, int B, int intensity, int tf_change, celt_norm *lowband, int resynth, ec_ctx *ec, + celt_int32 *remaining_bits, int LM, celt_norm *lowband_out, const celt_ener *bandE, int level, + celt_uint32 *seed, celt_word16 gain, celt_norm *lowband_scratch, int fill) +{ + const unsigned char *cache; + int q; + int curr_bits; + int stereo, split; + int imid=0, iside=0; + int N0=N; + int N_B=N; + int N_B0; + int B0=B; + int time_divide=0; + int recombine=0; + int inv = 0; + celt_word16 mid=0, side=0; + int longBlocks; + unsigned cm=0; + + longBlocks = B0==1; + + N_B /= B; + N_B0 = N_B; + + split = stereo = Y != NULL; + + /* Special case for one sample */ + if (N==1) + { + int c; + celt_norm *x = X; + c=0; do { + int sign=0; + if (*remaining_bits>=1<0) + recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1)) + { + int j; + for (j=0;j>k, 1<>k, 1<>4]<<2; + } + B>>=recombine; + N_B<<=recombine; + + /* Increasing the time resolution */ + while ((N_B&1) == 0 && tf_change<0) + { + if (encode) + haar1(X, N_B, B); + if (lowband) + haar1(lowband, N_B, B); + fill |= fill<>= 1; + time_divide++; + tf_change++; + } + B0=B; + N_B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (B0>1) + { + if (encode) + deinterleave_hadamard(X, N_B>>recombine, B0<>recombine, B0<cache.bits + m->cache.index[(LM+1)*m->nbEBands+i]; + if (!stereo && LM != -1 && b > cache[cache[0]]+12 && N>2) + { + if (LM>0 || (N&1)==0) + { + N >>= 1; + Y = X+N; + split = 1; + LM -= 1; + if (B==1) + fill = fill&1|fill<<1; + B = (B+1)>>1; + } + } + + if (split) + { + int qn; + int itheta=0; + int mbits, sbits, delta; + int qalloc; + int pulse_cap; + int offset; + int orig_fill; + celt_int32 tell; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = m->logN[i]+(LM<>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET); + qn = compute_qn(N, b, offset, pulse_cap, stereo); + if (stereo && i>=intensity) + qn = 1; + if (encode) + { + /* theta is the atan() of the ratio between the (normalized) + side and mid. With just that parameter, we can re-scale both + mid and side because we know that 1) they have unit norm and + 2) they are orthogonal. */ + itheta = stereo_itheta(X, Y, stereo, N); + } + tell = ec_tell_frac(ec); + if (qn!=1) + { + if (encode) + itheta = (itheta*qn+8192)>>14; + + /* Entropy coding of the angle. We use a uniform pdf for the + time split, a step for stereo, and a triangular one for the rest. */ + if (stereo && N>2) + { + int p0 = 3; + int x = itheta; + int x0 = qn/2; + int ft = p0*(x0+1) + x0; + /* Use a probability of p0 up to itheta=8192 and then use 1 after */ + if (encode) + { + ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + } else { + int fs; + fs=ec_decode(ec,ft); + if (fs<(x0+1)*p0) + x=fs/p0; + else + x=x0+1+(fs-(x0+1)*p0); + ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + itheta = x; + } + } else if (B0>1 || stereo) { + /* Uniform pdf */ + if (encode) + ec_enc_uint(ec, itheta, qn+1); + else + itheta = ec_dec_uint(ec, qn+1); + } else { + int fs=1, ft; + ft = ((qn>>1)+1)*((qn>>1)+1); + if (encode) + { + int fl; + + fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta; + fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 : + ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + + ec_encode(ec, fl, fl+fs, ft); + } else { + /* Triangular pdf */ + int fl=0; + int fm; + fm = ec_decode(ec, ft); + + if (fm < ((qn>>1)*((qn>>1) + 1)>>1)) + { + itheta = (isqrt32(8*(celt_uint32)fm + 1) - 1)>>1; + fs = itheta + 1; + fl = itheta*(itheta + 1)>>1; + } + else + { + itheta = (2*(qn + 1) + - isqrt32(8*(celt_uint32)(ft - fm - 1) + 1))>>1; + fs = qn + 1 - itheta; + fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + } + + ec_dec_update(ec, fl, fl+fs, ft); + } + } + itheta = (celt_int32)itheta*16384/qn; + if (encode && stereo) + { + if (itheta==0) + intensity_stereo(m, X, Y, bandE, i, N); + else + stereo_split(X, Y, N); + } + /* TODO: Renormalising X and Y *may* help fixed-point a bit at very high rate. + Let's do that at higher complexity */ + } else if (stereo) { + if (encode) + { + inv = itheta > 8192; + if (inv) + { + int j; + for (j=0;j2< 2< 8192; + *remaining_bits -= qalloc+sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) + { + if (encode) + { + /* Here we only need to encode a sign for the side */ + sign = x2[0]*y2[1] - x2[1]*y2[0] < 0; + ec_enc_bits(ec, sign, 1); + } else { + sign = ec_dec_bits(ec, 1); + } + } + sign = 1-2*sign; + /* We use orig_fill here because we want to fold the side, but if + itheta==16384, we'll have cleared the low bits of fill. */ + cm = quant_band(encode, m, i, x2, NULL, N, mbits, spread, B, intensity, tf_change, lowband, resynth, ec, remaining_bits, LM, lowband_out, NULL, level, seed, gain, lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), + and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign*x2[1]; + y2[1] = sign*x2[0]; + if (resynth) + { + celt_norm tmp; + X[0] = MULT16_16_Q15(mid, X[0]); + X[1] = MULT16_16_Q15(mid, X[1]); + Y[0] = MULT16_16_Q15(side, Y[0]); + Y[1] = MULT16_16_Q15(side, Y[1]); + tmp = X[0]; + X[0] = SUB16(tmp,Y[0]); + Y[0] = ADD16(tmp,Y[0]); + tmp = X[1]; + X[1] = SUB16(tmp,Y[1]); + Y[1] = ADD16(tmp,Y[1]); + } + } else { + /* "Normal" split code */ + celt_norm *next_lowband2=NULL; + celt_norm *next_lowband_out1=NULL; + int next_level=0; + celt_int32 rebalance; + + /* Give more bits to low-energy MDCTs than they would otherwise deserve */ + if (B0>1 && !stereo && (itheta&0x3fff)) + { + if (itheta > 8192) + /* Rough approximation for pre-echo masking */ + delta -= delta>>(4-LM); + else + /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */ + delta = IMIN(0, delta + (N<>(5-LM))); + } + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + *remaining_bits -= qalloc; + + if (lowband && !stereo) + next_lowband2 = lowband+N; /* >32-bit split case */ + + /* Only stereo needs to pass on lowband_out. Otherwise, it's + handled at the end */ + if (stereo) + next_lowband_out1 = lowband_out; + else + next_level = level+1; + + rebalance = *remaining_bits; + if (mbits >= sbits) + { + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized + mid for folding later */ + cm = quant_band(encode, m, i, X, NULL, N, mbits, spread, B, intensity, tf_change, + lowband, resynth, ec, remaining_bits, LM, next_lowband_out1, + NULL, next_level, seed, stereo ? Q15ONE : MULT16_16_P15(gain,mid), lowband_scratch, fill); + rebalance = mbits - (rebalance-*remaining_bits); + if (rebalance > 3<>B)<<(B0>>1&stereo-1); + } else { + /* For a stereo split, the high bits of fill are always zero, so no + folding will be done to the side. */ + cm = quant_band(encode, m, i, Y, NULL, N, sbits, spread, B, intensity, tf_change, + next_lowband2, resynth, ec, remaining_bits, LM, NULL, + NULL, next_level, seed, MULT16_16_P15(gain,side), NULL, fill>>B)<<(B0>>1&stereo-1); + rebalance = sbits - (rebalance-*remaining_bits); + if (rebalance > 3< 0) + { + *remaining_bits += curr_bits; + q--; + curr_bits = pulses2bits(m, i, LM, q); + *remaining_bits -= curr_bits; + } + + if (q!=0) + { + int K = get_pulses(q); + + /* Finally do the actual quantization */ + if (encode) + cm = alg_quant(X, N, K, spread, B, resynth, ec, gain); + else + cm = alg_unquant(X, N, K, spread, B, ec, gain); + } else { + /* If there's no pulse, fill the band anyway */ + int j; + if (resynth) + { + unsigned cm_mask; + /*B can be as large as 16, so this shift might overflow an int on a + 16-bit platform; use a long to get defined behavior.*/ + cm_mask = (unsigned)(1UL<>20; + } + cm = cm_mask; + } else { + /* Folded spectrum */ + for (j=0;j1) + interleave_hadamard(X, N_B>>recombine, B0<>= 1; + N_B <<= 1; + cm |= cm>>B; + haar1(X, N_B, B); + } + + for (k=0;k>k, 1<eBands; + celt_norm * restrict norm, * restrict norm2; + VARDECL(celt_norm, _norm); + VARDECL(celt_norm, lowband_scratch); + int B; + int M; + int lowband_offset; + int update_lowband = 1; + int C = _Y != NULL ? 2 : 1; + SAVE_STACK; + + M = 1<nbEBands], celt_norm); + ALLOC(lowband_scratch, M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]), celt_norm); + norm = _norm; + norm2 = norm + M*eBands[m->nbEBands]; + + lowband_offset = 0; + for (i=start;i= M*eBands[start] && (update_lowband || lowband_offset==0)) + lowband_offset = i; + + tf_change = tf_res[i]; + if (i>=m->effEBands) + { + X=norm; + if (_Y!=NULL) + Y = norm; + } + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0)) + { + int fold_start; + int fold_end; + int fold_i; + /* This ensures we never repeat spectral content within one band */ + effective_lowband = IMAX(M*eBands[start], M*eBands[lowband_offset]-N); + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; + while(M*eBands[++fold_end] < effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + y_cm |= collapse_masks[fold_i*C+C-1]; + } while (++fold_i(N<= 32767.0) return 32767; + if (d <= -32768.0) return -32768; + return (short)d; +} + + +/* ======================================================================== */ +/* D2S -- Truncate a 'double' to a 'int', with clamping. */ +/* ======================================================================== */ +static int d2i(double d) +{ + if (d >= 2147483647.0) return (int)0x7FFFFFFF; + if (d <= -2147483648.0) return (int)0x80000000; + return (int)d; +} + + +/* ======================================================================== */ +/* GEN_TWIDDLE -- Generate twiddle factors for TI's custom FFTs. */ +/* */ +/* USAGE */ +/* This routine is called as follows: */ +/* */ +/* int gen_twiddle(short *w, int n, double scale) */ +/* */ +/* short *w Pointer to twiddle-factor array */ +/* int n Size of FFT */ +/* double scale Scale factor to apply to values. */ +/* */ +/* The routine will generate the twiddle-factors directly into the */ +/* array you specify. The array needs to be approximately 2*N */ +/* elements long. (The actual size, which is slightly smaller, is */ +/* returned by the function.) */ +/* ======================================================================== */ +int gen_twiddle16(short *w, int n, double scale) +{ + int i, j, k; + + for (j = 1, k = 0; j < n >> 2; j = j << 2) + { + for (i = 0; i < n >> 2; i += j << 1) + { + w[k + 11] = d2s(scale * cos(6.0 * PI * (i + j) / n)); + w[k + 10] = d2s(scale * sin(6.0 * PI * (i + j) / n)); + w[k + 9] = d2s(scale * cos(6.0 * PI * (i ) / n)); + w[k + 8] = d2s(scale * sin(6.0 * PI * (i ) / n)); + + w[k + 7] = d2s(scale * cos(4.0 * PI * (i + j) / n)); + w[k + 6] = d2s(scale * sin(4.0 * PI * (i + j) / n)); + w[k + 5] = d2s(scale * cos(4.0 * PI * (i ) / n)); + w[k + 4] = d2s(scale * sin(4.0 * PI * (i ) / n)); + + w[k + 3] = d2s(scale * cos(2.0 * PI * (i + j) / n)); + w[k + 2] = d2s(scale * sin(2.0 * PI * (i + j) / n)); + w[k + 1] = d2s(scale * cos(2.0 * PI * (i ) / n)); + w[k + 0] = d2s(scale * sin(2.0 * PI * (i ) / n)); + + k += 12; + } + } + + return k; +} + + +/* ======================================================================== */ +/* GEN_TWIDDLE -- Generate twiddle factors for TI's custom FFTs. */ +/* */ +/* USAGE */ +/* This routine is called as follows: */ +/* */ +/* int gen_twiddle(int *w, int n, double scale) */ +/* */ +/* int *w Pointer to twiddle-factor array */ +/* int n Size of FFT */ +/* double scale Scale factor to apply to values. */ +/* */ +/* The routine will generate the twiddle-factors directly into the */ +/* array you specify. The array needs to be approximately 2*N */ +/* elements long. (The actual size, which is slightly smaller, is */ +/* returned by the function.) */ +/* ======================================================================== */ +int gen_twiddle32(int *w, int n, double scale) +{ + int i, j, k, s=0, t; + + for (j = 1, k = 0; j < n >> 2; j = j << 2, s++) + { + for (i = t=0; i < n >> 2; i += j, t++) + { + w[k + 5] = d2i(scale * cos(6.0 * PI * i / n)); + w[k + 4] = d2i(scale * sin(6.0 * PI * i / n)); + + w[k + 3] = d2i(scale * cos(4.0 * PI * i / n)); + w[k + 2] = d2i(scale * sin(4.0 * PI * i / n)); + + w[k + 1] = d2i(scale * cos(2.0 * PI * i / n)); + w[k + 0] = d2i(scale * sin(2.0 * PI * i / n)); + + k += 6; + } + } + + return k; +} + +#define NBCACHE 3 +static c64_fft_t *cache16[NBCACHE] = {NULL,}; +static c64_fft_t *cache32[NBCACHE] = {NULL,}; + +c64_fft_t *c64_fft16_alloc(int length, int x, int y) +{ + c64_fft_t *state; + celt_int16 *w, *iw; + + int i, c; + + for (c = 0; c < NBCACHE; c++) { + if (cache16[c] == NULL) + break; + if (cache16[c]->nfft == length) + return cache16[c]; + } + + state = (c64_fft_t *)celt_alloc(sizeof(c64_fft_t)); + state->shift = log(length)/log(2) - ceil(log(length)/log(4)-1); + state->nfft = length; + state->twiddle = celt_alloc(length*2*sizeof(celt_int16)); + state->itwiddle = celt_alloc(length*2*sizeof(celt_int16)); + + gen_twiddle16((celt_int16 *)state->twiddle, length, 32767.0); + + w = (celt_int16 *)state->twiddle; + iw = (celt_int16 *)state->itwiddle; + + for (i = 0; i < length; i++) { + iw[2*i+0] = w[2*i+0]; + iw[2*i+1] = - w[2*i+1]; + } + + if (c < NBCACHE) + cache16[c++] = state; + if (c < NBCACHE) + cache16[c] = NULL; + + return state; +} + + +c64_fft_t *c64_fft32_alloc(int length, int x, int y) +{ + c64_fft_t *state; + int i, c; + + for (c = 0; c < NBCACHE; c++) { + if (cache32[c] == NULL) + break; + if (cache32[c]->nfft == length) + return cache32[c]; + } + + state = (c64_fft_t *)celt_alloc(sizeof(c64_fft_t)); + state->shift = log(length)/log(2) - ceil(log(length)/log(4)-1); + state->nfft = length; + state->twiddle = celt_alloc(length*2*sizeof(celt_int32)); + state->itwiddle = celt_alloc(length*2*sizeof(celt_int32)); + + // Generate the inverse twiddle first because it does not need scaling + gen_twiddle32(state->itwiddle, length, 2147483647.000000000); + + for (i = 0; i < length; i++) { + state->twiddle[2*i+0] = state->itwiddle[2*i+0] >> 1; + state->twiddle[2*i+1] = state->itwiddle[2*i+1] >> 1; + } + + if (c < NBCACHE) + cache32[c++] = state; + if (c < NBCACHE) + cache32[c] = NULL; + + return state; +} + + +void c64_fft16_free(c64_fft_t *state) +{ + c64_fft32_free(state); +} + + +void c64_fft32_free(c64_fft_t *state) +{ +} + + +void c64_fft16_inplace(c64_fft_t * restrict state, celt_int16 *X) +{ + int i; + VARDECL(celt_int16, cin); + VARDECL(celt_int16, cout); + SAVE_STACK; + + ALLOC(cin, state->nfft*2, celt_int16); + ALLOC(cout, state->nfft*2, celt_int16); + + for (i = 0; i < state->nfft; i++) { + cin[2*i+0] = X[2*i+0]; + cin[2*i+1] = X[2*i+1]; + } + + DSP_fft16x16t((celt_int16 *)state->twiddle, state->nfft, cin, cout); + + for (i = 0; i < state->nfft; i++) { + X[2*i+0] = cout[2*i+0]; + X[2*i+1] = cout[2*i+1]; + } + + RESTORE_STACK; +} + + + +void c64_fft32(c64_fft_t * restrict state, const celt_int32 *X, celt_int32 *Y) +{ + int i; + VARDECL(celt_int32, cin); + SAVE_STACK; + ALLOC(cin, state->nfft*2, celt_int32); + + for (i = 0; i < state->nfft; i++) { + cin[2*i+0] = X[2*i+0] >> state->shift; + cin[2*i+1] = X[2*i+1] >> state->shift; + } + + DSP_fft32x32s(state->twiddle, state->nfft, cin, Y); + + RESTORE_STACK; +} + + +void c64_ifft16(c64_fft_t * restrict state, const celt_int16 *X, celt_int16 *Y) +{ + int i; + VARDECL(celt_int16, cin); + VARDECL(celt_int16, cout); + SAVE_STACK; + + ALLOC(cin, state->nfft*2, celt_int16); + if ((celt_int32)Y & 7) + ALLOC(cout, state->nfft*2, celt_int16); + else + cout = Y; + + for (i = 0; i < state->nfft; i++) { + // No need to scale for this one but still need to save the input + // because the fft is going to change it! + cin[2*i+0] = X[2*i+0]; + cin[2*i+1] = X[2*i+1]; + } + + DSP_fft16x16t((celt_int16 *)state->itwiddle, state->nfft, cin, cout); + + if ((celt_int32)Y & 7) + for (i = 0; i < state->nfft; i++) { + Y[2*i+0] = cout[2*i+0]; + Y[2*i+1] = cout[2*i+1]; + } + + RESTORE_STACK; +} + + +void c64_ifft32(c64_fft_t * restrict state, const celt_int32 *X, celt_int32 *Y) +{ + int i; + VARDECL(celt_int32, cin); + SAVE_STACK; + ALLOC(cin, state->nfft*2, celt_int32); + + celt_assert(Y & 7 == 0); + + for (i = 0; i < state->nfft; i++) { + // No need to scale for this one but still need to save the input + // because the fft is going to change it! + cin[2*i+0] = X[2*i+0]; + cin[2*i+1] = X[2*i+1]; + } + + DSP_ifft32x32(state->itwiddle, state->nfft, cin, Y); + + RESTORE_STACK; +} + + diff --git a/native/codec/libraries/celt/libcelt/c64_fft.h b/native/codec/libraries/celt/libcelt/c64_fft.h new file mode 100644 index 0000000..3a224e0 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/c64_fft.h @@ -0,0 +1,54 @@ +/* (c) Copyright 2008/2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _dsp_fft_h_ +#define _dsp_fft_h_ + +#include "config.h" + +#include "arch.h" +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +typedef struct { + int nfft; + int shift; + celt_int32 *twiddle; + celt_int32 *itwiddle; +} c64_fft_t; + +extern c64_fft_t *c64_fft16_alloc(int length, int x, int y); +extern void c64_fft16_free(c64_fft_t *state); +extern void c64_fft16_inplace(c64_fft_t *state, celt_int16 *X); +extern void c64_ifft16(c64_fft_t *state, const celt_int16 *X, celt_int16 *Y); + +extern c64_fft_t *c64_fft32_alloc(int length, int x, int y); +extern void c64_fft32_free(c64_fft_t *state); +extern void c64_fft32(c64_fft_t *state, const celt_int32 *X, celt_int32 *Y); +extern void c64_ifft32(c64_fft_t *state, const celt_int32 *X, celt_int32 *Y); + +#endif diff --git a/native/codec/libraries/celt/libcelt/celt.c b/native/codec/libraries/celt/libcelt/celt.c new file mode 100644 index 0000000..671ac58 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/celt.c @@ -0,0 +1,2816 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_C + +/* Always enable postfilter for Opus */ +#if defined(OPUS_BUILD) && !defined(ENABLE_POSTFILTER) +#define ENABLE_POSTFILTER +#endif + +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "plc.h" +#include "vq.h" + +static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; +/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ +static const unsigned char spread_icdf[4] = {25, 23, 2, 0}; + +static const unsigned char tapset_icdf[3]={2,1,0}; + +static const unsigned char toOpusTable[20] = { + 0xE0, 0xE8, 0xF0, 0xF8, + 0xC0, 0xC8, 0xD0, 0xD8, + 0xA0, 0xA8, 0xB0, 0xB8, + 0x00, 0x00, 0x00, 0x00, + 0x80, 0x88, 0x90, 0x98, +}; + +static const unsigned char fromOpusTable[16] = { + 0x80, 0x88, 0x90, 0x98, + 0x40, 0x48, 0x50, 0x58, + 0x20, 0x28, 0x30, 0x38, + 0x00, 0x08, 0x10, 0x18 +}; + +static inline int toOpus(unsigned char c) +{ + int ret=0; + if (c<0xA0) + ret = toOpusTable[c>>3]; + if (ret == 0) + return -1; + else + return ret|(c&0x7); +} + +static inline int fromOpus(unsigned char c) +{ + if (c<0x80) + return -1; + else + return fromOpusTable[(c>>3)-16] | (c&0x7); +} + +#define COMBFILTER_MAXPERIOD 1024 +#define COMBFILTER_MINPERIOD 15 + +static int resampling_factor(celt_int32 rate) +{ + int ret; + switch (rate) + { + case 48000: + ret = 1; + break; + case 24000: + ret = 2; + break; + case 16000: + ret = 3; + break; + case 12000: + ret = 4; + break; + case 8000: + ret = 6; + break; + default: + ret = 0; + } + return ret; +} + +/** Encoder state + @brief Encoder state + */ +struct CELTEncoder { + const CELTMode *mode; /**< Mode used by the encoder */ + int overlap; + int channels; + int stream_channels; + + int force_intra; + int clip; + int disable_pf; + int complexity; + int upsample; + int start, end; + + celt_int32 bitrate; + int vbr; + int signalling; + int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ + int loss_rate; + + /* Everything beyond this point gets cleared on a reset */ +#define ENCODER_RESET_START rng + + celt_uint32 rng; + int spread_decision; + celt_word32 delayedIntra; + int tonal_average; + int lastCodedBands; + int hf_average; + int tapset_decision; + + int prefilter_period; + celt_word16 prefilter_gain; + int prefilter_tapset; +#ifdef RESYNTH + int prefilter_period_old; + celt_word16 prefilter_gain_old; + int prefilter_tapset_old; +#endif + int consec_transient; + + /* VBR-related parameters */ + celt_int32 vbr_reservoir; + celt_int32 vbr_drift; + celt_int32 vbr_offset; + celt_int32 vbr_count; + + celt_word32 preemph_memE[2]; + celt_word32 preemph_memD[2]; + +#ifdef RESYNTH + celt_sig syn_mem[2][2*MAX_PERIOD]; +#endif + + celt_sig in_mem[1]; /* Size = channels*mode->overlap */ + /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_PERIOD */ + /* celt_sig overlap_mem[], Size = channels*mode->overlap */ + /* celt_word16 oldEBands[], Size = 2*channels*mode->nbEBands */ +}; + +int celt_encoder_get_size(int channels) +{ + CELTMode *mode = celt_mode_create(48000, 960, NULL); + return celt_encoder_get_size_custom(mode, channels); +} + +int celt_encoder_get_size_custom(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTEncoder) + + (2*channels*mode->overlap-1)*sizeof(celt_sig) + + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) + + 3*channels*mode->nbEBands*sizeof(celt_word16); + return size; +} + +CELTEncoder *celt_encoder_create(int sampling_rate, int channels, int *error) +{ + CELTEncoder *st; + st = (CELTEncoder *)celt_alloc(celt_encoder_get_size(channels)); + if (st!=NULL && celt_encoder_init(st, sampling_rate, channels, error)==NULL) + { + celt_encoder_destroy(st); + st = NULL; + } + return st; +} + +CELTEncoder *celt_encoder_create_custom(const CELTMode *mode, int channels, int *error) +{ + CELTEncoder *st = (CELTEncoder *)celt_alloc(celt_encoder_get_size_custom(mode, channels)); + if (st!=NULL && celt_encoder_init_custom(st, mode, channels, error)==NULL) + { + celt_encoder_destroy(st); + st = NULL; + } + return st; +} + +CELTEncoder *celt_encoder_init(CELTEncoder *st, int sampling_rate, int channels, int *error) +{ + celt_encoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, error); + st->upsample = resampling_factor(sampling_rate); + if (st->upsample==0) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + return st; +} + +CELTEncoder *celt_encoder_init_custom(CELTEncoder *st, const CELTMode *mode, int channels, int *error) +{ + if (channels < 0 || channels > 2) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + + if (st==NULL || mode==NULL) + { + if (error) + *error = CELT_ALLOC_FAIL; + return NULL; + } + + CELT_MEMSET((char*)st, 0, celt_encoder_get_size_custom(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->upsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + + st->constrained_vbr = 1; + st->clip = 1; + + st->bitrate = 255000*channels; + st->vbr = 0; + st->vbr_offset = 0; + st->force_intra = 0; + st->delayedIntra = 1; + st->tonal_average = 256; + st->spread_decision = SPREAD_NORMAL; + st->hf_average = 0; + st->tapset_decision = 0; + st->complexity = 5; + + if (error) + *error = CELT_OK; + return st; +} + +void celt_encoder_destroy(CELTEncoder *st) +{ + celt_free(st); +} + +static inline celt_int16 FLOAT2INT16(float x) +{ + x = x*CELT_SIG_SCALE; + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return (celt_int16)float2int(x); +} + +static inline celt_word16 SIG2WORD16(celt_sig x) +{ +#ifdef FIXED_POINT + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +#else + return (celt_word16)x; +#endif +} + +static int transient_analysis(const celt_word32 * restrict in, int len, int C, + int overlap) +{ + int i; + VARDECL(celt_word16, tmp); + celt_word32 mem0=0,mem1=0; + int is_transient = 0; + int block; + int N; + /* FIXME: Make that smaller */ + celt_word16 bins[50]; + SAVE_STACK; + ALLOC(tmp, len, celt_word16); + + block = overlap/2; + N=len/block; + if (C==1) + { + for (i=0;i=3) + is_transient=1; + conseq = 0; + for (j=i+1;j=7) + is_transient=1; + } + RESTORE_STACK; + return is_transient; +} + +/** Apply window and compute the MDCT for all sub-frames and + all channels in a frame */ +static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * restrict in, celt_sig * restrict out, int _C, int LM) +{ + const int C = CHANNELS(_C); + if (C==1 && !shortBlocks) + { + const int overlap = OVERLAP(mode); + clt_mdct_forward(&mode->mdct, in, out, mode->window, overlap, mode->maxLM-LM); + } else { + const int overlap = OVERLAP(mode); + int N = mode->shortMdctSize<mdct[0];*/ + N = mode->shortMdctSize; + B = shortBlocks; + } + ALLOC(tmp, N, celt_word32); + c=0; do { + for (b=0;bmdct, in+c*(B*N+overlap)+b*N, tmp, mode->window, overlap, shortBlocks ? mode->maxLM : mode->maxLM-LM); + /* Interleaving the sub-frames */ + for (j=0;jshortMdctSize<shortMdctSize; + B = shortBlocks; + } + /* Prevents problems from the imdct doing the overlap-add */ + CELT_MEMSET(x, 0, overlap); + + for (b=0;bmdct, tmp, x+N2*b, mode->window, overlap, shortBlocks ? mode->maxLM : mode->maxLM-LM); + } + + for (j=0;j>LM;j++) + L2 = MAC16_16(L2, tmp[(j<eBands[len]-m->eBands[len-1])<eBands[i+1]-m->eBands[i])<eBands[i]<eBands[i]<>LM); + best_L1 = L1; + /*printf ("%f ", L1);*/ + for (k=0;k>(LM-k), 1<<(LM-k)); + else + haar1(tmp, N>>k, 1<>LM); + + if (L1 < best_L1) + { + best_L1 = L1; + best_level = k+1; + } + } + /*printf ("%d ", isTransient ? LM-best_level : best_level);*/ + if (isTransient) + metric[i] = best_level; + else + metric[i] = -best_level; + *tf_sum += metric[i]; + } + /*printf("\n");*/ + /* FIXME: Figure out how to set this */ + tf_select = 0; + + cost0 = 0; + cost1 = isTransient ? 0 : lambda; + /* Viterbi forward pass */ + for (i=1;i=0;i--) + { + if (tf_res[i+1] == 1) + tf_res[i] = path1[i+1]; + else + tf_res[i] = path0[i+1]; + } + RESTORE_STACK; + return tf_select; +} + +static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM, int tf_select, ec_enc *enc) +{ + int curr, i; + int tf_select_rsv; + int tf_changed; + int logp; + celt_uint32 budget; + celt_uint32 tell; + budget = enc->storage*8; + tell = ec_tell(enc); + logp = isTransient ? 2 : 4; + /* Reserve space to code the tf_select decision. */ + tf_select_rsv = LM>0 && tell+logp+1 <= budget; + budget -= tf_select_rsv; + curr = tf_changed = 0; + for (i=start;istorage*8; + tell = ec_tell(dec); + logp = isTransient ? 2 : 4; + tf_select_rsv = LM>0 && tell+logp+1<=budget; + budget -= tf_select_rsv; + tf_changed = curr = 0; + for (i=start;inbEBands;i++) + { + int N; + N=(m->eBands[i+1]-m->eBands[i])<cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2; + } +} + +static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X, + const celt_word16 *bandLogE, int end, int LM, int C, int N0) +{ + int i; + celt_word32 diff=0; + int c; + int trim_index = 5; + if (C==2) + { + celt_word16 sum = 0; /* Q10 */ + /* Compute inter-channel correlation for low frequencies */ + for (i=0;i<8;i++) + { + int j; + celt_word32 partial = 0; + for (j=m->eBands[i]<eBands[i+1]< QCONST16(.995f,10)) + trim_index-=4; + else if (sum > QCONST16(.92f,10)) + trim_index-=3; + else if (sum > QCONST16(.85f,10)) + trim_index-=2; + else if (sum > QCONST16(.8f,10)) + trim_index-=1; + } + + /* Estimate spectral tilt */ + c=0; do { + for (i=0;inbEBands]*(celt_int32)(2+2*i-m->nbEBands); + } + } while (++c<0); + diff /= C*(end-1); + /*printf("%f\n", diff);*/ + if (diff > QCONST16(2.f, DB_SHIFT)) + trim_index--; + if (diff > QCONST16(8.f, DB_SHIFT)) + trim_index--; + if (diff < -QCONST16(4.f, DB_SHIFT)) + trim_index++; + if (diff < -QCONST16(10.f, DB_SHIFT)) + trim_index++; + + if (trim_index<0) + trim_index = 0; + if (trim_index>10) + trim_index = 10; + return trim_index; +} + +static int stereo_analysis(const CELTMode *m, const celt_norm *X, + int LM, int N0) +{ + int i; + int thetas; + celt_word32 sumLR = EPSILON, sumMS = EPSILON; + + /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */ + for (i=0;i<13;i++) + { + int j; + for (j=m->eBands[i]<eBands[i+1]<eBands[13]<<(LM+1))+thetas, sumMS) + > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR); +} + +#ifdef FIXED_POINT +CELT_STATIC +int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ +#else +CELT_STATIC +int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ +#endif + int i, c, N; + celt_int32 bits; + ec_enc _enc; + VARDECL(celt_sig, in); + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(celt_word16, bandLogE); + VARDECL(int, fine_quant); + VARDECL(celt_word16, error); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *_overlap_mem; + celt_sig *prefilter_mem; + celt_word16 *oldBandE, *oldLogE, *oldLogE2; + int shortBlocks=0; + int isTransient=0; + int resynth; + const int CC = CHANNELS(st->channels); + const int C = CHANNELS(st->stream_channels); + int LM, M; + int tf_select; + int nbFilledBytes, nbAvailableBytes; + int effEnd; + int codedBands; + int tf_sum; + int alloc_trim; + int pitch_index=COMBFILTER_MINPERIOD; + celt_word16 gain1 = 0; + int intensity=0; + int dual_stereo=0; + int effectiveBytes; + celt_word16 pf_threshold; + int dynalloc_logp; + celt_int32 vbr_rate; + celt_int32 total_bits; + celt_int32 total_boost; + celt_int32 balance; + celt_int32 tell; + int prefilter_tapset=0; + int pf_on; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence=0; + ALLOC_STACK; + + if (nbCompressedBytes<2 || pcm==NULL) + return CELT_BAD_ARG; + + frame_size *= st->upsample; + for (LM=0;LM<=st->mode->maxLM;LM++) + if (st->mode->shortMdctSize<st->mode->maxLM) + return CELT_BAD_ARG; + M=1<mode->shortMdctSize; + + prefilter_mem = st->in_mem+CC*(st->overlap); + _overlap_mem = prefilter_mem+CC*COMBFILTER_MAXPERIOD; + /*_overlap_mem = st->in_mem+C*(st->overlap);*/ + oldBandE = (celt_word16*)(st->in_mem+CC*(2*st->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + CC*st->mode->nbEBands; + oldLogE2 = oldLogE + CC*st->mode->nbEBands; + + if (enc==NULL) + { + tell=1; + nbFilledBytes=0; + } else { + tell=ec_tell(enc); + nbFilledBytes=(tell+4)>>3; + } + + if (st->signalling && enc==NULL) + { + int tmp = (st->mode->effEBands-st->end)>>1; + st->end = IMAX(1, st->mode->effEBands-tmp); + compressed[0] = tmp<<5; + compressed[0] |= LM<<3; + compressed[0] |= (C==2)<<2; + /* Convert "standard mode" to Opus header */ + if (st->mode->Fs==48000 && st->mode->shortMdctSize==120) + { + int c0 = toOpus(compressed[0]); + if (c0<0) + return CELT_BAD_ARG; + compressed[0] = c0; + } + compressed++; + nbCompressedBytes--; + } + + /* Can't produce more than 1275 output bytes */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275); + nbAvailableBytes = nbCompressedBytes - nbFilledBytes; + + if (st->vbr) + { + celt_int32 den=st->mode->Fs>>BITRES; + vbr_rate=(st->bitrate*frame_size+(den>>1))/den; + if (st->signalling) + vbr_rate -= 8<>(3+BITRES); + } else { + celt_int32 tmp; + vbr_rate = 0; + tmp = st->bitrate*frame_size; + if (tell>1) + tmp += tell; + nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, + (tmp+4*st->mode->Fs)/(8*st->mode->Fs)-!!st->signalling)); + effectiveBytes = nbCompressedBytes; + } + + if (enc==NULL) + { + ec_enc_init(&_enc, compressed, nbCompressedBytes); + enc = &_enc; + } + + if (vbr_rate>0) + { + /* Computes the max bit-rate allowed in VBR mode to avoid violating the + target rate and buffering. + We must do this up front so that bust-prevention logic triggers + correctly if we don't have enough bits. */ + if (st->constrained_vbr) + { + celt_int32 vbr_bound; + celt_int32 max_allowed; + /* We could use any multiple of vbr_rate as bound (depending on the + delay). + This is clamped to ensure we use at least two bytes if the encoder + was entirely empty, but to allow 0 in hybrid mode. */ + vbr_bound = vbr_rate; + max_allowed = IMIN(IMAX(tell==1?2:0, + vbr_rate+vbr_bound-st->vbr_reservoir>>(BITRES+3)), + nbAvailableBytes); + if(max_allowed < nbAvailableBytes) + { + nbCompressedBytes = nbFilledBytes+max_allowed; + nbAvailableBytes = max_allowed; + ec_enc_shrink(enc, nbCompressedBytes); + } + } + } + total_bits = nbCompressedBytes*8; + + effEnd = st->end; + if (effEnd > st->mode->effEBands) + effEnd = st->mode->effEBands; + + ALLOC(in, CC*(N+st->overlap), celt_sig); + + /* Find pitch period and gain */ + { + VARDECL(celt_sig, _pre); + celt_sig *pre[2]; + SAVE_STACK; + ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig); + + pre[0] = _pre; + pre[1] = _pre + (N+COMBFILTER_MAXPERIOD); + + silence = 1; + c=0; do { + int count = 0; + const celt_word16 * restrict pcmp = pcm+c; + celt_sig * restrict inp = in+c*(N+st->overlap)+st->overlap; + + for (i=0;iclip) + x = MAX32(-65536.f, MIN32(65536.f,x)); +#endif + if (++count==st->upsample) + { + count=0; + pcmp+=CC; + } else { + x = 0; + } + /* Apply pre-emphasis */ + tmp = MULT16_16(st->mode->preemph[2], x); + *inp = tmp + st->preemph_memE[c]; + st->preemph_memE[c] = MULT16_32_Q15(st->mode->preemph[1], *inp) + - MULT16_32_Q15(st->mode->preemph[0], tmp); + silence = silence && *inp == 0; + inp++; + } + CELT_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); + CELT_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+st->overlap)+st->overlap, N); + } while (++c0) + { + effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2); + total_bits=nbCompressedBytes*8; + nbAvailableBytes=2; + ec_enc_shrink(enc, nbCompressedBytes); + } + /* Pretend we've filled all the remaining bits with zeros + (that's what the initialiser did anyway) */ + tell = nbCompressedBytes*8; + enc->nbits_total+=tell-ec_tell(enc); + } +#ifdef ENABLE_POSTFILTER + if (nbAvailableBytes>12*C && st->start==0 && !silence && !st->disable_pf && st->complexity >= 5) + { + VARDECL(celt_word16, pitch_buf); + ALLOC(pitch_buf, (COMBFILTER_MAXPERIOD+N)>>1, celt_word16); + + pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC); + pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N, + COMBFILTER_MAXPERIOD-COMBFILTER_MINPERIOD, &pitch_index); + pitch_index = COMBFILTER_MAXPERIOD-pitch_index; + + gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD, + N, &pitch_index, st->prefilter_period, st->prefilter_gain); + if (pitch_index > COMBFILTER_MAXPERIOD-2) + pitch_index = COMBFILTER_MAXPERIOD-2; + gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1); + if (st->loss_rate>2) + gain1 = HALF32(gain1); + if (st->loss_rate>4) + gain1 = HALF32(gain1); + if (st->loss_rate>8) + gain1 = 0; + prefilter_tapset = st->tapset_decision; + } else { + gain1 = 0; + } + + /* Gain threshold for enabling the prefilter/postfilter */ + pf_threshold = QCONST16(.2f,15); + + /* Adjusting the threshold based on rate and continuity */ + if (abs(pitch_index-st->prefilter_period)*10>pitch_index) + pf_threshold += QCONST16(.2f,15); + if (nbAvailableBytes<25) + pf_threshold += QCONST16(.1f,15); + if (nbAvailableBytes<35) + pf_threshold += QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.4f,15)) + pf_threshold -= QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.55f,15)) + pf_threshold -= QCONST16(.1f,15); + + /* Hard threshold at 0.2 */ + pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15)); + if (gain1start==0 && tell+16<=total_bits) + ec_enc_bit_logp(enc, 0, 1); + gain1 = 0; + pf_on = 0; + } else { + /*This block is not gated by a total bits check only because + of the nbAvailableBytes check above.*/ + int qg; + int octave; + + if (ABS16(gain1-st->prefilter_gain)prefilter_gain; + +#ifdef FIXED_POINT + qg = ((gain1+1536)>>10)/3-1; +#else + qg = floor(.5+gain1*32/3)-1; +#endif + qg = IMAX(0, IMIN(7, qg)); + ec_enc_bit_logp(enc, 1, 1); + pitch_index += 1; + octave = EC_ILOG(pitch_index)-5; + ec_enc_uint(enc, octave, 6); + ec_enc_bits(enc, pitch_index-(16<start==0 && tell+16<=total_bits) + ec_enc_bit_logp(enc, 0, 1); + pf_on = 0; +#endif /* ENABLE_POSTFILTER */ + + c=0; do { + int offset = st->mode->shortMdctSize-st->mode->overlap; + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + CELT_COPY(in+c*(N+st->overlap), st->in_mem+c*(st->overlap), st->overlap); +#ifdef ENABLE_POSTFILTER + if (offset) + comb_filter(in+c*(N+st->overlap)+st->overlap, pre[c]+COMBFILTER_MAXPERIOD, + st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain, + st->prefilter_tapset, st->prefilter_tapset, NULL, 0); + + comb_filter(in+c*(N+st->overlap)+st->overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset, + st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1, + st->prefilter_tapset, prefilter_tapset, st->mode->window, st->mode->overlap); +#endif /* ENABLE_POSTFILTER */ + CELT_COPY(st->in_mem+c*(st->overlap), in+c*(N+st->overlap)+N, st->overlap); + +#ifdef ENABLE_POSTFILTER + if (N>COMBFILTER_MAXPERIOD) + { + CELT_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD); + } else { + CELT_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N); + CELT_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N); + } +#endif /* ENABLE_POSTFILTER */ + } while (++c0 && ec_tell(enc)+3<=total_bits) + { + if (st->complexity > 1) + { + isTransient = transient_analysis(in, N+st->overlap, CC, + st->overlap); + if (isTransient) + shortBlocks = M; + } + ec_enc_bit_logp(enc, isTransient, 3); + } + + ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(bandE,st->mode->nbEBands*CC, celt_ener); + ALLOC(bandLogE,st->mode->nbEBands*CC, celt_word16); + /* Compute MDCTs */ + compute_mdcts(st->mode, shortBlocks, in, freq, CC, LM); + + if (CC==2&&C==1) + { + for (i=0;iupsample != 1) + { + c=0; do + { + int bound = N/st->upsample; + for (i=0;iupsample; + for (;imode, freq, bandE, effEnd, C, M); + + amp2Log2(st->mode, effEnd, st->end, bandE, bandLogE, C); + + /* Band normalisation */ + normalise_bands(st->mode, freq, X, bandE, effEnd, C, M); + + ALLOC(tf_res, st->mode->nbEBands, int); + /* Needs to be before coarse energy quantization because otherwise the energy gets modified */ + tf_select = tf_analysis(st->mode, bandLogE, oldBandE, effEnd, C, isTransient, tf_res, effectiveBytes, X, N, LM, &tf_sum); + for (i=effEnd;iend;i++) + tf_res[i] = tf_res[effEnd-1]; + + ALLOC(error, C*st->mode->nbEBands, celt_word16); + quant_coarse_energy(st->mode, st->start, st->end, effEnd, bandLogE, + oldBandE, total_bits, error, enc, + C, LM, nbAvailableBytes, st->force_intra, + &st->delayedIntra, st->complexity >= 4, st->loss_rate); + + tf_encode(st->start, st->end, isTransient, tf_res, LM, tf_select, enc); + + st->spread_decision = SPREAD_NORMAL; + if (ec_tell(enc)+4<=total_bits) + { + if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + } else { + st->spread_decision = spreading_decision(st->mode, X, + &st->tonal_average, st->spread_decision, &st->hf_average, + &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M); + } + ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5); + } + + ALLOC(cap, st->mode->nbEBands, int); + ALLOC(offsets, st->mode->nbEBands, int); + + init_caps(st->mode,cap,LM,C); + for (i=0;imode->nbEBands;i++) + offsets[i] = 0; + /* Dynamic allocation code */ + /* Make sure that dynamic allocation can't make us bust the budget */ + if (effectiveBytes > 50 && LM>=1) + { + int t1, t2; + if (LM <= 1) + { + t1 = 3; + t2 = 5; + } else { + t1 = 2; + t2 = 4; + } + for (i=st->start+1;iend-1;i++) + { + celt_word32 d2; + d2 = 2*bandLogE[i]-bandLogE[i-1]-bandLogE[i+1]; + if (C==2) + d2 = HALF32(d2 + 2*bandLogE[i+st->mode->nbEBands]- + bandLogE[i-1+st->mode->nbEBands]-bandLogE[i+1+st->mode->nbEBands]); + if (d2 > SHL16(t1,DB_SHIFT)) + offsets[i] += 1; + if (d2 > SHL16(t2,DB_SHIFT)) + offsets[i] += 1; + } + } + dynalloc_logp = 6; + total_bits<<=BITRES; + total_boost = 0; + tell = ec_tell_frac(enc); + for (i=st->start;iend;i++) + { + int width, quanta; + int dynalloc_loop_logp; + int boost; + int j; + width = C*(st->mode->eBands[i+1]-st->mode->eBands[i])<mode, X, bandLogE, + st->end, LM, C, N); + ec_enc_icdf(enc, alloc_trim, trim_icdf, 7); + tell = ec_tell_frac(enc); + } + + /* Variable bitrate */ + if (vbr_rate>0) + { + celt_word16 alpha; + celt_int32 delta; + /* The target rate in 8th bits per frame */ + celt_int32 target; + celt_int32 min_allowed; + + target = vbr_rate + st->vbr_offset - ((40*C+20)<end-st->start)) + target = 7*target/4; + else if (tf_sum < -(st->end-st->start)) + target = 3*target/2; + else if (M > 1) + target-=(target+14)/28; + + /* The current offset is removed from the target and the space used + so far is added*/ + target=target+tell; + + /* In VBR mode the frame size must not be reduced so much that it would + result in the encoder running out of bits. + The margin of 2 bytes ensures that none of the bust-prevention logic + in the decoder will have triggered so far. */ + min_allowed = (tell+total_boost+(1<>(BITRES+3)) + 2 - nbFilledBytes; + + nbAvailableBytes = target+(1<<(BITRES+2))>>(BITRES+3); + nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes); + nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes; + + /* By how much did we "miss" the target on that frame */ + delta = target - vbr_rate; + + target=nbAvailableBytes<<(BITRES+3); + + /*If the frame is silent we don't adjust our drift, otherwise + the encoder will shoot to very high rates after hitting a + span of silence, but we do allow the bitres to refill. + This means that we'll undershoot our target in CVBR/VBR modes + on files with lots of silence. */ + if(silence) + { + nbAvailableBytes = 2; + target = 2*8<vbr_count < 970) + { + st->vbr_count++; + alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16)); + } else + alpha = QCONST16(.001f,15); + /* How many bits have we used in excess of what we're allowed */ + if (st->constrained_vbr) + st->vbr_reservoir += target - vbr_rate; + /*printf ("%d\n", st->vbr_reservoir);*/ + + /* Compute the offset we need to apply in order to reach the target */ + st->vbr_drift += (celt_int32)MULT16_32_Q15(alpha,delta-st->vbr_offset-st->vbr_drift); + st->vbr_offset = -st->vbr_drift; + /*printf ("%d\n", st->vbr_drift);*/ + + if (st->constrained_vbr && st->vbr_reservoir < 0) + { + /* We're under the min value -- increase rate */ + int adjust = (-st->vbr_reservoir)/(8<vbr_reservoir = 0; + /*printf ("+%d\n", adjust);*/ + } + nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes); + /* This moves the raw bits to take into account the new compressed size */ + ec_enc_shrink(enc, nbCompressedBytes); + } + if (C==2) + { + int effectiveRate; + + /* Always use MS for 2.5 ms frames until we can do a better analysis */ + if (LM!=0) + dual_stereo = stereo_analysis(st->mode, X, LM, N); + + /* Account for coarse energy */ + effectiveRate = (8*effectiveBytes - 80)>>LM; + + /* effectiveRate in kb/s */ + effectiveRate = 2*effectiveRate/5; + if (effectiveRate<35) + intensity = 8; + else if (effectiveRate<50) + intensity = 12; + else if (effectiveRate<68) + intensity = 16; + else if (effectiveRate<84) + intensity = 18; + else if (effectiveRate<102) + intensity = 19; + else if (effectiveRate<130) + intensity = 20; + else + intensity = 100; + intensity = IMIN(st->end,IMAX(st->start, intensity)); + } + + /* Bit allocation */ + ALLOC(fine_quant, st->mode->nbEBands, int); + ALLOC(pulses, st->mode->nbEBands, int); + ALLOC(fine_priority, st->mode->nbEBands, int); + + /* bits = packet size - where we are - safety*/ + bits = ((celt_int32)nbCompressedBytes*8<=2&&bits>=(LM+2<mode, st->start, st->end, offsets, cap, + alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands); + st->lastCodedBands = codedBands; + + quant_fine_energy(st->mode, st->start, st->end, oldBandE, error, fine_quant, enc, C); + +#ifdef MEASURE_NORM_MSE + float X0[3000]; + float bandE0[60]; + c=0; do + for (i=0;imode->nbEBands;i++) + bandE0[i] = bandE[i]; +#endif + + /* Residual quantisation */ + ALLOC(collapse_masks, C*st->mode->nbEBands, unsigned char); + quant_all_bands(1, st->mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks, + bandE, pulses, shortBlocks, st->spread_decision, dual_stereo, intensity, tf_res, resynth, + nbCompressedBytes*(8<rng); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = st->consec_transient<2; + ec_enc_bits(enc, anti_collapse_on, 1); + } + quant_energy_finalise(st->mode, st->start, st->end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C); + + if (silence) + { + for (i=0;imode->nbEBands;i++) + oldBandE[i] = -QCONST16(28.f,DB_SHIFT); + } + +#ifdef RESYNTH + /* Re-synthesis of the coded audio if required */ + if (resynth) + { + celt_sig *out_mem[2]; + celt_sig *overlap_mem[2]; + + log2Amp(st->mode, st->start, st->end, bandE, oldBandE, C); + if (silence) + { + for (i=0;imode->nbEBands;i++) + bandE[i] = 0; + } + +#ifdef MEASURE_NORM_MSE + measure_norm_mse(st->mode, X, X0, bandE, bandE0, M, N, C); +#endif + if (anti_collapse_on) + { + anti_collapse(st->mode, X, collapse_masks, LM, C, CC, N, + st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng); + } + + /* Synthesis */ + denormalise_bands(st->mode, X, freq, bandE, effEnd, C, M); + + CELT_MOVE(st->syn_mem[0], st->syn_mem[0]+N, MAX_PERIOD); + if (CC==2) + CELT_MOVE(st->syn_mem[1], st->syn_mem[1]+N, MAX_PERIOD); + + c=0; do + for (i=0;imode->eBands[st->start];i++) + freq[c*N+i] = 0; + while (++cmode->eBands[st->end];isyn_mem[0]+MAX_PERIOD; + if (CC==2) + out_mem[1] = st->syn_mem[1]+MAX_PERIOD; + + c=0; do + overlap_mem[c] = _overlap_mem + c*st->overlap; + while (++cmode, shortBlocks, freq, out_mem, overlap_mem, CC, LM); + +#ifdef ENABLE_POSTFILTER + c=0; do { + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, st->mode->shortMdctSize, + st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset, + st->mode->window, st->overlap); + if (LM!=0) + comb_filter(out_mem[c]+st->mode->shortMdctSize, out_mem[c]+st->mode->shortMdctSize, st->prefilter_period, pitch_index, N-st->mode->shortMdctSize, + st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset, + st->mode->window, st->mode->overlap); + } while (++cupsample, st->mode->preemph, st->preemph_memD); + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + st->prefilter_period = pitch_index; + st->prefilter_gain = gain1; + st->prefilter_tapset = prefilter_tapset; +#ifdef RESYNTH + if (LM!=0) + { + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + if (CC==2&&C==1) { + for (i=0;imode->nbEBands;i++) + oldBandE[st->mode->nbEBands+i]=oldBandE[i]; + } + + /* In case start or end were to change */ + c=0; do + { + for (i=0;istart;i++) + oldBandE[c*st->mode->nbEBands+i]=0; + for (i=st->end;imode->nbEBands;i++) + oldBandE[c*st->mode->nbEBands+i]=0; + } while (++cmode->nbEBands;i++) + oldLogE2[i] = oldLogE[i]; + for (i=0;imode->nbEBands;i++) + oldLogE[i] = oldBandE[i]; + } else { + for (i=0;imode->nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + if (isTransient) + st->consec_transient++; + else + st->consec_transient=0; + st->rng = enc->rng; + + /* If there's any room left (can only happen for very high rates), + it's already filled with zeros */ + ec_enc_done(enc); + + if (st->signalling) + nbCompressedBytes++; + + RESTORE_STACK; + if (ec_get_error(enc)) + return CELT_INTERNAL_ERROR; + else + return nbCompressedBytes; +} + +#ifdef FIXED_POINT +#ifndef DISABLE_FLOAT_API +CELT_STATIC +int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ + int j, ret, C, N; + VARDECL(celt_int16, in); + ALLOC_STACK; + + if (pcm==NULL) + return CELT_BAD_ARG; + + C = CHANNELS(st->channels); + N = frame_size; + ALLOC(in, C*N, celt_int16); + + for (j=0;jchannels); + N=frame_size; + ALLOC(in, C*N, celt_sig); + for (j=0;j10) + goto bad_arg; + st->complexity = value; + } + break; + case CELT_SET_START_BAND_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + if (value<0 || value>=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_PREDICTION_REQUEST: + { + int value = va_arg(ap, celt_int32); + if (value<0 || value>2) + goto bad_arg; + st->disable_pf = value<=1; + st->force_intra = value==0; + } + break; + case CELT_SET_LOSS_PERC_REQUEST: + { + int value = va_arg(ap, celt_int32); + if (value<0 || value>100) + goto bad_arg; + st->loss_rate = value; + } + break; + case CELT_SET_VBR_CONSTRAINT_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + st->constrained_vbr = value; + } + break; + case CELT_SET_VBR_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + st->vbr = value; + } + break; + case CELT_SET_BITRATE_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + if (value<=500) + goto bad_arg; + value = IMIN(value, 260000*st->channels); + st->bitrate = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case CELT_RESET_STATE: + { + CELT_MEMSET((char*)&st->ENCODER_RESET_START, 0, + celt_encoder_get_size_custom(st->mode, st->channels)- + ((char*)&st->ENCODER_RESET_START - (char*)st)); + st->vbr_offset = 0; + st->delayedIntra = 1; + st->spread_decision = SPREAD_NORMAL; + st->tonal_average = QCONST16(1.f,8); + } + break; + case CELT_SET_INPUT_CLIPPING_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + st->clip = value; + } + break; +#ifdef OPUS_BUILD + case CELT_SET_SIGNALLING_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + st->signalling = value; + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; +#endif + default: + goto bad_request; + } + va_end(ap); + return CELT_OK; +bad_arg: + va_end(ap); + return CELT_BAD_ARG; +bad_request: + va_end(ap); + return CELT_UNIMPLEMENTED; +} + +/**********************************************************************/ +/* */ +/* DECODER */ +/* */ +/**********************************************************************/ +#define DECODE_BUFFER_SIZE 2048 + +/** Decoder state + @brief Decoder state + */ +struct CELTDecoder { + const CELTMode *mode; + int overlap; + int channels; + int stream_channels; + + int downsample; + int start, end; + int signalling; + + /* Everything beyond this point gets cleared on a reset */ +#define DECODER_RESET_START rng + + celt_uint32 rng; + int error; + int last_pitch_index; + int loss_count; + int postfilter_period; + int postfilter_period_old; + celt_word16 postfilter_gain; + celt_word16 postfilter_gain_old; + int postfilter_tapset; + int postfilter_tapset_old; + + celt_sig preemph_memD[2]; + + celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */ + /* celt_word16 lpc[], Size = channels*LPC_ORDER */ + /* celt_word16 oldEBands[], Size = 2*mode->nbEBands */ + /* celt_word16 oldLogE[], Size = 2*mode->nbEBands */ + /* celt_word16 oldLogE2[], Size = 2*mode->nbEBands */ + /* celt_word16 backgroundLogE[], Size = 2*mode->nbEBands */ +}; + +int celt_decoder_get_size(int channels) +{ + const CELTMode *mode = celt_mode_create(48000, 960, NULL); + return celt_decoder_get_size_custom(mode, channels); +} + +int celt_decoder_get_size_custom(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTDecoder) + + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig) + + channels*LPC_ORDER*sizeof(celt_word16) + + 4*2*mode->nbEBands*sizeof(celt_word16); + return size; +} + +CELTDecoder *celt_decoder_create(int sampling_rate, int channels, int *error) +{ + CELTDecoder *st; + st = (CELTDecoder *)celt_alloc(celt_decoder_get_size(channels)); + if (st!=NULL && celt_decoder_init(st, sampling_rate, channels, error)==NULL) + { + celt_decoder_destroy(st); + st = NULL; + } + return st; +} + +CELTDecoder *celt_decoder_create_custom(const CELTMode *mode, int channels, int *error) +{ + CELTDecoder *st = (CELTDecoder *)celt_alloc(celt_decoder_get_size_custom(mode, channels)); + if (st!=NULL && celt_decoder_init_custom(st, mode, channels, error)==NULL) + { + celt_decoder_destroy(st); + st = NULL; + } + return st; +} + +CELTDecoder *celt_decoder_init(CELTDecoder *st, int sampling_rate, int channels, int *error) +{ + celt_decoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, error); + st->downsample = resampling_factor(sampling_rate); + if (st->downsample==0) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + return st; +} + +CELTDecoder *celt_decoder_init_custom(CELTDecoder *st, const CELTMode *mode, int channels, int *error) +{ + if (channels < 0 || channels > 2) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + + if (st==NULL) + { + if (error) + *error = CELT_ALLOC_FAIL; + return NULL; + } + + CELT_MEMSET((char*)st, 0, celt_decoder_get_size_custom(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->downsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + + st->loss_count = 0; + + if (error) + *error = CELT_OK; + return st; +} + +void celt_decoder_destroy(CELTDecoder *st) +{ + celt_free(st); +} + +static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict pcm, int N, int LM) +{ + int c; + int pitch_index; + int overlap = st->mode->overlap; + celt_word16 fade = Q15ONE; + int i, len; + const int C = CHANNELS(st->channels); + int offset; + celt_sig *out_mem[2]; + celt_sig *decode_mem[2]; + celt_sig *overlap_mem[2]; + celt_word16 *lpc; + celt_word32 *out_syn[2]; + celt_word16 *oldBandE, *oldLogE2, *backgroundLogE; + int plc=1; + SAVE_STACK; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+st->overlap); + out_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE-MAX_PERIOD; + overlap_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*C); + oldBandE = lpc+C*LPC_ORDER; + oldLogE2 = oldBandE + C*st->mode->nbEBands; + backgroundLogE = oldLogE2 + C*st->mode->nbEBands; + + out_syn[0] = out_mem[0]+MAX_PERIOD-N; + if (C==2) + out_syn[1] = out_mem[1]+MAX_PERIOD-N; + + len = N+st->mode->overlap; + + if (st->loss_count >= 5) + { + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + celt_uint32 seed; + int effEnd; + + effEnd = st->end; + if (effEnd > st->mode->effEBands) + effEnd = st->mode->effEBands; + + ALLOC(freq, C*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + ALLOC(bandE, st->mode->nbEBands*C, celt_ener); + + log2Amp(st->mode, st->start, st->end, bandE, backgroundLogE, C); + + seed = st->rng; + for (c=0;cmode->eBands[st->start]<mode->effEBands;i++) + { + int j; + int boffs; + int blen; + boffs = N*c+(st->mode->eBands[i]<mode->eBands[i+1]-st->mode->eBands[i])<>20; + } + renormalise_vector(X+boffs, blen, Q15ONE); + } + for (i=(st->mode->eBands[st->end]<rng = seed; + + denormalise_bands(st->mode, X, freq, bandE, st->mode->effEBands, C, 1<mode->eBands[st->start]<mode->eBands[effEnd]<downsample!=1) + bound = IMIN(bound, N/st->downsample); + for (i=bound;imode, 0, freq, out_syn, overlap_mem, C, LM); + plc = 0; + } else if (st->loss_count == 0) + { + celt_word16 pitch_buf[MAX_PERIOD>>1]; + int len2 = len; + /* FIXME: This is a kludge */ + if (len2>MAX_PERIOD>>1) + len2 = MAX_PERIOD>>1; + pitch_downsample(out_mem, pitch_buf, MAX_PERIOD, C); + pitch_search(pitch_buf+((MAX_PERIOD-len2)>>1), pitch_buf, len2, + MAX_PERIOD-len2-100, &pitch_index); + pitch_index = MAX_PERIOD-len2-pitch_index; + st->last_pitch_index = pitch_index; + } else { + pitch_index = st->last_pitch_index; + fade = QCONST16(.8f,15); + } + + if (plc) + { + c=0; do { + /* FIXME: This is more memory than necessary */ + celt_word32 e[2*MAX_PERIOD]; + celt_word16 exc[2*MAX_PERIOD]; + celt_word32 ac[LPC_ORDER+1]; + celt_word16 decay = 1; + celt_word32 S1=0; + celt_word16 mem[LPC_ORDER]={0}; + + offset = MAX_PERIOD-pitch_index; + for (i=0;iloss_count == 0) + { + _celt_autocorr(exc, ac, st->mode->window, st->mode->overlap, + LPC_ORDER, MAX_PERIOD); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=LPC_ORDER;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER); + } + for (i=0;i E2) + E1 = E2; + decay = celt_sqrt(frac_div32(SHR(E1,1),E2)); + } + + /* Copy excitation, taking decay into account */ + for (i=0;imode->overlap;i++) + { + celt_word16 tmp; + if (offset+i >= MAX_PERIOD) + { + offset -= pitch_index; + decay = MULT16_16_Q15(decay, decay); + } + e[i] = SHL32(EXTEND32(MULT16_16_Q15(decay, exc[offset+i])), SIG_SHIFT); + tmp = ROUND16(out_mem[c][offset+i],SIG_SHIFT); + S1 += SHR32(MULT16_16(tmp,tmp),8); + } + for (i=0;imode->overlap;i++) + e[i] = MULT16_32_Q15(fade, e[i]); + iir(e, lpc+c*LPC_ORDER, e, len+st->mode->overlap, LPC_ORDER, mem); + + { + celt_word32 S2=0; + for (i=0;i SHR32(S2,2))) +#else + /* Float test is written this way to catch NaNs at the same time */ + if (!(S1 > 0.2f*S2)) +#endif + { + for (i=0;ipostfilter_period, st->postfilter_period, st->overlap, + st->postfilter_gain, st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset, + NULL, 0); +#endif /* ENABLE_POSTFILTER */ + + for (i=0;imode->overlap-N;i++) + out_mem[c][i] = out_mem[c][N+i]; + + /* Apply TDAC to the concealed audio so that it blends with the + previous and next frames */ + for (i=0;imode->window[i], e[N+overlap-1-i]) + + MULT16_32_Q15(st->mode->window[overlap-i-1], e[N+i ]); + out_mem[c][MAX_PERIOD+i] = MULT16_32_Q15(st->mode->window[overlap-i-1], tmp); + out_mem[c][MAX_PERIOD+overlap-i-1] = MULT16_32_Q15(st->mode->window[i], tmp); + } + for (i=0;ipostfilter_period, st->postfilter_period, st->overlap, + -st->postfilter_gain, -st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset, + NULL, 0); +#endif /* ENABLE_POSTFILTER */ + for (i=0;idownsample, st->mode->preemph, st->preemph_memD); + + st->loss_count++; + + RESTORE_STACK; +} + +#ifdef FIXED_POINT +CELT_STATIC +int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, celt_int16 * restrict pcm, int frame_size, ec_dec *dec) +{ +#else +CELT_STATIC +int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, celt_sig * restrict pcm, int frame_size, ec_dec *dec) +{ +#endif + int c, i, N; + int spread_decision; + celt_int32 bits; + ec_dec _dec; + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(int, fine_quant); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *out_mem[2]; + celt_sig *decode_mem[2]; + celt_sig *overlap_mem[2]; + celt_sig *out_syn[2]; + celt_word16 *lpc; + celt_word16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + + int shortBlocks; + int isTransient; + int intra_ener; + const int CC = CHANNELS(st->channels); + int LM, M; + int effEnd; + int codedBands; + int alloc_trim; + int postfilter_pitch; + celt_word16 postfilter_gain; + int intensity=0; + int dual_stereo=0; + celt_int32 total_bits; + celt_int32 balance; + celt_int32 tell; + int dynalloc_logp; + int postfilter_tapset; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence; + int C = CHANNELS(st->stream_channels); + ALLOC_STACK; + + frame_size *= st->downsample; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+st->overlap); + out_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE-MAX_PERIOD; + overlap_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*CC); + oldBandE = lpc+LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + backgroundLogE = oldLogE2 + 2*st->mode->nbEBands; + + if (st->signalling && data!=NULL) + { + int data0=data[0]; + /* Convert "standard mode" to Opus header */ + if (st->mode->Fs==48000 && st->mode->shortMdctSize==120) + { + data0 = fromOpus(data0); + if (data0<0) + return CELT_CORRUPTED_DATA; + } + st->end = IMAX(1, st->mode->effEBands-2*(data0>>5)); + LM = (data0>>3)&0x3; + C = 1 + ((data0>>2)&0x1); + data++; + len--; + if (LM>st->mode->maxLM) + return CELT_CORRUPTED_DATA; + if (frame_size < st->mode->shortMdctSize<mode->shortMdctSize<mode->maxLM;LM++) + if (st->mode->shortMdctSize<st->mode->maxLM) + return CELT_BAD_ARG; + } + M=1<1275 || pcm==NULL) + return CELT_BAD_ARG; + + N = M*st->mode->shortMdctSize; + + effEnd = st->end; + if (effEnd > st->mode->effEBands) + effEnd = st->mode->effEBands; + + ALLOC(freq, IMAX(CC,C)*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + ALLOC(bandE, st->mode->nbEBands*C, celt_ener); + c=0; do + for (i=0;imode->eBands[st->start];i++) + X[c*N+i] = 0; + while (++cmode->eBands[effEnd];idownsample; + } + if (len<0) { + RESTORE_STACK; + return CELT_BAD_ARG; + } + + if (dec == NULL) + { + ec_dec_init(&_dec,(unsigned char*)data,len); + dec = &_dec; + } + + if (Cmode->nbEBands;i++) + oldBandE[i]=MAX16(oldBandE[i],oldBandE[st->mode->nbEBands+i]); + } + + total_bits = len*8; + tell = ec_tell(dec); + + if (tell==1) + silence = ec_dec_bit_logp(dec, 15); + else + silence = 0; + if (silence) + { + /* Pretend we've read all the remaining bits */ + tell = len*8; + dec->nbits_total+=tell-ec_tell(dec); + } + + postfilter_gain = 0; + postfilter_pitch = 0; + postfilter_tapset = 0; + if (st->start==0 && tell+16 <= total_bits) + { + if(ec_dec_bit_logp(dec, 1)) + { +#ifdef ENABLE_POSTFILTER + int qg, octave; + octave = ec_dec_uint(dec, 6); + postfilter_pitch = (16< 0 && tell+3 <= total_bits) + { + isTransient = ec_dec_bit_logp(dec, 3); + tell = ec_tell(dec); + } + else + isTransient = 0; + + if (isTransient) + shortBlocks = M; + else + shortBlocks = 0; + + /* Decode the global flags (first symbols in the stream) */ + intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0; + /* Get band energies */ + unquant_coarse_energy(st->mode, st->start, st->end, oldBandE, + intra_ener, dec, C, LM); + + ALLOC(tf_res, st->mode->nbEBands, int); + tf_decode(st->start, st->end, isTransient, tf_res, LM, dec); + + tell = ec_tell(dec); + spread_decision = SPREAD_NORMAL; + if (tell+4 <= total_bits) + spread_decision = ec_dec_icdf(dec, spread_icdf, 5); + + ALLOC(pulses, st->mode->nbEBands, int); + ALLOC(cap, st->mode->nbEBands, int); + ALLOC(offsets, st->mode->nbEBands, int); + ALLOC(fine_priority, st->mode->nbEBands, int); + + init_caps(st->mode,cap,LM,C); + + dynalloc_logp = 6; + total_bits<<=BITRES; + tell = ec_tell_frac(dec); + for (i=st->start;iend;i++) + { + int width, quanta; + int dynalloc_loop_logp; + int boost; + width = C*(st->mode->eBands[i+1]-st->mode->eBands[i])<0) + dynalloc_logp = IMAX(2, dynalloc_logp-1); + } + + ALLOC(fine_quant, st->mode->nbEBands, int); + alloc_trim = tell+(6<=2&&bits>=(LM+2<mode, st->start, st->end, offsets, cap, + alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, dec, 0, 0); + + unquant_fine_energy(st->mode, st->start, st->end, oldBandE, fine_quant, dec, C); + + /* Decode fixed codebook */ + ALLOC(collapse_masks, C*st->mode->nbEBands, unsigned char); + quant_all_bands(0, st->mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks, + NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res, 1, + len*(8<rng); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = ec_dec_bits(dec, 1); + } + + unquant_energy_finalise(st->mode, st->start, st->end, oldBandE, + fine_quant, fine_priority, len*8-ec_tell(dec), dec, C); + + if (anti_collapse_on) + anti_collapse(st->mode, X, collapse_masks, LM, C, C, N, + st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng); + + log2Amp(st->mode, st->start, st->end, bandE, oldBandE, C); + + if (silence) + { + for (i=0;imode->nbEBands;i++) + { + bandE[i] = 0; + oldBandE[i] = -QCONST16(28.f,DB_SHIFT); + } + } + /* Synthesis */ + denormalise_bands(st->mode, X, freq, bandE, effEnd, C, M); + + CELT_MOVE(decode_mem[0], decode_mem[0]+N, DECODE_BUFFER_SIZE-N); + if (CC==2) + CELT_MOVE(decode_mem[1], decode_mem[1]+N, DECODE_BUFFER_SIZE-N); + + c=0; do + for (i=0;imode->eBands[st->start];i++) + freq[c*N+i] = 0; + while (++cmode->eBands[effEnd]; + if (st->downsample!=1) + bound = IMIN(bound, N/st->downsample); + for (i=bound;imode, shortBlocks, freq, out_syn, overlap_mem, CC, LM); + +#ifdef ENABLE_POSTFILTER + c=0; do { + st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD); + st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, st->mode->shortMdctSize, + st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset, + st->mode->window, st->overlap); + if (LM!=0) + comb_filter(out_syn[c]+st->mode->shortMdctSize, out_syn[c]+st->mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-st->mode->shortMdctSize, + st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset, + st->mode->window, st->mode->overlap); + + } while (++cpostfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + st->postfilter_period = postfilter_pitch; + st->postfilter_gain = postfilter_gain; + st->postfilter_tapset = postfilter_tapset; + if (LM!=0) + { + st->postfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + } +#endif /* ENABLE_POSTFILTER */ + + if (C==1) { + for (i=0;imode->nbEBands;i++) + oldBandE[st->mode->nbEBands+i]=oldBandE[i]; + } + + /* In case start or end were to change */ + c=0; do + { + for (i=0;istart;i++) + oldBandE[c*st->mode->nbEBands+i]=0; + for (i=st->end;imode->nbEBands;i++) + oldBandE[c*st->mode->nbEBands+i]=0; + } while (++c<2); + if (!isTransient) + { + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE2[i] = oldLogE[i]; + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i] = oldBandE[i]; + for (i=0;i<2*st->mode->nbEBands;i++) + backgroundLogE[i] = MIN16(backgroundLogE[i] + M*QCONST16(0.001f,DB_SHIFT), oldBandE[i]); + } else { + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + st->rng = dec->rng; + + deemphasis(out_syn, pcm, N, CC, st->downsample, st->mode->preemph, st->preemph_memD); + st->loss_count = 0; + RESTORE_STACK; + if (ec_tell(dec) > 8*len) + return CELT_INTERNAL_ERROR; + if(ec_get_error(dec)) + st->error = 1; + return frame_size/st->downsample; +} + +#ifdef FIXED_POINT +#ifndef DISABLE_FLOAT_API +CELT_STATIC +int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size, ec_dec *dec) +{ + int j, ret, C, N; + VARDECL(celt_int16, out); + ALLOC_STACK; + + if (pcm==NULL) + return CELT_BAD_ARG; + + C = CHANNELS(st->channels); + N = frame_size; + + ALLOC(out, C*N, celt_int16); + ret=celt_decode_with_ec(st, data, len, out, frame_size, dec); + if (ret>0) + for (j=0;jchannels); + N = frame_size; + ALLOC(out, C*N, celt_sig); + + ret=celt_decode_with_ec_float(st, data, len, out, frame_size, dec); + + if (ret>0) + for (j=0;j=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case CELT_GET_AND_CLEAR_ERROR_REQUEST: + { + int *value = va_arg(ap, int*); + if (value==NULL) + goto bad_arg; + *value=st->error; + st->error = 0; + } + break; + case CELT_GET_LOOKAHEAD_REQUEST: + { + int *value = va_arg(ap, int*); + if (value==NULL) + goto bad_arg; + *value = st->overlap/st->downsample; + } + break; + case CELT_RESET_STATE: + { + CELT_MEMSET((char*)&st->DECODER_RESET_START, 0, + celt_decoder_get_size_custom(st->mode, st->channels)- + ((char*)&st->DECODER_RESET_START - (char*)st)); + } + break; +#ifdef OPUS_BUILD + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case CELT_SET_SIGNALLING_REQUEST: + { + celt_int32 value = va_arg(ap, celt_int32); + st->signalling = value; + } + break; +#endif + default: + goto bad_request; + } + va_end(ap); + return CELT_OK; +bad_arg: + va_end(ap); + return CELT_BAD_ARG; +bad_request: + va_end(ap); + return CELT_UNIMPLEMENTED; +} + +const char *celt_strerror(int error) +{ + static const char *error_strings[8] = { + "success", + "invalid argument", + "buffer too small", + "internal error", + "corrupted stream", + "request not implemented", + "invalid state", + "memory allocation failed" + }; + if (error > 0 || error < -7) + return "unknown error"; + else + return error_strings[-error]; +} + diff --git a/native/codec/libraries/celt/libcelt/celt.h b/native/codec/libraries/celt/libcelt/celt.h new file mode 100644 index 0000000..2bbf506 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/celt.h @@ -0,0 +1,325 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CELT_H +#define CELT_H + +#include "celt_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && defined(CELT_BUILD) +#define EXPORT __attribute__ ((visibility ("default"))) +#elif defined(WIN32) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +#define _celt_check_int(x) (((void)((x) == (celt_int32)0)), (celt_int32)(x)) +#define _celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr))) +#define _celt_check_int_ptr(ptr) ((ptr) + ((ptr) - (int*)(ptr))) + +/* Error codes */ +/** No error */ +#define CELT_OK 0 +/** An (or more) invalid argument (e.g. out of range) */ +#define CELT_BAD_ARG -1 +/** The mode struct passed is invalid */ +#define CELT_BUFFER_TOO_SMALL -2 +/** An internal error was detected */ +#define CELT_INTERNAL_ERROR -3 +/** The data passed (e.g. compressed data to decoder) is corrupted */ +#define CELT_CORRUPTED_DATA -4 +/** Invalid/unsupported request number */ +#define CELT_UNIMPLEMENTED -5 +/** An encoder or decoder structure is invalid or already freed */ +#define CELT_INVALID_STATE -6 +/** Memory allocation has failed */ +#define CELT_ALLOC_FAIL -7 + + +/* Encoder/decoder Requests */ + +#define CELT_SET_COMPLEXITY_REQUEST 2 +/** Controls the complexity from 0-10 (int) */ +#define CELT_SET_COMPLEXITY(x) CELT_SET_COMPLEXITY_REQUEST, _celt_check_int(x) + +#define CELT_SET_PREDICTION_REQUEST 4 +/** Controls the use of interframe prediction. + 0=Independent frames + 1=Short term interframe prediction allowed + 2=Long term prediction allowed + */ +#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, _celt_check_int(x) + +#define CELT_SET_BITRATE_REQUEST 6 +/** Set the target VBR rate in bits per second(int); 0=CBR (default) */ +#define CELT_SET_BITRATE(x) CELT_SET_BITRATE_REQUEST, _celt_check_int(x) + +#define CELT_RESET_STATE_REQUEST 8 +/** Reset the encoder/decoder memories to zero*/ +#define CELT_RESET_STATE CELT_RESET_STATE_REQUEST + +#define CELT_SET_VBR_CONSTRAINT_REQUEST 10 +#define CELT_SET_VBR_CONSTRAINT(x) CELT_SET_VBR_CONSTRAINT_REQUEST, _celt_check_int(x) + +#define CELT_SET_VBR_REQUEST 12 +#define CELT_SET_VBR(x) CELT_SET_VBR_REQUEST, _celt_check_int(x) + +#define CELT_SET_INPUT_CLIPPING_REQUEST 14 +#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, _celt_check_int(x) + +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 15 +#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, _celt_check_int_ptr(x) + +#define CELT_GET_LOOKAHEAD_REQUEST 17 +#define CELT_GET_LOOKAHEAD(x) CELT_GET_LOOKAHEAD_REQUEST, _celt_check_int_ptr(x) + +#define CELT_SET_CHANNELS_REQUEST 18 +#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, _celt_check_int(x) + +#define CELT_SET_LOSS_PERC_REQUEST 20 +#define CELT_SET_LOSS_PERC(x) CELT_SET_LOSS_PERC_REQUEST, _celt_check_int(x) + +/* Internal */ +#define CELT_SET_START_BAND_REQUEST 10000 +#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, _celt_check_int(x) + +#define CELT_SET_END_BAND_REQUEST 10001 +#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, _celt_check_int(x) + + + +/** Contains the state of an encoder. One encoder state is needed + for each stream. It is initialised once at the beginning of the + stream. Do *not* re-initialise the state for every frame. + @brief Encoder state + */ +typedef struct CELTEncoder CELTEncoder; + +/** State of the decoder. One decoder state is needed for each stream. + It is initialised once at the beginning of the stream. Do *not* + re-initialise the state for every frame */ +typedef struct CELTDecoder CELTDecoder; + +/** The mode contains all the information necessary to create an + encoder. Both the encoder and decoder need to be initialised + with exactly the same mode, otherwise the quality will be very + bad */ +typedef struct CELTMode CELTMode; + + +/** \defgroup codec Encoding and decoding */ +/* @{ */ + +/* Mode calls */ + +/** Creates a new mode struct. This will be passed to an encoder or + decoder. The mode MUST NOT BE DESTROYED until the encoders and + decoders that use it are destroyed as well. + @param Fs Sampling rate (32000 to 96000 Hz) + @param frame_size Number of samples (per channel) to encode in each + packet (even values; 64 - 512) + @param error Returned error code (if NULL, no error will be returned) + @return A newly created mode +*/ +EXPORT CELTMode *celt_mode_create(celt_int32 Fs, int frame_size, int *error); + +/** Destroys a mode struct. Only call this after all encoders and + decoders using this mode are destroyed as well. + @param mode Mode to be destroyed +*/ +EXPORT void celt_mode_destroy(CELTMode *mode); + +/* Encoder stuff */ + +EXPORT int celt_encoder_get_size(int channels); + +EXPORT int celt_encoder_get_size_custom(const CELTMode *mode, int channels); + +/** Creates a new encoder state. Each stream needs its own encoder + state (can't be shared across simultaneous streams). + @param channels Number of channels + @param error Returns an error code + @return Newly created encoder state. +*/ +EXPORT CELTEncoder *celt_encoder_create(int sampling_rate, int channels, int *error); + +/** Creates a new encoder state. Each stream needs its own encoder + state (can't be shared across simultaneous streams). + @param mode Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + @param channels Number of channels + @param error Returns an error code + @return Newly created encoder state. +*/ +EXPORT CELTEncoder *celt_encoder_create_custom(const CELTMode *mode, int channels, int *error); + +EXPORT CELTEncoder *celt_encoder_init(CELTEncoder *st, int sampling_rate, int channels, int *error); + +EXPORT CELTEncoder *celt_encoder_init_custom(CELTEncoder *st, const CELTMode *mode, int channels, int *error); + +/** Destroys a an encoder state. + @param st Encoder state to be destroyed + */ +EXPORT void celt_encoder_destroy(CELTEncoder *st); + +/** Encodes a frame of audio. + @param st Encoder state + @param pcm PCM audio in float format, with a normal range of ±1.0. + * Samples with a range beyond ±1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynmaic range. There must be exactly + * frame_size samples per channel. + @param compressed The compressed data is written here. This may not alias pcm or + * optional_synthesis. + @param nbCompressedBytes Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + @return Number of bytes written to "compressed". Will be the same as + * "nbCompressedBytes" unless the stream is VBR and will never be larger. + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. +*/ +EXPORT int celt_encode_float(CELTEncoder *st, const float *pcm, int frame_size, unsigned char *compressed, int maxCompressedBytes); + +/** Encodes a frame of audio. + @param st Encoder state + @param pcm PCM audio in signed 16-bit format (native endian). There must be + * exactly frame_size samples per channel. + @param compressed The compressed data is written here. This may not alias pcm or + * optional_synthesis. + @param nbCompressedBytes Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + @return Number of bytes written to "compressed". Will be the same as + * "nbCompressedBytes" unless the stream is VBR and will never be larger. + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +EXPORT int celt_encode(CELTEncoder *st, const celt_int16 *pcm, int frame_size, unsigned char *compressed, int maxCompressedBytes); + +/** Query and set encoder parameters + @param st Encoder state + @param request Parameter to change or query + @param value Pointer to a 32-bit int value + @return Error code +*/ +EXPORT int celt_encoder_ctl(CELTEncoder * st, int request, ...); + +/* Decoder stuff */ + +EXPORT int celt_decoder_get_size(int channels); + +EXPORT int celt_decoder_get_size_custom(const CELTMode *mode, int channels); + +/** Creates a new decoder state. Each stream needs its own decoder state (can't + be shared across simultaneous streams). + @param mode Contains all the information about the characteristics of the + stream (must be the same characteristics as used for the encoder) + @param channels Number of channels + @param error Returns an error code + @return Newly created decoder state. + */ +EXPORT CELTDecoder *celt_decoder_create(int sampling_rate, int channels, int *error); + +/** Creates a new decoder state. Each stream needs its own decoder state (can't + be shared across simultaneous streams). + @param mode Contains all the information about the characteristics of the + stream (must be the same characteristics as used for the encoder) + @param channels Number of channels + @param error Returns an error code + @return Newly created decoder state. + */ +EXPORT CELTDecoder *celt_decoder_create_custom(const CELTMode *mode, int channels, int *error); + +EXPORT CELTDecoder *celt_decoder_init(CELTDecoder *st, int sampling_rate, int channels, int *error); + +EXPORT CELTDecoder *celt_decoder_init_custom(CELTDecoder *st, const CELTMode *mode, int channels, int *error); + +/** Destroys a a decoder state. + @param st Decoder state to be destroyed + */ +EXPORT void celt_decoder_destroy(CELTDecoder *st); + +/** Decodes a frame of audio. + @param st Decoder state + @param data Compressed data produced by an encoder + @param len Number of bytes to read from "data". This MUST be exactly the number + of bytes returned by the encoder. Using a larger value WILL NOT WORK. + @param pcm One frame (frame_size samples per channel) of decoded PCM will be + returned here in float format. + @return Error code. + */ +EXPORT int celt_decode_float(CELTDecoder *st, const unsigned char *data, int len, float *pcm, int frame_size); + +/** Decodes a frame of audio. + @param st Decoder state + @param data Compressed data produced by an encoder + @param len Number of bytes to read from "data". This MUST be exactly the number + of bytes returned by the encoder. Using a larger value WILL NOT WORK. + @param pcm One frame (frame_size samples per channel) of decoded PCM will be + returned here in 16-bit PCM format (native endian). + @return Error code. + */ +EXPORT int celt_decode(CELTDecoder *st, const unsigned char *data, int len, celt_int16 *pcm, int frame_size); + +/** Query and set decoder parameters + @param st Decoder state + @param request Parameter to change or query + @param value Pointer to a 32-bit int value + @return Error code + */ +EXPORT int celt_decoder_ctl(CELTDecoder * st, int request, ...); + + +/** Returns the English string that corresponds to an error code + * @param error Error code (negative for an error, 0 for success + * @return Constant string (must NOT be freed) + */ +EXPORT const char *celt_strerror(int error); + +/* @} */ + + +#ifdef __cplusplus +} +#endif + +#endif /*CELT_H */ diff --git a/native/codec/libraries/celt/libcelt/celt_header.h b/native/codec/libraries/celt/libcelt/celt_header.h new file mode 100644 index 0000000..3777484 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/celt_header.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CELT_HEADER_H +#define CELT_HEADER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "celt.h" +#include "celt_types.h" + +/** Header data to be used for Ogg files (or possibly other encapsulation) + @brief Header data + */ +typedef struct { + char codec_id[8]; /**< MUST be "CELT " (four spaces) */ + char codec_version[20]; /**< Version used (as string) */ + celt_int32 version_id; /**< Version id (negative for until stream is frozen) */ + celt_int32 header_size; /**< Size of this header */ + celt_int32 sample_rate; /**< Sampling rate of the original audio */ + celt_int32 nb_channels; /**< Number of channels */ + celt_int32 frame_size; /**< Samples per frame (per channel) */ + celt_int32 overlap; /**< Overlapping samples (per channel) */ + celt_int32 bytes_per_packet; /**< Number of bytes per compressed packet (0 if unknown) */ + celt_int32 extra_headers; /**< Number of additional headers that follow this header */ +} CELTHeader; + +/** Creates a basic header struct */ +EXPORT int celt_header_init(CELTHeader *header, const CELTMode *m, int frame_size, int channels); + +EXPORT int celt_header_to_packet(const CELTHeader *header, unsigned char *packet, celt_uint32 size); + +EXPORT int celt_header_from_packet(const unsigned char *packet, celt_uint32 size, CELTHeader *header); + +#ifdef __cplusplus +} +#endif + +#endif /* CELT_HEADER_H */ diff --git a/native/codec/libraries/celt/libcelt/celt_types.h b/native/codec/libraries/celt/libcelt/celt_types.h new file mode 100644 index 0000000..bfd498a --- /dev/null +++ b/native/codec/libraries/celt/libcelt/celt_types.h @@ -0,0 +1,151 @@ +/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ +/* Modified by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* celt_types.h taken from libogg */ + +/** + @file celt_types.h + @brief CELT types +*/ +#ifndef _CELT_TYPES_H +#define _CELT_TYPES_H + +/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ +#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) +#include + + typedef int16_t celt_int16; + typedef uint16_t celt_uint16; + typedef int32_t celt_int32; + typedef uint32_t celt_uint32; +#elif defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t celt_int32; + typedef _G_uint32_t celt_uint32; + typedef _G_int16 celt_int16; + typedef _G_uint16 celt_uint16; +# elif defined(__MINGW32__) + typedef short celt_int16; + typedef unsigned short celt_uint16; + typedef int celt_int32; + typedef unsigned int celt_uint32; +# elif defined(__MWERKS__) + typedef int celt_int32; + typedef unsigned int celt_uint32; + typedef short celt_int16; + typedef unsigned short celt_uint16; +# else + /* MSVC/Borland */ + typedef __int32 celt_int32; + typedef unsigned __int32 celt_uint32; + typedef __int16 celt_int16; + typedef unsigned __int16 celt_uint16; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 celt_int16; + typedef UInt16 celt_uint16; + typedef SInt32 celt_int32; + typedef UInt32 celt_uint32; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t celt_int16; + typedef u_int16_t celt_uint16; + typedef int32_t celt_int32; + typedef u_int32_t celt_uint32; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16 celt_int16; + typedef u_int16 celt_uint16; + typedef int32_t celt_int32; + typedef u_int32_t celt_uint32; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short celt_int16; + typedef unsigned short celt_uint16; + typedef int celt_int32; + typedef unsigned int celt_uint32; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short celt_int16; + typedef unsigned short celt_uint16; + typedef int celt_int32; + typedef unsigned int celt_uint32; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int celt_int32; + typedef unsigned celt_uint32; + typedef short celt_int16; + typedef unsigned short celt_uint16; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short celt_int16; + typedef unsigned short celt_uint16; + typedef signed int celt_int32; + typedef unsigned int celt_uint32; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short celt_int16; + typedef unsigned short celt_uint16; + typedef long celt_int32; + typedef unsigned long celt_uint32; + +#elif defined(CONFIG_TI_C6X) + + typedef short celt_int16; + typedef unsigned short celt_uint16; + typedef int celt_int32; + typedef unsigned int celt_uint32; + +#else + + /* Give up, take a reasonable guess */ + typedef short celt_int16; + typedef unsigned short celt_uint16; + typedef int celt_int32; + typedef unsigned int celt_uint32; + +#endif + +#endif /* _CELT_TYPES_H */ diff --git a/native/codec/libraries/celt/libcelt/cwrs.c b/native/codec/libraries/celt/libcelt/cwrs.c new file mode 100644 index 0000000..21d278f --- /dev/null +++ b/native/codec/libraries/celt/libcelt/cwrs.c @@ -0,0 +1,736 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include +#include +#include "cwrs.h" +#include "mathops.h" +#include "arch.h" + +/*Guaranteed to return a conservatively large estimate of the binary logarithm + with frac bits of fractional precision. + Tested for all possible 32-bit inputs with frac=4, where the maximum + overestimation is 0.06254243 bits.*/ +int log2_frac(celt_uint32 val, int frac) +{ + int l; + l=EC_ILOG(val); + if(val&val-1){ + /*This is (val>>l-16), but guaranteed to round up, even if adding a bias + before the shift would cause overflow (e.g., for 0xFFFFxxxx).*/ + if(l>16)val=(val>>l-16)+((val&(1<>l-16); + else val<<=16-l; + l=l-1<>16); + l+=b<>b; + val=val*val+0x7FFF>>15; + } + while(frac-->0); + /*If val is not exactly 0x8000, then we have to round up the remainder.*/ + return l+(val>0x8000); + } + /*Exact powers of two require no rounding.*/ + else return l-1<0); + shift=EC_ILOG(_d^_d-1); + celt_assert(_d<=256); + inv=INV_TABLE[_d-1>>shift]; + shift--; + one=1<>shift)-(_c>>shift)+ + (_a*(_b&mask)+one-(_c&mask)>>shift)-1)*inv&MASK32; +} + +#endif /* SMALL_FOOTPRINT */ + +/*Although derived separately, the pulse vector coding scheme is equivalent to + a Pyramid Vector Quantizer \cite{Fis86}. + Some additional notes about an early version appear at + http://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering + and the definitions of some terms have evolved since that was written. + + The conversion from a pulse vector to an integer index (encoding) and back + (decoding) is governed by two related functions, V(N,K) and U(N,K). + + V(N,K) = the number of combinations, with replacement, of N items, taken K + at a time, when a sign bit is added to each item taken at least once (i.e., + the number of N-dimensional unit pulse vectors with K pulses). + One way to compute this is via + V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1, + where choose() is the binomial function. + A table of values for N<10 and K<10 looks like: + V[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, + {1, 4, 8, 12, 16, 20, 24, 28, 32, 36}, + {1, 6, 18, 38, 66, 102, 146, 198, 258, 326}, + {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992}, + {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290}, + {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436}, + {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598}, + {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688}, + {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146} + }; + + U(N,K) = the number of such combinations wherein N-1 objects are taken at + most K-1 at a time. + This is given by + U(N,K) = sum(k=0...K-1,V(N-1,k)) + = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0. + The latter expression also makes clear that U(N,K) is half the number of such + combinations wherein the first object is taken at least once. + Although it may not be clear from either of these definitions, U(N,K) is the + natural function to work with when enumerating the pulse vector codebooks, + not V(N,K). + U(N,K) is not well-defined for N=0, but with the extension + U(0,K) = K>0 ? 0 : 1, + the function becomes symmetric: U(N,K) = U(K,N), with a similar table: + U[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 1, 3, 5, 7, 9, 11, 13, 15, 17}, + {0, 1, 5, 13, 25, 41, 61, 85, 113, 145}, + {0, 1, 7, 25, 63, 129, 231, 377, 575, 833}, + {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649}, + {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073}, + {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081}, + {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545}, + {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729} + }; + + With this extension, V(N,K) may be written in terms of U(N,K): + V(N,K) = U(N,K) + U(N,K+1) + for all N>=0, K>=0. + Thus U(N,K+1) represents the number of combinations where the first element + is positive or zero, and U(N,K) represents the number of combinations where + it is negative. + With a large enough table of U(N,K) values, we could write O(N) encoding + and O(min(N*log(K),N+K)) decoding routines, but such a table would be + prohibitively large for small embedded devices (K may be as large as 32767 + for small N, and N may be as large as 200). + + Both functions obey the same recurrence relation: + V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), + U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1), + for all N>0, K>0, with different initial conditions at N=0 or K=0. + This allows us to construct a row of one of the tables above given the + previous row or the next row. + Thus we can derive O(NK) encoding and decoding routines with O(K) memory + using only addition and subtraction. + + When encoding, we build up from the U(2,K) row and work our way forwards. + When decoding, we need to start at the U(N,K) row and work our way backwards, + which requires a means of computing U(N,K). + U(N,K) may be computed from two previous values with the same N: + U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2) + for all N>1, and since U(N,K) is symmetric, a similar relation holds for two + previous values with the same K: + U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K) + for all K>1. + This allows us to construct an arbitrary row of the U(N,K) table by starting + with the first two values, which are constants. + This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K) + multiplications. + Similar relations can be derived for V(N,K), but are not used here. + + For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree + polynomial for fixed N. + The first few are + U(1,K) = 1, + U(2,K) = 2*K-1, + U(3,K) = (2*K-2)*K+1, + U(4,K) = (((4*K-6)*K+8)*K-3)/3, + U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3, + and + V(1,K) = 2, + V(2,K) = 4*K, + V(3,K) = 4*K*K+2, + V(4,K) = 8*(K*K+2)*K/3, + V(5,K) = ((4*K*K+20)*K*K+6)/3, + for all K>0. + This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for + small N (and indeed decoding is also O(N) for N<3). + + @ARTICLE{Fis86, + author="Thomas R. Fischer", + title="A Pyramid Vector Quantizer", + journal="IEEE Transactions on Information Theory", + volume="IT-32", + number=4, + pages="568--583", + month=Jul, + year=1986 + }*/ + +#ifndef SMALL_FOOTPRINT + +/*Compute U(1,_k).*/ +static inline unsigned ucwrs1(int _k){ + return _k?1:0; +} + +/*Compute V(1,_k).*/ +static inline unsigned ncwrs1(int _k){ + return _k?2:1; +} + +/*Compute U(2,_k). + Note that this may be called with _k=32768 (maxK[2]+1).*/ +static inline unsigned ucwrs2(unsigned _k){ + return _k?_k+(_k-1):0; +} + +/*Compute V(2,_k).*/ +static inline celt_uint32 ncwrs2(int _k){ + return _k?4*(celt_uint32)_k:1; +} + +/*Compute U(3,_k). + Note that this may be called with _k=32768 (maxK[3]+1).*/ +static inline celt_uint32 ucwrs3(unsigned _k){ + return _k?(2*(celt_uint32)_k-2)*_k+1:0; +} + +/*Compute V(3,_k).*/ +static inline celt_uint32 ncwrs3(int _k){ + return _k?2*(2*(unsigned)_k*(celt_uint32)_k+1):1; +} + +/*Compute U(4,_k).*/ +static inline celt_uint32 ucwrs4(int _k){ + return _k?imusdiv32odd(2*_k,(2*_k-3)*(celt_uint32)_k+4,3,1):0; +} + +/*Compute V(4,_k).*/ +static inline celt_uint32 ncwrs4(int _k){ + return _k?((_k*(celt_uint32)_k+2)*_k)/3<<3:1; +} + +/*Compute U(5,_k).*/ +static inline celt_uint32 ucwrs5(int _k){ + return _k?(((((_k-2)*(unsigned)_k+5)*(celt_uint32)_k-4)*_k)/3<<1)+1:0; +} + +/*Compute V(5,_k).*/ +static inline celt_uint32 ncwrs5(int _k){ + return _k?(((_k*(unsigned)_k+5)*(celt_uint32)_k*_k)/3<<2)+2:1; +} + +#endif /* SMALL_FOOTPRINT */ + +/*Computes the next row/column of any recurrence that obeys the relation + u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static inline void unext(celt_uint32 *_ui,unsigned _len,celt_uint32 _ui0){ + celt_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_len); + _ui[j-1]=_ui0; +} + +/*Computes the previous row/column of any recurrence that obeys the relation + u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static inline void uprev(celt_uint32 *_ui,unsigned _n,celt_uint32 _ui0){ + celt_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_n); + _ui[j-1]=_ui0; +} + +/*Compute V(_n,_k), as well as U(_n,0..._k+1). + _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/ +static celt_uint32 ncwrs_urow(unsigned _n,unsigned _k,celt_uint32 *_u){ + celt_uint32 um2; + unsigned len; + unsigned k; + len=_k+2; + /*We require storage at least 3 values (e.g., _k>0).*/ + celt_assert(len>=3); + _u[0]=0; + _u[1]=um2=1; +#ifndef SMALL_FOOTPRINT + if(_n<=6 || _k>255) +#endif + { + /*If _n==0, _u[0] should be 1 and the rest should be 0.*/ + /*If _n==1, _u[i] should be 1 for i>1.*/ + celt_assert(_n>=2); + /*If _k==0, the following do-while loop will overflow the buffer.*/ + celt_assert(_k>0); + k=2; + do _u[k]=(k<<1)-1; + while(++k=len)break; + _u[k]=um1=imusdiv32odd(n2m1,um2,um1,k-1>>1)+um1; + } + } +#endif /* SMALL_FOOTPRINT */ + return _u[_k]+_u[_k+1]; +} + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 1 with associated sign bits. + _y: Returns the vector of pulses.*/ +static inline void cwrsi1(int _k,celt_uint32 _i,int *_y){ + int s; + s=-(int)_i; + _y[0]=_k+s^s; +} + +#ifndef SMALL_FOOTPRINT + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 2 with associated sign bits. + _y: Returns the vector of pulses.*/ +static inline void cwrsi2(int _k,celt_uint32 _i,int *_y){ + celt_uint32 p; + int s; + int yj; + p=ucwrs2(_k+1U); + s=-(_i>=p); + _i-=p&s; + yj=_k; + _k=_i+1>>1; + p=ucwrs2(_k); + _i-=p; + yj-=_k; + _y[0]=yj+s^s; + cwrsi1(_k,_i,_y+1); +} + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 3 with associated sign bits. + _y: Returns the vector of pulses.*/ +static void cwrsi3(int _k,celt_uint32 _i,int *_y){ + celt_uint32 p; + int s; + int yj; + p=ucwrs3(_k+1U); + s=-(_i>=p); + _i-=p&s; + yj=_k; + /*Finds the maximum _k such that ucwrs3(_k)<=_i (tested for all + _i<2147418113=U(3,32768)).*/ + _k=_i>0?isqrt32(2*_i-1)+1>>1:0; + p=ucwrs3(_k); + _i-=p; + yj-=_k; + _y[0]=yj+s^s; + cwrsi2(_k,_i,_y+1); +} + +/*Returns the _i'th combination of _k elements (at most 1172) chosen from a set + of size 4 with associated sign bits. + _y: Returns the vector of pulses.*/ +static void cwrsi4(int _k,celt_uint32 _i,int *_y){ + celt_uint32 p; + int s; + int yj; + int kl; + int kr; + p=ucwrs4(_k+1); + s=-(_i>=p); + _i-=p&s; + yj=_k; + /*We could solve a cubic for k here, but the form of the direct solution does + not lend itself well to exact integer arithmetic. + Instead we do a binary search on U(4,K).*/ + kl=0; + kr=_k; + for(;;){ + _k=kl+kr>>1; + p=ucwrs4(_k); + if(p<_i){ + if(_k>=kr)break; + kl=_k+1; + } + else if(p>_i)kr=_k-1; + else break; + } + _i-=p; + yj-=_k; + _y[0]=yj+s^s; + cwrsi3(_k,_i,_y+1); +} + +/*Returns the _i'th combination of _k elements (at most 238) chosen from a set + of size 5 with associated sign bits. + _y: Returns the vector of pulses.*/ +static void cwrsi5(int _k,celt_uint32 _i,int *_y){ + celt_uint32 p; + int s; + int yj; + p=ucwrs5(_k+1); + s=-(_i>=p); + _i-=p&s; + yj=_k; + /* A binary search on U(5,K) avoids the need for 64-bit arithmetic */ + { + int kl=0; + int kr=_k; + for(;;){ + _k=kl+kr>>1; + p=ucwrs5(_k); + if(p<_i){ + if(_k>=kr)break; + kl=_k+1; + } + else if(p>_i)kr=_k-1; + else break; + } + } + _i-=p; + yj-=_k; + _y[0]=yj+s^s; + cwrsi4(_k,_i,_y+1); +} +#endif /* SMALL_FOOTPRINT */ + +/*Returns the _i'th combination of _k elements chosen from a set of size _n + with associated sign bits. + _y: Returns the vector of pulses. + _u: Must contain entries [0..._k+1] of row _n of U() on input. + Its contents will be destructively modified.*/ +static void cwrsi(int _n,int _k,celt_uint32 _i,int *_y,celt_uint32 *_u){ + int j; + celt_assert(_n>0); + j=0; + do{ + celt_uint32 p; + int s; + int yj; + p=_u[_k+1]; + s=-(_i>=p); + _i-=p&s; + yj=_k; + p=_u[_k]; + while(p>_i)p=_u[--_k]; + _i-=p; + yj-=_k; + _y[j]=yj+s^s; + uprev(_u,_k+2,0); + } + while(++j<_n); +} + + +/*Returns the index of the given combination of K elements chosen from a set + of size 1 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline celt_uint32 icwrs1(const int *_y,int *_k){ + *_k=abs(_y[0]); + return _y[0]<0; +} + +#ifndef SMALL_FOOTPRINT + +/*Returns the index of the given combination of K elements chosen from a set + of size 2 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline celt_uint32 icwrs2(const int *_y,int *_k){ + celt_uint32 i; + int k; + i=icwrs1(_y+1,&k); + i+=ucwrs2(k); + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs2(k+1U); + *_k=k; + return i; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 3 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline celt_uint32 icwrs3(const int *_y,int *_k){ + celt_uint32 i; + int k; + i=icwrs2(_y+1,&k); + i+=ucwrs3(k); + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs3(k+1U); + *_k=k; + return i; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 4 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline celt_uint32 icwrs4(const int *_y,int *_k){ + celt_uint32 i; + int k; + i=icwrs3(_y+1,&k); + i+=ucwrs4(k); + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs4(k+1); + *_k=k; + return i; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 5 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline celt_uint32 icwrs5(const int *_y,int *_k){ + celt_uint32 i; + int k; + i=icwrs4(_y+1,&k); + i+=ucwrs5(k); + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs5(k+1); + *_k=k; + return i; +} +#endif /* SMALL_FOOTPRINT */ + +/*Returns the index of the given combination of K elements chosen from a set + of size _n with associated sign bits. + _y: The vector of pulses, whose sum of absolute values must be _k. + _nc: Returns V(_n,_k).*/ +celt_uint32 icwrs(int _n,int _k,celt_uint32 *_nc,const int *_y, + celt_uint32 *_u){ + celt_uint32 i; + int j; + int k; + /*We can't unroll the first two iterations of the loop unless _n>=2.*/ + celt_assert(_n>=2); + _u[0]=0; + for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1; + i=icwrs1(_y+_n-1,&k); + j=_n-2; + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + while(j-->0){ + unext(_u,_k+2,0); + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + } + *_nc=_u[k]+_u[k+1]; + return i; +} + +#ifdef CUSTOM_MODES +void get_required_bits(celt_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + if (_n==1) + { + for (k=1;k<=_maxk;k++) + _bits[k] = 1<<_frac; + } + else { + VARDECL(celt_uint32,u); + SAVE_STACK; + ALLOC(u,_maxk+2U,celt_uint32); + ncwrs_urow(_n,_maxk,u); + for(k=1;k<=_maxk;k++) + _bits[k]=log2_frac(u[k]+u[k+1],_frac); + RESTORE_STACK; + } +} +#endif /* CUSTOM_MODES */ + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + celt_uint32 i; + if (_k==0) + return; + switch(_n){ + case 1:{ + i=icwrs1(_y,&_k); + celt_assert(ncwrs1(_k)==2); + ec_enc_bits(_enc,i,1); + }break; +#ifndef SMALL_FOOTPRINT + case 2:{ + i=icwrs2(_y,&_k); + ec_enc_uint(_enc,i,ncwrs2(_k)); + }break; + case 3:{ + i=icwrs3(_y,&_k); + ec_enc_uint(_enc,i,ncwrs3(_k)); + }break; + case 4:{ + i=icwrs4(_y,&_k); + ec_enc_uint(_enc,i,ncwrs4(_k)); + }break; + case 5:{ + i=icwrs5(_y,&_k); + ec_enc_uint(_enc,i,ncwrs5(_k)); + }break; +#endif + default: + { + VARDECL(celt_uint32,u); + celt_uint32 nc; + SAVE_STACK; + ALLOC(u,_k+2U,celt_uint32); + i=icwrs(_n,_k,&nc,_y,u); + ec_enc_uint(_enc,i,nc); + RESTORE_STACK; + }; + } +} + +void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec) +{ + if (_k==0) { + int i; + for (i=0;i<_n;i++) + _y[i] = 0; + return; + } + switch(_n){ + case 1:{ + celt_assert(ncwrs1(_k)==2); + cwrsi1(_k,ec_dec_bits(_dec,1),_y); + }break; +#ifndef SMALL_FOOTPRINT + case 2:cwrsi2(_k,ec_dec_uint(_dec,ncwrs2(_k)),_y);break; + case 3:cwrsi3(_k,ec_dec_uint(_dec,ncwrs3(_k)),_y);break; + case 4:cwrsi4(_k,ec_dec_uint(_dec,ncwrs4(_k)),_y);break; + case 5:cwrsi5(_k,ec_dec_uint(_dec,ncwrs5(_k)),_y);break; +#endif + default: + { + VARDECL(celt_uint32,u); + SAVE_STACK; + ALLOC(u,_k+2U,celt_uint32); + cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u); + RESTORE_STACK; + } + } +} + diff --git a/native/codec/libraries/celt/libcelt/cwrs.h b/native/codec/libraries/celt/libcelt/cwrs.h new file mode 100644 index 0000000..443213f --- /dev/null +++ b/native/codec/libraries/celt/libcelt/cwrs.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CWRS_H +#define CWRS_H + +#include "arch.h" +#include "stack_alloc.h" +#include "entenc.h" +#include "entdec.h" + +int log2_frac(celt_uint32 val, int frac); + +void get_required_bits(celt_int16 *bits, int N, int K, int frac); + +void encode_pulses(const int *_y, int N, int K, ec_enc *enc); + +void decode_pulses(int *_y, int N, int K, ec_dec *dec); + +#endif /* CWRS_H */ diff --git a/native/codec/libraries/celt/libcelt/dump_modes.c b/native/codec/libraries/celt/libcelt/dump_modes.c new file mode 100644 index 0000000..486a10b --- /dev/null +++ b/native/codec/libraries/celt/libcelt/dump_modes.c @@ -0,0 +1,325 @@ +/* Copyright (c) 2008 CSIRO + Copyright (c) 2008-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "modes.h" +#include "celt.h" +#include "rate.h" + +#define INT16 "%d" +#define INT32 "%d" +#define FLOAT "%f" + +#ifdef FIXED_POINT +#define WORD16 INT16 +#define WORD32 INT32 +#else +#define WORD16 FLOAT +#define WORD32 FLOAT +#endif + + +void dump_modes(FILE *file, CELTMode **modes, int nb_modes) +{ + int i, j, k; + fprintf(file, "/* The contents of this file is automatically generated and contains static\n"); + fprintf(file, " definitions for some pre-defined modes */\n"); + fprintf(file, "#include \"modes.h\"\n"); + fprintf(file, "#include \"rate.h\"\n"); + + fprintf(file, "\n"); + + for (i=0;ishortMdctSize*mode->nbShortMdcts; + standard = (mode->Fs == 400*(celt_int32)mode->shortMdctSize); + framerate = mode->Fs/mode->shortMdctSize; + + if (!standard) + { + fprintf(file, "#ifndef DEF_EBANDS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define DEF_EBANDS%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const celt_int16 eBands%d_%d[%d] = {\n", mode->Fs, mdctSize, mode->nbEBands+2); + for (j=0;jnbEBands+2;j++) + fprintf (file, "%d, ", mode->eBands[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#ifndef DEF_WINDOW%d\n", mode->overlap); + fprintf(file, "#define DEF_WINDOW%d\n", mode->overlap); + fprintf (file, "static const celt_word16 window%d[%d] = {\n", mode->overlap, mode->overlap); + for (j=0;joverlap;j++) + fprintf (file, WORD16 ", ", mode->window[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + if (!standard) + { + fprintf(file, "#ifndef DEF_ALLOC_VECTORS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define DEF_ALLOC_VECTORS%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const unsigned char allocVectors%d_%d[%d] = {\n", mode->Fs, mdctSize, mode->nbEBands*mode->nbAllocVectors); + for (j=0;jnbAllocVectors;j++) + { + for (k=0;knbEBands;k++) + fprintf (file, "%2d, ", mode->allocVectors[j*mode->nbEBands+k]); + fprintf (file, "\n"); + } + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#ifndef DEF_LOGN%d\n", framerate); + fprintf(file, "#define DEF_LOGN%d\n", framerate); + fprintf (file, "static const celt_int16 logN%d[%d] = {\n", framerate, mode->nbEBands); + for (j=0;jnbEBands;j++) + fprintf (file, "%d, ", mode->logN[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* Pulse cache */ + fprintf(file, "#ifndef DEF_PULSE_CACHE%d\n", mode->Fs/mdctSize); + fprintf(file, "#define DEF_PULSE_CACHE%d\n", mode->Fs/mdctSize); + fprintf (file, "static const celt_int16 cache_index%d[%d] = {\n", mode->Fs/mdctSize, (mode->maxLM+2)*mode->nbEBands); + for (j=0;jnbEBands*(mode->maxLM+2);j++) + fprintf (file, "%d, ", mode->cache.index[j]); + fprintf (file, "};\n"); + fprintf (file, "static const unsigned char cache_bits%d[%d] = {\n", mode->Fs/mdctSize, mode->cache.size); + for (j=0;jcache.size;j++) + fprintf (file, "%d, ", mode->cache.bits[j]); + fprintf (file, "};\n"); + fprintf (file, "static const unsigned char cache_caps%d[%d] = {\n", mode->Fs/mdctSize, (mode->maxLM+1)*2*mode->nbEBands); + for (j=0;j<(mode->maxLM+1)*2*mode->nbEBands;j++) + fprintf (file, "%d, ", mode->cache.caps[j]); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* FFT twiddles */ + fprintf(file, "#ifndef FFT_TWIDDLES%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define FFT_TWIDDLES%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const kiss_twiddle_cpx fft_twiddles%d_%d[%d] = {\n", + mode->Fs, mdctSize, mode->mdct.kfft[0]->nfft); + for (j=0;jmdct.kfft[0]->nfft;j++) + fprintf (file, "{" WORD16 ", " WORD16 "}, ", mode->mdct.kfft[0]->twiddles[j].r, mode->mdct.kfft[0]->twiddles[j].i); + fprintf (file, "};\n"); + + /* FFT Bitrev tables */ + for (k=0;k<=mode->mdct.maxshift;k++) + { + fprintf(file, "#ifndef FFT_BITREV%d\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "#define FFT_BITREV%d\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "static const celt_int16 fft_bitrev%d[%d] = {\n", + mode->mdct.kfft[k]->nfft, mode->mdct.kfft[k]->nfft); + for (j=0;jmdct.kfft[k]->nfft;j++) + fprintf (file, "%d, ", mode->mdct.kfft[k]->bitrev[j]); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + /* FFT States */ + for (k=0;k<=mode->mdct.maxshift;k++) + { + fprintf(file, "#ifndef FFT_STATE%d_%d_%d\n", mode->Fs, mdctSize, k); + fprintf(file, "#define FFT_STATE%d_%d_%d\n", mode->Fs, mdctSize, k); + fprintf (file, "static const kiss_fft_state fft_state%d_%d_%d = {\n", + mode->Fs, mdctSize, k); + fprintf (file, "%d,\t/* nfft */\n", mode->mdct.kfft[k]->nfft); +#ifndef FIXED_POINT + fprintf (file, "%f,\t/* scale */\n", mode->mdct.kfft[k]->scale); +#endif + fprintf (file, "%d,\t/* shift */\n", mode->mdct.kfft[k]->shift); + fprintf (file, "{"); + for (j=0;j<2*MAXFACTORS;j++) + fprintf (file, "%d, ", mode->mdct.kfft[k]->factors[j]); + fprintf (file, "},\t/* factors */\n"); + fprintf (file, "fft_bitrev%d,\t/* bitrev */\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "fft_twiddles%d_%d,\t/* bitrev */\n", mode->Fs, mdctSize); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* MDCT twiddles */ + fprintf(file, "#ifndef MDCT_TWIDDLES%d\n", mdctSize); + fprintf(file, "#define MDCT_TWIDDLES%d\n", mdctSize); + fprintf (file, "static const celt_word16 mdct_twiddles%d[%d] = {\n", + mdctSize, mode->mdct.n/4+1); + for (j=0;j<=mode->mdct.n/4;j++) + fprintf (file, WORD16 ", ", mode->mdct.trig[j]); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + + /* Print the actual mode data */ + fprintf(file, "static const CELTMode mode%d_%d_%d = {\n", mode->Fs, mdctSize, mode->overlap); + fprintf(file, INT32 ",\t/* Fs */\n", mode->Fs); + fprintf(file, "%d,\t/* overlap */\n", mode->overlap); + fprintf(file, "%d,\t/* nbEBands */\n", mode->nbEBands); + fprintf(file, "%d,\t/* effEBands */\n", mode->effEBands); + fprintf(file, "{"); + for (j=0;j<4;j++) + fprintf(file, WORD16 ", ", mode->preemph[j]); + fprintf(file, "},\t/* preemph */\n"); + if (standard) + fprintf(file, "eband5ms,\t/* eBands */\n"); + else + fprintf(file, "eBands%d_%d,\t/* eBands */\n", mode->Fs, mdctSize); + fprintf(file, "%d,\t/* nbAllocVectors */\n", mode->nbAllocVectors); + if (standard) + fprintf(file, "band_allocation,\t/* allocVectors */\n"); + else + fprintf(file, "allocVectors%d_%d,\t/* allocVectors */\n", mode->Fs, mdctSize); + + fprintf(file, "{%d, %d, {", mode->mdct.n, mode->mdct.maxshift); + for (k=0;k<=mode->mdct.maxshift;k++) + fprintf(file, "&fft_state%d_%d_%d, ", mode->Fs, mdctSize, k); + fprintf (file, "}, mdct_twiddles%d},\t/* mdct */\n", mdctSize); + + fprintf(file, "window%d,\t/* window */\n", mode->overlap); + fprintf(file, "%d,\t/* maxLM */\n", mode->maxLM); + fprintf(file, "%d,\t/* nbShortMdcts */\n", mode->nbShortMdcts); + fprintf(file, "%d,\t/* shortMdctSize */\n", mode->shortMdctSize); + fprintf(file, "logN%d,\t/* logN */\n", framerate); + fprintf(file, "{%d, cache_index%d, cache_bits%d, cache_caps%d},\t/* cache */\n", + mode->cache.size, mode->Fs/mdctSize, mode->Fs/mdctSize, mode->Fs/mdctSize); + fprintf(file, "};\n"); + } + fprintf(file, "\n"); + fprintf(file, "/* List of all the available modes */\n"); + fprintf(file, "#define TOTAL_MODES %d\n", nb_modes); + fprintf(file, "static const CELTMode * const static_mode_list[TOTAL_MODES] = {\n"); + for (i=0;ishortMdctSize*mode->nbShortMdcts; + fprintf(file, "&mode%d_%d_%d,\n", mode->Fs, mdctSize, mode->overlap); + } + fprintf(file, "};\n"); +} + +void dump_header(FILE *file, CELTMode **modes, int nb_modes) +{ + int i; + int channels = 0; + int frame_size = 0; + int overlap = 0; + fprintf (file, "/* This header file is generated automatically*/\n"); + for (i=0;ishortMdctSize*mode->nbShortMdcts; + else if (frame_size != mode->shortMdctSize*mode->nbShortMdcts) + frame_size = -1; + if (overlap==0) + overlap = mode->overlap; + else if (overlap != mode->overlap) + overlap = -1; + } + if (channels>0) + { + fprintf (file, "#define CHANNELS(mode) %d\n", channels); + if (channels==1) + fprintf (file, "#define DISABLE_STEREO\n"); + } + if (frame_size>0) + { + fprintf (file, "#define FRAMESIZE(mode) %d\n", frame_size); + } + if (overlap>0) + { + fprintf (file, "#define OVERLAP(mode) %d\n", overlap); + } +} + +#ifdef FIXED_POINT +#define BASENAME "static_modes_fixed" +#else +#define BASENAME "static_modes_float" +#endif + +int main(int argc, char **argv) +{ + int i, nb; + FILE *file; + CELTMode **m; + if (argc%2 != 1) + { + fprintf (stderr, "must have a multiple of 2 arguments\n"); + return 1; + } + nb = (argc-1)/2; + m = malloc(nb*sizeof(CELTMode*)); + for (i=0;i +#include +#if !defined(_ecintrin_H) +# define _ecintrin_H (1) + +/*Some specific platforms may have optimized intrinsic or inline assembly + versions of these functions which can substantially improve performance. + We define macros for them to allow easy incorporation of these non-ANSI + features.*/ + +/*Note that we do not provide a macro for abs(), because it is provided as a + library function, which we assume is translated into an intrinsic to avoid + the function call overhead and then implemented in the smartest way for the + target platform. + With modern gcc (4.x), this is true: it uses cmov instructions if the + architecture supports it and branchless bit-twiddling if it does not (the + speed difference between the two approaches is not measurable). + Interestingly, the bit-twiddling method was patented in 2000 (US 6,073,150) + by Sun Microsystems, despite prior art dating back to at least 1996: + http://web.archive.org/web/19961201174141/www.x86.org/ftp/articles/pentopt/PENTOPT.TXT + On gcc 3.x, however, our assumption is not true, as abs() is translated to a + conditional jump, which is horrible on deeply piplined architectures (e.g., + all consumer architectures for the past decade or more) when the sign cannot + be reliably predicted.*/ + +/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if + given an appropriate architecture, but the branchless bit-twiddling versions + are just as fast, and do not require any special target architecture. + Earlier gcc versions (3.x) compiled both code to the same assembly + instructions, because of the way they represented ((_b)>(_a)) internally.*/ +#define EC_MAXI(_a,_b) ((_a)-((_a)-(_b)&-((_b)>(_a)))) +#define EC_MINI(_a,_b) ((_a)+((_b)-(_a)&-((_b)<(_a)))) +/*This has a chance of compiling branchless, and is just as fast as the + bit-twiddling method, which is slightly less portable, since it relies on a + sign-extended rightshift, which is not guaranteed by ANSI (but present on + every relevant platform).*/ +#define EC_SIGNI(_a) (((_a)>0)-((_a)<0)) +/*Slightly more portable than relying on a sign-extended right-shift (which is + not guaranteed by ANSI), and just as fast, since gcc (3.x and 4.x both) + compile it into the right-shift anyway.*/ +#define EC_SIGNMASK(_a) (-((_a)<0)) +/*Clamps an integer into the given range. + If _a>_c, then the lower bound _a is respected over the upper bound _c (this + behavior is required to meet our documented API behavior). + _a: The lower bound. + _b: The value to clamp. + _c: The upper boud.*/ +#define EC_CLAMPI(_a,_b,_c) (EC_MAXI(_a,EC_MINI(_b,_c))) + + +/*Count leading zeros. + This macro should only be used for implementing ec_ilog(), if it is defined. + All other code should use EC_ILOG() instead.*/ +#if defined(_MSC_VER) +# include +/*In _DEBUG mode this is not an intrinsic by default.*/ +# pragma intrinsic(_BitScanReverse) + +static __inline int ec_bsr(unsigned long _x){ + unsigned long ret; + _BitScanReverse(&ret,_x); + return (int)ret; +} +# define EC_CLZ0 (1) +# define EC_CLZ(_x) (-ec_bsr(_x)) +#elif defined(ENABLE_TI_DSPLIB) +# include "dsplib.h" +# define EC_CLZ0 (31) +# define EC_CLZ(_x) (_lnorm(_x)) +#elif defined(__GNUC_PREREQ) +# if __GNUC_PREREQ(3,4) +# if INT_MAX>=2147483647 +# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clz(_x)) +# elif LONG_MAX>=2147483647L +# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clzl(_x)) +# endif +# endif +#endif + +#if defined(EC_CLZ) +/*Note that __builtin_clz is not defined when _x==0, according to the gcc + documentation (and that of the BSR instruction that implements it on x86). + The majority of the time we can never pass it zero. + When we need to, it can be special cased.*/ +# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) +#else +int ec_ilog(celt_uint32 _v); + +# define EC_ILOG(_x) (ec_ilog(_x)) +#endif + +#endif diff --git a/native/codec/libraries/celt/libcelt/entcode.c b/native/codec/libraries/celt/libcelt/entcode.c new file mode 100644 index 0000000..0626e51 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/entcode.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "entcode.h" + + + +#if !defined(EC_CLZ) +int ec_ilog(celt_uint32 _v){ + /*On a Pentium M, this branchless version tested as the fastest on + 1,000,000,000 random 32-bit integers, edging out a similar version with + branches, and a 256-entry LUT version.*/ + int ret; + int m; + ret=!!_v; + m=!!(_v&0xFFFF0000)<<4; + _v>>=m; + ret|=m; + m=!!(_v&0xFF00)<<3; + _v>>=m; + ret|=m; + m=!!(_v&0xF0)<<2; + _v>>=m; + ret|=m; + m=!!(_v&0xC)<<1; + _v>>=m; + ret|=m; + ret+=!!(_v&0x2); + return ret; +} +#endif + + +celt_uint32 ec_tell_frac(ec_ctx *_this){ + celt_uint32 nbits; + celt_uint32 r; + int l; + int i; + /*To handle the non-integral number of bits still left in the encoder/decoder + state, we compute the worst-case number of bits of val that must be + encoded to ensure that the value is inside the range for any possible + subsequent bits. + The computation here is independent of val itself (the decoder does not + even track that value), even though the real number of bits used after + ec_enc_done() may be 1 smaller if rng is a power of two and the + corresponding trailing bits of val are all zeros. + If we did try to track that special case, then coding a value with a + probability of 1/(1<nbits_total<rng); + r=_this->rng>>l-16; + for(i=BITRES;i-->0;){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} diff --git a/native/codec/libraries/celt/libcelt/entcode.h b/native/codec/libraries/celt/libcelt/entcode.h new file mode 100644 index 0000000..f24e1c4 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/entcode.h @@ -0,0 +1,128 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "celt_types.h" + +#if !defined(_entcode_H) +# define _entcode_H (1) +# include +# include +# include "ecintrin.h" + + + +/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a + larger type, you can speed up the decoder by using it here.*/ +typedef celt_uint32 ec_window; +typedef struct ec_ctx ec_ctx; +typedef struct ec_ctx ec_enc; +typedef struct ec_ctx ec_dec; + + + +# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT) + +/*The number of bits to use for the range-coded part of unsigned integers.*/ +# define EC_UINT_BITS (8) + +/*The resolution of fractional-precision bit usage measurements, i.e., + 3 => 1/8th bits.*/ +# define BITRES 3 + + + +/*The entropy encoder/decoder context. + We use the same structure for both, so that common functions like ec_tell() + can be used on either one.*/ +struct ec_ctx{ + /*Buffered input/output.*/ + unsigned char *buf; + /*The size of the buffer.*/ + celt_uint32 storage; + /*The offset at which the last byte containing raw bits was read/written.*/ + celt_uint32 end_offs; + /*Bits that will be read from/written at the end.*/ + ec_window end_window; + /*Number of valid bits in end_window.*/ + int nend_bits; + /*The total number of whole bits read/written. + This does not include partial bits currently in the range coder.*/ + int nbits_total; + /*The offset at which the next range coder byte will be read/written.*/ + celt_uint32 offs; + /*The number of values in the current range.*/ + celt_uint32 rng; + /*In the decoder: the difference between the top of the current range and + the input value, minus one. + In the encoder: the low end of the current range.*/ + celt_uint32 val; + /*In the decoder: the saved normalization factor from ec_decode(). + In the encoder: the number of oustanding carry propagating symbols.*/ + celt_uint32 ext; + /*A buffered input/output symbol, awaiting carry propagation.*/ + int rem; + /*Nonzero if an error occurred.*/ + int error; +}; + + +/*Shared functions.*/ +static inline void ec_reset(ec_ctx *_this){ + _this->offs=_this->end_offs=0; +} + +static inline celt_uint32 ec_range_bytes(ec_ctx *_this){ + return _this->offs; +} + +static inline unsigned char *ec_get_buffer(ec_ctx *_this){ + return _this->buf; +} + +static inline int ec_get_error(ec_ctx *_this){ + return _this->error; +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +static inline int ec_tell(ec_ctx *_this){ + return _this->nbits_total-EC_ILOG(_this->rng); +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits scaled by 2**BITRES. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +celt_uint32 ec_tell_frac(ec_ctx *_this); + +#endif diff --git a/native/codec/libraries/celt/libcelt/entdec.c b/native/codec/libraries/celt/libcelt/entdec.c new file mode 100644 index 0000000..8b4d2ee --- /dev/null +++ b/native/codec/libraries/celt/libcelt/entdec.c @@ -0,0 +1,254 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "os_support.h" +#include "arch.h" +#include "entdec.h" +#include "mfrngcod.h" + + + +/*A range decoder. + This is an entropy decoder based upon \cite{Mar79}, which is itself a + rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}. + It is very similar to arithmetic encoding, except that encoding is done with + digits in any base, instead of with bits, and so it is faster when using + larger bases (i.e.: a byte). + The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$ + is the base, longer than the theoretical optimum, but to my knowledge there + is no published justification for this claim. + This only seems true when using near-infinite precision arithmetic so that + the process is carried out with no rounding errors. + + IBM (the author's employer) never sought to patent the idea, and to my + knowledge the algorithm is unencumbered by any patents, though its + performance is very competitive with proprietary arithmetic coding. + The two are based on very similar ideas, however. + An excellent description of implementation details is available at + http://www.arturocampos.com/ac_range.html + A recent work \cite{MNW98} which proposes several changes to arithmetic + encoding for efficiency actually re-discovers many of the principles + behind range encoding, and presents a good theoretical analysis of them. + + End of stream is handled by writing out the smallest number of bits that + ensures that the stream will be correctly decoded regardless of the value of + any subsequent bits. + ec_tell() can be used to determine how many bits were needed to decode + all the symbols thus far; other data can be packed in the remaining bits of + the input buffer. + @PHDTHESIS{Pas76, + author="Richard Clark Pasco", + title="Source coding algorithms for fast data compression", + school="Dept. of Electrical Engineering, Stanford University", + address="Stanford, CA", + month=May, + year=1976 + } + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video & Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + + + +static int ec_read_byte(ec_dec *_this){ + return _this->offs<_this->storage?_this->buf[_this->offs++]:0; +} + +static int ec_read_byte_from_end(ec_dec *_this){ + return _this->end_offs<_this->storage? + _this->buf[_this->storage-++(_this->end_offs)]:0; +} + + +/*Normalizes the contents of val and rng so that rng lies entirely in the + high-order symbol.*/ +static void ec_dec_normalize(ec_dec *_this){ + /*If the range is too small, rescale it and input some bits.*/ + while(_this->rng<=EC_CODE_BOT){ + int sym; + _this->nbits_total+=EC_SYM_BITS; + _this->rng<<=EC_SYM_BITS; + /*Use up the remaining bits from our last symbol.*/ + sym=_this->rem; + /*Read the next value from the input.*/ + _this->rem=ec_read_byte(_this); + /*Take the rest of the bits we need from this new symbol.*/ + sym=(sym<rem)>>EC_SYM_BITS-EC_CODE_EXTRA; + /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ + _this->val=(_this->val<buf=_buf; + _this->storage=_storage; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + _this->offs=0; + _this->rng=1U<rem=ec_read_byte(_this); + _this->val=_this->rng-1-(_this->rem>>EC_SYM_BITS-EC_CODE_EXTRA); + _this->error=0; + /*Normalize the interval.*/ + ec_dec_normalize(_this); + /*This is the offset from which ec_tell() will subtract partial bits. + This must be after the initial ec_dec_normalize(), or you will have to + compensate for the bits that are read there.*/ + _this->nbits_total=EC_CODE_BITS+1; +} + + +unsigned ec_decode(ec_dec *_this,unsigned _ft){ + unsigned s; + _this->ext=_this->rng/_ft; + s=(unsigned)(_this->val/_this->ext); + return _ft-EC_MINI(s+1,_ft); +} + +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){ + unsigned s; + _this->ext=_this->rng>>_bits; + s=(unsigned)(_this->val/_this->ext); + return (1<<_bits)-EC_MINI(s+1,1<<_bits); +} + +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + celt_uint32 s; + s=IMUL32(_this->ext,_ft-_fh); + _this->val-=s; + _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s; + ec_dec_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){ + celt_uint32 r; + celt_uint32 d; + celt_uint32 s; + int ret; + r=_this->rng; + d=_this->val; + s=r>>_logp; + ret=dval=d-s; + _this->rng=ret?s:r-s; + ec_dec_normalize(_this); + return ret; +} + +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){ + celt_uint32 r; + celt_uint32 d; + celt_uint32 s; + celt_uint32 t; + int ret; + s=_this->rng; + d=_this->val; + r=s>>_ftb; + ret=-1; + do{ + t=s; + s=IMUL32(r,_icdf[++ret]); + } + while(dval=d-s; + _this->rng=t-s; + ec_dec_normalize(_this); + return ret; +} + +celt_uint32 ec_dec_uint(ec_dec *_this,celt_uint32 _ft){ + unsigned ft; + unsigned s; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + celt_uint32 t; + ftb-=EC_UINT_BITS; + ft=(unsigned)(_ft>>ftb)+1; + s=ec_decode(_this,ft); + ec_dec_update(_this,s,s+1,ft); + t=(celt_uint32)s<error=1; + return _ft; + } + else{ + _ft++; + s=ec_decode(_this,(unsigned)_ft); + ec_dec_update(_this,s,s+1,(unsigned)_ft); + return s; + } +} + +celt_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){ + ec_window window; + int available; + celt_uint32 ret; + window=_this->end_window; + available=_this->nend_bits; + if(available<_bits){ + do{ + window|=(ec_window)ec_read_byte_from_end(_this)<>=_bits; + available-=_bits; + _this->end_window=window; + _this->nend_bits=available; + _this->nbits_total+=_bits; + return ret; +} diff --git a/native/codec/libraries/celt/libcelt/entdec.h b/native/codec/libraries/celt/libcelt/entdec.h new file mode 100644 index 0000000..593979b --- /dev/null +++ b/native/codec/libraries/celt/libcelt/entdec.h @@ -0,0 +1,102 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entdec_H) +# define _entdec_H (1) +# include +# include "entcode.h" + + + +/*Initializes the decoder. + _buf: The input buffer to use. + Return: 0 on success, or a negative value on error.*/ +void ec_dec_init(ec_dec *_this,unsigned char *_buf,celt_uint32 _storage); + +/*Calculates the cumulative frequency for the next symbol. + This can then be fed into the probability model to determine what that + symbol is, and the additional frequency information required to advance to + the next symbol. + This function cannot be called more than once without a corresponding call to + ec_dec_update(), or decoding will not proceed correctly. + _ft: The total frequency of the symbols in the alphabet the next symbol was + encoded with. + Return: A cumulative frequency representing the encoded symbol. + If the cumulative frequency of all the symbols before the one that + was encoded was fl, and the cumulative frequency of all the symbols + up to and including the one encoded is fh, then the returned value + will fall in the range [fl,fh).*/ +unsigned ec_decode(ec_dec *_this,unsigned _ft); + +/*Equivalent to ec_decode() with _ft==1<<_bits.*/ +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits); + +/*Advance the decoder past the next symbol using the frequency information the + symbol was encoded with. + Exactly one call to ec_decode() must have been made so that all necessary + intermediate calculations are performed. + _fl: The cumulative frequency of all symbols that come before the symbol + decoded. + _fh: The cumulative frequency of all symbols up to and including the symbol + decoded. + Together with _fl, this defines the range [_fl,_fh) in which the value + returned above must fall. + _ft: The total frequency of the symbols in the alphabet the symbol decoded + was encoded in. + This must be the same as passed to the preceding call to ec_decode().*/ +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/* Decode a bit that has a 1/(1<<_logp) probability of being a one */ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp); + +/*Decodes a symbol given an "inverse" CDF table. + No call to ec_dec_update() is necessary after this call. + _icdf: The "inverse" CDF, such that symbol s falls in the range + [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution. + Return: The decoded symbol s.*/ +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); + +/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream. + The bits must have been encoded with ec_enc_uint(). + No call to ec_dec_update() is necessary after this call. + _ft: The number of integers that can be decoded (one more than the max). + This must be at least one, and no more than 2**32-1. + Return: The decoded bits.*/ +celt_uint32 ec_dec_uint(ec_dec *_this,celt_uint32 _ft); + +/*Extracts a sequence of raw bits from the stream. + The bits must have been encoded with ec_enc_bits(). + No call to ec_dec_update() is necessary after this call. + _ftb: The number of bits to extract. + This must be between 0 and 25, inclusive. + Return: The decoded bits.*/ +celt_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb); + +#endif diff --git a/native/codec/libraries/celt/libcelt/entenc.c b/native/codec/libraries/celt/libcelt/entenc.c new file mode 100644 index 0000000..df649a6 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/entenc.c @@ -0,0 +1,298 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if defined(HAVE_CONFIG_H) +# include "config.h" +#endif +#include "os_support.h" +#include "arch.h" +#include "entenc.h" +#include "mfrngcod.h" + + + +/*A range encoder. + See entdec.c and the references for implementation details \cite{Mar79,MNW98}. + + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video \& Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + + + +static int ec_write_byte(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->offs++]=(unsigned char)_value; + return 0; +} + +static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value; + return 0; +} + + +/*Outputs a symbol, with a carry bit. + If there is a potential to propagate a carry over several symbols, they are + buffered until it can be determined whether or not an actual carry will + occur. + If the counter for the buffered symbols overflows, then the stream becomes + undecodable. + This gives a theoretical limit of a few billion symbols in a single packet on + 32-bit systems. + The alternative is to truncate the range in order to force a carry, but + requires similar carry tracking in the decoder, needlessly slowing it down.*/ +static void ec_enc_carry_out(ec_enc *_this,int _c){ + if(_c!=EC_SYM_MAX){ + /*No further carry propagation possible, flush buffer.*/ + int carry; + carry=_c>>EC_SYM_BITS; + /*Don't output a byte on the first write. + This compare should be taken care of by branch-prediction thereafter.*/ + if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry); + if(_this->ext>0){ + unsigned sym; + sym=EC_SYM_MAX+carry&EC_SYM_MAX; + do _this->error|=ec_write_byte(_this,sym); + while(--(_this->ext)>0); + } + _this->rem=_c&EC_SYM_MAX; + } + else _this->ext++; +} + +static void ec_enc_normalize(ec_enc *_this){ + /*If the range is too small, output some bits and rescale it.*/ + while(_this->rng<=EC_CODE_BOT){ + ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT)); + /*Move the next-to-high-order symbol into the high-order position.*/ + _this->val=_this->val<rng<<=EC_SYM_BITS; + _this->nbits_total+=EC_SYM_BITS; + } +} + +void ec_enc_init(ec_enc *_this,unsigned char *_buf,celt_uint32 _size){ + _this->buf=_buf; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits.*/ + _this->nbits_total=EC_CODE_BITS+1; + _this->offs=0; + _this->rng=EC_CODE_TOP; + _this->rem=-1; + _this->val=0; + _this->ext=0; + _this->storage=_size; + _this->error=0; +} + +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + celt_uint32 r; + r=_this->rng/_ft; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,(_ft-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,(_ft-_fh)); + ec_enc_normalize(_this); +} + +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){ + celt_uint32 r; + r=_this->rng>>_bits; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,((1<<_bits)-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,((1<<_bits)-_fh)); + ec_enc_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){ + celt_uint32 r; + celt_uint32 s; + celt_uint32 l; + r=_this->rng; + l=_this->val; + s=r>>_logp; + r-=s; + if(_val)_this->val=l+r; + _this->rng=_val?s:r; + ec_enc_normalize(_this); +} + +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){ + celt_uint32 r; + r=_this->rng>>_ftb; + if(_s>0){ + _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]); + _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]); + } + else _this->rng-=IMUL32(r,_icdf[_s]); + ec_enc_normalize(_this); +} + +void ec_enc_uint(ec_enc *_this,celt_uint32 _fl,celt_uint32 _ft){ + unsigned ft; + unsigned fl; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + ftb-=EC_UINT_BITS; + ft=(_ft>>ftb)+1; + fl=(unsigned)(_fl>>ftb); + ec_encode(_this,fl,fl+1,ft); + ec_enc_bits(_this,_fl&((celt_uint32)1<end_window; + used=_this->nend_bits; + if(used+_bits>EC_WINDOW_SIZE){ + do{ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + while(used>=EC_SYM_BITS); + } + window|=(ec_window)_fl<end_window=window; + _this->nend_bits=used; + _this->nbits_total+=_bits; +} + +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){ + int shift; + unsigned mask; + celt_assert(_nbits<=EC_SYM_BITS); + shift=EC_SYM_BITS-_nbits; + mask=(1<<_nbits)-1<offs>0){ + /*The first byte has been finalized.*/ + _this->buf[0]=(unsigned char)(_this->buf[0]&~mask|_val<rem>=0){ + /*The first byte is still awaiting carry propagation.*/ + _this->rem=_this->rem&~mask|_val<rng<=EC_CODE_TOP>>shift){ + /*The renormalization loop has never been run.*/ + _this->val=_this->val&~((celt_uint32)mask<error=-1; +} + +void ec_enc_shrink(ec_enc *_this,celt_uint32 _size){ + celt_assert(_this->offs+_this->end_offs<=_size); + CELT_MOVE(_this->buf+_size-_this->end_offs, + _this->buf+_this->storage-_this->end_offs,_this->end_offs); + _this->storage=_size; +} + +void ec_enc_done(ec_enc *_this){ + ec_window window; + int used; + celt_uint32 msk; + celt_uint32 end; + int l; + /*We output the minimum number of bits that ensures that the symbols encoded + thus far will be decoded correctly regardless of the bits that follow.*/ + l=EC_CODE_BITS-EC_ILOG(_this->rng); + msk=EC_CODE_TOP-1>>l; + end=_this->val+msk&~msk; + if((end|msk)>=_this->val+_this->rng){ + l++; + msk>>=1; + end=_this->val+msk&~msk; + } + while(l>0){ + ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT)); + end=end<rem>=0||_this->ext>0)ec_enc_carry_out(_this,0); + /*If we have buffered extra bits, flush them as well.*/ + window=_this->end_window; + used=_this->nend_bits; + while(used>=EC_SYM_BITS){ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + /*Clear any excess space and add any remaining extra bits to the last byte.*/ + if(!_this->error){ + CELT_MEMSET(_this->buf+_this->offs,0, + _this->storage-_this->offs-_this->end_offs); + if(used>0){ + /*If there's no range coder data at all, give up.*/ + if(_this->end_offs>=_this->storage)_this->error=-1; + else{ + l=-l; + /*If we've busted, don't add too many extra bits to the last byte; it + would corrupt the range coder data, and that's more important.*/ + if(_this->offs+_this->end_offs>=_this->storage&&lerror=-1; + } + } + _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window; + } + } +} diff --git a/native/codec/libraries/celt/libcelt/entenc.h b/native/codec/libraries/celt/libcelt/entenc.h new file mode 100644 index 0000000..7e30617 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/entenc.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entenc_H) +# define _entenc_H (1) +# include +# include "entcode.h" + + + +/*Initializes the encoder. + _buf: The buffer to store output bytes in. + _size: The size of the buffer, in chars.*/ +void ec_enc_init(ec_enc *_this,unsigned char *_buf,celt_uint32 _size); +/*Encodes a symbol given its frequency information. + The frequency information must be discernable by the decoder, assuming it + has read only the previous symbols from the stream. + It is allowable to change the frequency information, or even the entire + source alphabet, so long as the decoder can tell from the context of the + previously encoded information that it is supposed to do so as well. + _fl: The cumulative frequency of all symbols that come before the one to be + encoded. + _fh: The cumulative frequency of all symbols up to and including the one to + be encoded. + Together with _fl, this defines the range [_fl,_fh) in which the + decoded value will fall. + _ft: The sum of the frequencies of all the symbols*/ +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/*Equivalent to ec_encode() with _ft==1<<_bits.*/ +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits); + +/* Encode a bit that has a 1/(1<<_logp) probability of being a one */ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp); + +/*Encodes a symbol given an "inverse" CDF table. + _s: The index of the symbol to encode. + _icdf: The "inverse" CDF, such that symbol _s falls in the range + [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution.*/ +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb); + +/*Encodes a raw unsigned integer in the stream. + _fl: The integer to encode. + _ft: The number of integers that can be encoded (one more than the max). + This must be at least one, and no more than 2**32-1.*/ +void ec_enc_uint(ec_enc *_this,celt_uint32 _fl,celt_uint32 _ft); + +/*Encodes a sequence of raw bits in the stream. + _fl: The bits to encode. + _ftb: The number of bits to encode. + This must be between 0 and 25, inclusive.*/ +void ec_enc_bits(ec_enc *_this,celt_uint32 _fl,unsigned _ftb); + +/*Overwrites a few bits at the very start of an existing stream, after they + have already been encoded. + This makes it possible to have a few flags up front, where it is easy for + decoders to access them without parsing the whole stream, even if their + values are not determined until late in the encoding process, without having + to buffer all the intermediate symbols in the encoder. + In order for this to work, at least _nbits bits must have already been + encoded using probabilities that are an exact power of two. + The encoder can verify the number of encoded bits is sufficient, but cannot + check this latter condition. + _val: The bits to encode (in the least _nbits significant bits). + They will be decoded in order from most-significant to least. + _nbits: The number of bits to overwrite. + This must be no more than 8.*/ +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits); + +/*Compacts the data to fit in the target size. + This moves up the raw bits at the end of the current buffer so they are at + the end of the new buffer size. + The caller must ensure that the amount of data that's already been written + will fit in the new size. + _size: The number of bytes in the new buffer. + This must be large enough to contain the bits already written, and + must be no larger than the existing size.*/ +void ec_enc_shrink(ec_enc *_this,celt_uint32 _size); + +/*Indicates that there are no more symbols to encode. + All reamining output bytes are flushed to the output buffer. + ec_enc_init() must be called before the encoder can be used again.*/ +void ec_enc_done(ec_enc *_this); + +#endif diff --git a/native/codec/libraries/celt/libcelt/fixed_c5x.h b/native/codec/libraries/celt/libcelt/fixed_c5x.h new file mode 100644 index 0000000..7e2aa32 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/fixed_c5x.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_c5x.h + @brief Fixed-point operations for the TI C5x DSP family +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_C5X_H +#define FIXED_C5X_H + +#include "dsplib.h" + +#undef IMUL32 +static inline long IMUL32(long i, long j) +{ + long ac0, ac1; + ac0 = _lmpy(i>>16,j); + ac1 = ac0 + _lmpy(i,j>>16); + return _lmpyu(i,j) + (ac1<<16); +} + +#undef MAX16 +#define MAX16(a,b) _max(a,b) + +#undef MIN16 +#define MIN16(a,b) _min(a,b) + +#undef MAX32 +#define MAX32(a,b) _lmax(a,b) + +#undef MIN32 +#define MIN32(a,b) _lmin(a,b) + +#undef VSHR32 +#define VSHR32(a, shift) _lshl(a,-(shift)) + +#undef MULT16_16_Q15 +#define MULT16_16_Q15(a,b) (_smpy(a,b)) + +#undef MULT16_16SU +#define MULT16_16SU(a,b) _lmpysu(a,b) + +#undef MULT_16_16 +#define MULT_16_16(a,b) _lmpy(a,b) + +/* FIXME: This is technically incorrect and is bound to cause problems. Is there any cleaner solution? */ +#undef MULT16_32_Q15 +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),(b)),15)) + + +#define celt_ilog2(x) (30 - _lnorm(x)) +#define OVERRIDE_CELT_ILOG2 + +#define celt_maxabs16(x, len) MAX16(maxval((DATA *)x, len),-minval((DATA *)x, len)) +#define OVERRIDE_CELT_MAXABS16 + +#define OVERRIDE_FIND_MAX16 +static inline int find_max16(celt_word16 *x, int len) +{ + DATA max_corr16 = -VERY_LARGE16; + DATA pitch16 = 0; + maxvec((DATA *)x, len, &max_corr16, &pitch16); + return pitch16; +} + +#endif /* FIXED_C5X_H */ diff --git a/native/codec/libraries/celt/libcelt/fixed_c6x.h b/native/codec/libraries/celt/libcelt/fixed_c6x.h new file mode 100644 index 0000000..47b851a --- /dev/null +++ b/native/codec/libraries/celt/libcelt/fixed_c6x.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2008 CSIRO */ +/** + @file fixed_c6x.h + @brief Fixed-point operations for the TI C6x DSP family +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_C6X_H +#define FIXED_C6X_H + +#undef MULT16_16SU +#define MULT16_16SU(a,b) _mpysu(a,b) + +#undef MULT_16_16 +#define MULT_16_16(a,b) _mpy(a,b) + +#define celt_ilog2(x) (30 - _norm(x)) +#define OVERRIDE_CELT_ILOG2 + +#undef MULT16_32_Q15 +#define MULT16_32_Q15(a,b) (_mpylill(a, b) >> 15) + +#if 0 +#include "dsplib.h" + +#undef MAX16 +#define MAX16(a,b) _max(a,b) + +#undef MIN16 +#define MIN16(a,b) _min(a,b) + +#undef MAX32 +#define MAX32(a,b) _lmax(a,b) + +#undef MIN32 +#define MIN32(a,b) _lmin(a,b) + +#undef VSHR32 +#define VSHR32(a, shift) _lshl(a,-(shift)) + +#undef MULT16_16_Q15 +#define MULT16_16_Q15(a,b) (_smpy(a,b)) + +#define celt_maxabs16(x, len) MAX16(maxval((DATA *)x, len),-minval((DATA *)x, len)) +#define OVERRIDE_CELT_MAXABS16 + +#define OVERRIDE_FIND_MAX16 +static inline int find_max16(celt_word16 *x, int len) +{ + DATA max_corr16 = -VERY_LARGE16; + DATA pitch16 = 0; + maxvec((DATA *)x, len, &max_corr16, &pitch16); + return pitch16; +} +#endif + +#endif /* FIXED_C6X_H */ diff --git a/native/codec/libraries/celt/libcelt/fixed_debug.h b/native/codec/libraries/celt/libcelt/fixed_debug.h new file mode 100644 index 0000000..ddf5695 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/fixed_debug.h @@ -0,0 +1,551 @@ +/* Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include + +#ifdef CELT_C +long long celt_mips=0; +#else +extern long long celt_mips; +#endif + +#define MIPS_INC celt_mips++, + +#define MULT16_16SU(a,b) ((celt_word32)(celt_word16)(a)*(celt_word32)(celt_uint16)(b)) +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +#define QCONST16(x,bits) ((celt_word16)(.5+(x)*(((celt_word32)1)<<(bits)))) +#define QCONST32(x,bits) ((celt_word32)(.5+(x)*(((celt_word32)1)<<(bits)))) + + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) +#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1)) + +#define SHR(a,b) SHR32(a,b) +#define PSHR(a,b) PSHR32(a,b) + +static inline short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); + } + res = -x; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); + celt_mips++; + return res; +} +static inline int NEG32(long long x) +{ + long long res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); + } + res = -x; + if (!VERIFY_INT(res)) + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); + celt_mips+=2; + return res; +} + +#define EXTRACT16(x) _EXTRACT16(x, __FILE__, __LINE__) +static inline short _EXTRACT16(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + celt_mips++; + return res; +} + +#define EXTEND32(x) _EXTEND32(x, __FILE__, __LINE__) +static inline int _EXTEND32(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + celt_mips++; + return res; +} + +#define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) +static inline short _SHR16(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); + celt_mips++; + return res; +} +#define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) +static inline short _SHL16(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); + } + celt_mips+=2; + return res; +} +static inline int SHL32(long long a, int shift) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift); + } + res = a<>1))),shift)) +#define PSHR32(a,shift) (celt_mips--,SHR32(ADD32((a),(((celt_word32)(1)<<((shift))>>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a)))) +#define HALF32(x) (SHR32(x,1)) + +//#define SHR(a,shift) ((a) >> (shift)) +//#define SHL(a,shift) ((a) << (shift)) + +#define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) +static inline short _ADD16(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); + } + celt_mips++; + return res; +} + +#define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) +static inline short _SUB16(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a-b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); + celt_mips++; + return res; +} + +#define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) +static inline int _ADD32(long long a, long long b, char *file, int line) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); + } + celt_mips+=2; + return res; +} + +#define SUB32(a, b) _SUB32(a, b, __FILE__, __LINE__) +static inline int _SUB32(long long a, long long b, char *file, int line) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a-b; + if (!VERIFY_INT(res)) + fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line); + celt_mips+=2; + return res; +} + +#undef UADD32 +#define UADD32(a, b) _UADD32(a, b, __FILE__, __LINE__) +static inline unsigned int _UADD32(unsigned long long a, unsigned long long b, char *file, int line) +{ + long long res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "UADD32: inputs are not int: %u %u in %s: line %d\n", (unsigned)a, (unsigned)b, file, line); + } + res = a+b; + if (!VERIFY_UINT(res)) + { + fprintf (stderr, "UADD32: output is not int: %u in %s: line %d\n", (unsigned)res, file, line); + } + celt_mips+=2; + return res; +} + +#undef USUB32 +#define USUB32(a, b) _USUB32(a, b, __FILE__, __LINE__) +static inline unsigned int _USUB32(unsigned long long a, unsigned long long b, char *file, int line) +{ + long long res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + /*fprintf (stderr, "USUB32: inputs are not int: %llu %llu in %s: line %d\n", (unsigned)a, (unsigned)b, file, line);*/ + } + res = a-b; + if (!VERIFY_UINT(res)) + { + /*fprintf (stderr, "USUB32: output is not int: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);*/ + } + celt_mips+=2; + return res; +} + + + +/* result fits in 16 bits */ +static inline short MULT16_16_16(int a, int b) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b); + } + res = a*b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res); + celt_mips++; + return res; +} + +#define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) +static inline int _MULT16_16(int a, int b, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = ((long long)a)*b; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line); + celt_mips++; + return res; +} + +#define MAC16_16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_16((a),(b)))) +#define MAC16_16_Q11(c,a,b) (ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11)))) +#define MAC16_16_Q13(c,a,b) (ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13)))) +#define MAC16_16_P13(c,a,b) (ADD16((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13))) + + +#define MULT16_32_QX(a, b, Q) _MULT16_32_QX(a, b, Q, __FILE__, __LINE__) +static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + } + if (ABS32(b)>=((celt_word32)(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + res = (((long long)a)*(long long)b) >> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); + if (Q==15) + celt_mips+=3; + else + celt_mips+=4; + return res; +} + +static inline int MULT16_32_PX(int a, long long b, int Q) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); + } + if (ABS32(b)>=((celt_word32)(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); + res = ((((long long)a)*(long long)b) + (((celt_word32)(1)<>1))>> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); + if (Q==15) + celt_mips+=4; + else + celt_mips+=5; + return res; +} + + +#define MULT16_32_Q11(a,b) MULT16_32_QX(a,b,11) +#define MAC16_32_Q11(c,a,b) ADD32((c),MULT16_32_Q11((a),(b))) +#define MULT16_32_Q12(a,b) MULT16_32_QX(a,b,12) +#define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13) +#define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14) +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MULT16_32_P15(a,b) MULT16_32_PX(a,b,15) +#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b)))) + +static inline int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + celt_mips+=3; + return a; +} + +static inline int MULT16_16_Q11_32(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); + celt_mips+=3; + return res; +} +static inline short MULT16_16_Q13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); + celt_mips+=3; + return res; +} +static inline short MULT16_16_Q14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); + celt_mips+=3; + return res; +} + +#define MULT16_16_Q15(a, b) _MULT16_16_Q15(a, b, __FILE__, __LINE__) +static inline short _MULT16_16_Q15(int a, int b, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = ((long long)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line); + } + celt_mips+=1; + return res; +} + +static inline short MULT16_16_P13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); + celt_mips+=4; + return res; +} +static inline short MULT16_16_P14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); + celt_mips+=4; + return res; +} +static inline short MULT16_16_P15(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 15; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); + celt_mips+=2; + return res; +} + +#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) + +static inline int _DIV32_16(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; + } + celt_mips+=35; + return res; +} + +#define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) +static inline int _DIV32(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_INT(res)) + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); + celt_mips+=70; + return res; +} +#define PDIV32(a,b) DIV32(ADD32((a),(b)>>1),b) +#define PDIV32_16(a,b) DIV32_16(ADD32((a),(b)>>1),b) + +#undef PRINT_MIPS +#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0); + +#endif diff --git a/native/codec/libraries/celt/libcelt/fixed_generic.h b/native/codec/libraries/celt/libcelt/fixed_generic.h new file mode 100644 index 0000000..069070f --- /dev/null +++ b/native/codec/libraries/celt/libcelt/fixed_generic.h @@ -0,0 +1,157 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */ +#define MULT16_16SU(a,b) ((celt_word32)(celt_word16)(a)*(celt_word32)(celt_uint16)(b)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15)) + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15)) + +/** 32x32 multiplication, followed by a 32-bit shift right. Results fits in 32 bits */ +#define MULT32_32_Q32(a,b) ADD32(ADD32(MULT16_16(SHR((a),16),SHR((b),16)), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),16)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),16)) + +/** Compile-time conversion of float constant to 16-bit value */ +#define QCONST16(x,bits) ((celt_word16)(.5+(x)*(((celt_word32)1)<<(bits)))) +/** Compile-time conversion of float constant to 32-bit value */ +#define QCONST32(x,bits) ((celt_word32)(.5+(x)*(((celt_word32)1)<<(bits)))) + +/** Negate a 16-bit value */ +#define NEG16(x) (-(x)) +/** Negate a 32-bit value */ +#define NEG32(x) (-(x)) + +/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */ +#define EXTRACT16(x) ((celt_word16)(x)) +/** Change a 16-bit value into a 32-bit value */ +#define EXTEND32(x) ((celt_word32)(x)) + +/** Arithmetic shift-right of a 16-bit value */ +#define SHR16(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 16-bit value */ +#define SHL16(a,shift) ((a) << (shift)) +/** Arithmetic shift-right of a 32-bit value */ +#define SHR32(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 32-bit value */ +#define SHL32(a,shift) ((celt_word32)(a) << (shift)) + +/** 16-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) +/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +/** 32-bit arithmetic shift right where the argument can be negative */ +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +/** Saturates 16-bit value to +/- a */ +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +/** Saturates 32-bit value to +/- a */ +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +/** "RAW" macros, should not be used outside of this header file */ +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) ((celt_word32)(a) << (shift)) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */ +#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a)))) +/** Divide by two */ +#define HALF32(x) (SHR32(x,1)) + +/** Add two 16-bit values */ +#define ADD16(a,b) ((celt_word16)((celt_word16)(a)+(celt_word16)(b))) +/** Subtract two 16-bit values */ +#define SUB16(a,b) ((celt_word16)(a)-(celt_word16)(b)) +/** Add two 32-bit values */ +#define ADD32(a,b) ((celt_word32)(a)+(celt_word32)(b)) +/** Subtract two 32-bit values */ +#define SUB32(a,b) ((celt_word32)(a)-(celt_word32)(b)) + + +/** 16x16 multiplication where the result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((celt_word16)(a))*((celt_word16)(b)))) + +/* (celt_word32)(celt_word16) gives TI compiler a hint that it's 16x16->32 multiply */ +/** 16x16 multiplication where the result fits in 32 bits */ +#define MULT16_16(a,b) (((celt_word32)(celt_word16)(a))*((celt_word32)(celt_word16)(b))) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +/** 16x32 multiplication, followed by a 12-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) +/** 16x32 multiplication, followed by a 13-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) +/** 16x32 multiplication, followed by a 14-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14)) + +/** 16x32 multiplication, followed by an 11-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) +/** 16x32 multiply-add, followed by an 11-bit shift right. Results fits in 32 bits */ +#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) + +/** 16x32 multiplication, followed by a 15-bit shift right (round-to-nearest). Results fits in 32 bits */ +#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) +/** 16x32 multiply-add, followed by a 15-bit shift right. Results fits in 32 bits */ +#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + + +#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) +#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13))) +#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */ +#define DIV32_16(a,b) ((celt_word16)(((celt_word32)(a))/((celt_word16)(b)))) +/** Divide a 32-bit value by a 16-bit value and round to nearest. Result fits in 16 bits */ +#define PDIV32_16(a,b) ((celt_word16)(((celt_word32)(a)+((celt_word16)(b)>>1))/((celt_word16)(b)))) +/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */ +#define DIV32(a,b) (((celt_word32)(a))/((celt_word32)(b))) +/** Divide a 32-bit value by a 32-bit value and round to nearest. Result fits in 32 bits */ +#define PDIV32(a,b) (((celt_word32)(a)+((celt_word16)(b)>>1))/((celt_word32)(b))) + +#endif diff --git a/native/codec/libraries/celt/libcelt/float_cast.h b/native/codec/libraries/celt/libcelt/float_cast.h new file mode 100644 index 0000000..72c1714 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/float_cast.h @@ -0,0 +1,132 @@ +/* Copyright (C) 2001 Erik de Castro Lopo */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Version 1.1 */ + +#ifndef FLOAT_CAST_H +#define FLOAT_CAST_H + +/*============================================================================ +** On Intel Pentium processors (especially PIII and probably P4), converting +** from float to int is very slow. To meet the C specs, the code produced by +** most C compilers targeting Pentium needs to change the FPU rounding mode +** before the float to int conversion is performed. +** +** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It +** is this flushing of the pipeline which is so slow. +** +** Fortunately the ISO C99 specifications define the functions lrint, lrintf, +** llrint and llrintf which fix this problem as a side effect. +** +** On Unix-like systems, the configure process should have detected the +** presence of these functions. If they weren't found we have to replace them +** here with a standard C cast. +*/ + +/* +** The C99 prototypes for lrint and lrintf are as follows: +** +** long int lrintf (float x) ; +** long int lrint (double x) ; +*/ + +/* The presence of the required functions are detected during the configure +** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in +** the config.h file. +*/ + +#if (HAVE_LRINTF) +/*#if 0*/ + + /* These defines enable functionality introduced with the 1999 ISO C + ** standard. They must be defined before the inclusion of math.h to + ** engage them. If optimisation is enabled, these functions will be + ** inlined. With optimisation switched off, you have to link in the + ** maths library using -lm. + */ + + #define _ISOC9X_SOURCE 1 + #define _ISOC99_SOURCE 1 + + #define __USE_ISOC9X 1 + #define __USE_ISOC99 1 + + #include + #define float2int(x) lrintf(x) + +#elif (defined(HAVE_LRINT)) + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrint(x) + +#elif (defined (WIN64) || defined (_WIN64)) + #include + + __inline long int float2int(float value) + { + return _mm_cvtss_si32(_mm_load_ss(&value)); + } +#elif (defined (WIN32) || defined (_WIN32)) + + #include + + /* Win32 doesn't seem to have these functions. + ** Therefore implement inline versions of these functions here. + */ + + __inline long int + float2int (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + +#else + +#ifdef __GNUC__ /* supported by gcc, but not by all other compilers*/ + #warning "Don't have the functions lrint() and lrintf ()." + #warning "Replacing these functions with a standard C cast." +#endif /* __GNUC__ */ + + #include + + #define float2int(flt) ((int)(floor(.5+flt))) + +#endif + + +#endif /* FLOAT_CAST_H */ diff --git a/native/codec/libraries/celt/libcelt/header.c b/native/codec/libraries/celt/libcelt/header.c new file mode 100644 index 0000000..37b11bf --- /dev/null +++ b/native/codec/libraries/celt/libcelt/header.c @@ -0,0 +1,124 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt_header.h" +#include "os_support.h" +#include "modes.h" + +static celt_uint32 +_le_32 (celt_uint32 i) +{ + celt_uint32 ret=i; +#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) + ret = (i>>24); + ret += (i>>8) & 0x0000ff00; + ret += (i<<8) & 0x00ff0000; + ret += (i<<24); +#endif + return ret; +} + +int celt_header_init(CELTHeader *header, const CELTMode *m, int frame_size, int channels) +{ + if (header==NULL) + return CELT_BAD_ARG; + + CELT_COPY(header->codec_id, "CELT ", 8); + CELT_COPY(header->codec_version, "experimental ", 20); + + /* FIXME: Set that to zero when we freeze */ + header->version_id = 0x80001000; + header->header_size = 56; + header->sample_rate = m->Fs; + header->nb_channels = channels; + /*FIXME: This won't work for variable frame size */ + header->frame_size = frame_size; + header->overlap = m->overlap; + header->bytes_per_packet = -1; + header->extra_headers = 0; + return CELT_OK; +} + +int celt_header_to_packet(const CELTHeader *header, unsigned char *packet, celt_uint32 size) +{ + celt_int32 * h; + + if ((size < 56) || (header==NULL) || (packet==NULL)) + return CELT_BAD_ARG; /* FAIL */ + + CELT_MEMSET(packet, 0, sizeof(*header)); + /* FIXME: Do it in an alignment-safe manner */ + + /* Copy ident and version */ + CELT_COPY(packet, (unsigned char*)header, 28); + + /* Copy the int32 fields */ + h = (celt_int32*)(packet+28); + *h++ = _le_32 (header->version_id); + *h++ = _le_32 (header->header_size); + *h++ = _le_32 (header->sample_rate); + *h++ = _le_32 (header->nb_channels); + *h++ = _le_32 (header->frame_size); + *h++ = _le_32 (header->overlap); + *h++ = _le_32 (header->bytes_per_packet); + *h = _le_32 (header->extra_headers); + + return sizeof(*header); +} + +int celt_header_from_packet(const unsigned char *packet, celt_uint32 size, CELTHeader *header) +{ + celt_int32 * h; + + if ((size < 56) || (header==NULL) || (packet==NULL)) + return CELT_BAD_ARG; /* FAIL */ + + CELT_MEMSET((unsigned char*)header, 0, sizeof(*header)); + /* FIXME: Do it in an alignment-safe manner */ + + /* Copy ident and version */ + CELT_COPY((unsigned char*)header, packet, 28); + + /* Copy the int32 fields */ + h = (celt_int32*)(packet+28); + header->version_id = _le_32(*h++); + header->header_size = _le_32(*h++); + header->sample_rate = _le_32(*h++); + header->nb_channels = _le_32(*h++); + header->frame_size = _le_32(*h++); + header->overlap = _le_32(*h++); + header->bytes_per_packet = _le_32(*h++); + header->extra_headers = _le_32(*h); + + return sizeof(*header); +} + diff --git a/native/codec/libraries/celt/libcelt/kiss_fft.c b/native/codec/libraries/celt/libcelt/kiss_fft.c new file mode 100644 index 0000000..4909231 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/kiss_fft.c @@ -0,0 +1,693 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding +Lots of modifications by Jean-Marc Valin +Copyright (c) 2005-2007, Xiph.Org Foundation +Copyright (c) 2008, Xiph.Org Foundation, CSIRO + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SKIP_CONFIG_H +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + complex numbers. It also delares the kf_ internal functions. +*/ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + const kiss_twiddle_cpx * tw1; + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jr = SHR(Fout->r, 1);Fout->i = SHR(Fout->i, 1); + Fout2->r = SHR(Fout2->r, 1);Fout2->i = SHR(Fout2->i, 1); + C_MUL (t, *Fout2 , *tw1); + tw1 += fstride; + C_SUB( *Fout2 , *Fout , t ); + C_ADDTO( *Fout , t ); + ++Fout2; + ++Fout; + } + } +} + +static void ki_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + const kiss_twiddle_cpx * tw1; + kiss_fft_cpx t; + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jtwiddles; + for (j=0;jr = PSHR(Fout->r, 2); + Fout->i = PSHR(Fout->i, 2); + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + Fout[m2].r = PSHR(Fout[m2].r, 2); + Fout[m2].i = PSHR(Fout[m2].i, 2); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + ++Fout; + } + } +} + +static void ki_bfly4( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + const kiss_twiddle_cpx *tw1,*tw2,*tw3; + kiss_fft_cpx scratch[6]; + const size_t m2=2*m; + const size_t m3=3*m; + int i, j; + + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for (j=0;jtwiddles[fstride*m]; + for (i=0;itwiddles; + k=m; + do { + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + } while(--k); + } +} + +static void ki_bfly3( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + size_t m, + int N, + int mm + ) +{ + size_t i, k; + const size_t m2 = 2*m; + const kiss_twiddle_cpx *tw1,*tw2; + kiss_fft_cpx scratch[5]; + kiss_twiddle_cpx epi3; + + kiss_fft_cpx * Fout_beg = Fout; + epi3 = st->twiddles[fstride*m]; + for (i=0;itwiddles; + k=m; + do{ + + C_MULC(scratch[1],Fout[m] , *tw1); + C_MULC(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , -epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + }while(--k); + } +} + + +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx * twiddles = st->twiddles; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + +static void ki_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx * twiddles = st->twiddles; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = -S_MUL(scratch[10].i,ya.i) - S_MUL(scratch[9].i,yb.i); + scratch[6].i = S_MUL(scratch[10].r,ya.i) + S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = S_MUL(scratch[10].i,yb.i) - S_MUL(scratch[9].i,ya.i); + scratch[12].i = -S_MUL(scratch[10].r,yb.i) + S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + +#endif + +static void kf_work( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + size_t fstride, + int in_stride, + const celt_int16 * factors, + const kiss_fft_state *st, + int N, + int m2 + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + /*printf ("fft %d %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N, m2);*/ + if (m!=1) + kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, m); + + /* Compensate for longer twiddles table (when sharing) */ + if (st->shift>0) + fstride <<= st->shift; + switch (p) { + case 2: kf_bfly2(Fout,fstride,st,m, N, m2); break; + case 4: kf_bfly4(Fout,fstride,st,m, N, m2); break; +#ifndef RADIX_TWO_ONLY + case 3: kf_bfly3(Fout,fstride,st,m, N, m2); break; + case 5: kf_bfly5(Fout,fstride,st,m, N, m2); break; +#endif + } +} + + +static void ki_work( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + size_t fstride, + int in_stride, + const celt_int16 * factors, + const kiss_fft_state *st, + int N, + int m2 + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + /*printf ("fft %d %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N, m2);*/ + if (m!=1) + ki_work( Fout , f, fstride*p, in_stride, factors,st, N*p, m); + + /* Compensate for longer twiddles table (when sharing) */ + if (st->shift>0) + fstride <<= st->shift; + switch (p) { + case 2: ki_bfly2(Fout,fstride,st,m, N, m2); break; + case 4: ki_bfly4(Fout,fstride,st,m, N, m2); break; +#ifndef RADIX_TWO_ONLY + case 3: ki_bfly3(Fout,fstride,st,m, N, m2); break; + case 5: ki_bfly5(Fout,fstride,st,m, N, m2); break; +#endif + } +} + + +#ifdef CUSTOM_MODES + +static +void compute_bitrev_table( + int Fout, + celt_int16 *f, + const size_t fstride, + int in_stride, + celt_int16 * factors, + const kiss_fft_state *st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (celt_int32)p*(celt_int32)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; +#ifdef RADIX_TWO_ONLY + if (p!=2 && p != 4) +#else + if (p>5) +#endif + { + return 0; + } + *facbuf++ = p; + *facbuf++ = n; + } while (n > 1); + return 1; +} + +static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft) +{ + int i; +#ifdef FIXED_POINT + for (i=0;i= memneeded) + st = (kiss_fft_state*)mem; + *lenmem = memneeded; + } + if (st) { + celt_int16 *bitrev; + kiss_twiddle_cpx *twiddles; + + st->nfft=nfft; +#ifndef FIXED_POINT + st->scale = 1./nfft; +#endif + if (base != NULL) + { + st->twiddles = base->twiddles; + st->shift = 0; + while (nfft<shift != base->nfft && st->shift < 32) + st->shift++; + /* FIXME: Report error and do proper cleanup */ + if (st->shift>=32) + return NULL; + } else { + st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft); + compute_twiddles(twiddles, nfft); + st->shift = -1; + } + if (!kf_factor(nfft,st->factors)) + { + kiss_fft_free(st); + return NULL; + } + + /* bitrev */ + st->bitrev = bitrev = (celt_int16*)KISS_FFT_MALLOC(sizeof(celt_int16)*nfft); + compute_bitrev_table(0, bitrev, 1,1, st->factors,st); + } + return st; +} + +kiss_fft_state *kiss_fft_alloc(int nfft,void * mem,size_t * lenmem ) +{ + return kiss_fft_alloc_twiddles(nfft, mem, lenmem, NULL); +} + +void kiss_fft_free(const kiss_fft_state *cfg) +{ + if (cfg) + { + celt_free((celt_int16*)cfg->bitrev); + if (cfg->shift < 0) + celt_free((kiss_twiddle_cpx*)cfg->twiddles); + celt_free((kiss_fft_state*)cfg); + } +} + +#endif /* CUSTOM_MODES */ + +static void kiss_fft_stride(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) +{ + int i; + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + { + fout[st->bitrev[i]] = fin[i]; +#ifndef FIXED_POINT + fout[st->bitrev[i]].r *= st->scale; + fout[st->bitrev[i]].i *= st->scale; +#endif + } + kf_work( fout, fin, 1,in_stride, st->factors,st, 1, 1); +} + +void kiss_fft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + kiss_fft_stride(cfg,fin,fout,1); +} + +static void kiss_ifft_stride(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) +{ + int i; + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + fout[st->bitrev[i]] = fin[i]; + ki_work( fout, fin, 1,in_stride, st->factors,st, 1, 1); +} + +void kiss_ifft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + kiss_ifft_stride(cfg,fin,fout,1); +} + diff --git a/native/codec/libraries/celt/libcelt/kiss_fft.h b/native/codec/libraries/celt/libcelt/kiss_fft.h new file mode 100644 index 0000000..d413dae --- /dev/null +++ b/native/codec/libraries/celt/libcelt/kiss_fft.h @@ -0,0 +1,165 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding +Lots of modifications by Jean-Marc Valin +Copyright (c) 2005-2007, Xiph.Org Foundation +Copyright (c) 2008, Xiph.Org Foundation, CSIRO + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ATTENTION! + If you would like a : + -- a utility that will handle the caching of fft objects + -- real-only (no imaginary time component ) FFT + -- a multi-dimensional FFT + -- a command-line utility to perform ffts + -- a command-line utility to perform fast-convolution filtering + + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c + in the tools/ directory. +*/ + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC celt_alloc +#endif + + +#ifdef FIXED_POINT +#include "arch.h" +#define DOUBLE_PRECISION + +#ifdef DOUBLE_PRECISION +# define kiss_fft_scalar celt_int32 +# define kiss_twiddle_scalar celt_int16 +# define KF_SUFFIX _celt_double +#else +# define kiss_fft_scalar celt_int16 +# define kiss_twiddle_scalar celt_int16 +# define KF_SUFFIX _celt_single +#endif +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# define kiss_twiddle_scalar float +# define KF_SUFFIX _celt_single +# endif +#endif + +#if 0 +/* This adds a suffix to all the kiss_fft functions so we + can easily link with more than one copy of the fft */ +#define CAT_SUFFIX(a,b) a ## b +#define SUF(a,b) CAT_SUFFIX(a, b) + +#define kiss_fft_alloc_twiddles SUF(kiss_fft_alloc_twiddles,KF_SUFFIX) +#define kiss_fft_alloc SUF(kiss_fft_alloc,KF_SUFFIX) +#define kiss_fft SUF(kiss_fft,KF_SUFFIX) +#define kiss_ifft SUF(kiss_ifft,KF_SUFFIX) +#define kiss_fft_stride SUF(kiss_fft_stride,KF_SUFFIX) +#define kiss_ifft_stride SUF(kiss_ifft_stride,KF_SUFFIX) +#define kiss_fft_free SUF(kiss_fft_free,KF_SUFFIX) + +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct { + kiss_twiddle_scalar r; + kiss_twiddle_scalar i; +}kiss_twiddle_cpx; + +#define MAXFACTORS 8 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +typedef struct kiss_fft_state{ + int nfft; +#ifndef FIXED_POINT + kiss_fft_scalar scale; +#endif + int shift; + celt_int16 factors[2*MAXFACTORS]; + const celt_int16 *bitrev; + const kiss_twiddle_cpx *twiddles; +} kiss_fft_state; + +//typedef struct kiss_fft_state* kiss_fft_cfg; + +/** + * kiss_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_state *kiss_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base); + +kiss_fft_state *kiss_fft_alloc(int nfft,void * mem,size_t * lenmem); + +/** + * kiss_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void kiss_fft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); +void kiss_ifft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +void kiss_fft_free(const kiss_fft_state *cfg); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/celt/libcelt/laplace.c b/native/codec/libraries/celt/libcelt/laplace.c new file mode 100644 index 0000000..b4e1f87 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/laplace.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "laplace.h" +#include "mathops.h" + +/* The minimum probability of an energy delta (out of 32768). */ +#define LAPLACE_LOG_MINP (0) +#define LAPLACE_MINP (1<>15; +} + +void ec_laplace_encode(ec_enc *enc, int *value, int fs, int decay) +{ + unsigned fl; + int val = *value; + fl = 0; + if (val) + { + int s; + int i; + s = -(val<0); + val = val+s^s; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay); + /* Search the decaying part of the PDF.*/ + for (i=1; fs > 0 && i < val; i++) + { + fs *= 2; + fl += fs+2*LAPLACE_MINP; + fs = (fs*(celt_int32)decay)>>15; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= 0) + { + int di; + int ndi_max; + ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP; + ndi_max = (ndi_max-s)>>1; + di = IMIN(val - i, ndi_max - 1); + fl += (2*di+1+s)*LAPLACE_MINP; + fs = IMIN(LAPLACE_MINP, 32768-fl); + *value = i+di+s^s; + } + else + { + fs += LAPLACE_MINP; + fl += fs&~s; + } + celt_assert(fl+fs<=32768); + celt_assert(fs>0); + } + ec_encode_bin(enc, fl, fl+fs, 15); +} + + +int ec_laplace_decode(ec_dec *dec, int fs, int decay) +{ + int val=0; + unsigned fl; + int fm; + fm = ec_decode_bin(dec, 15); + fl = 0; + if (fm >= fs) + { + val++; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP; + /* Search the decaying part of the PDF.*/ + while(fs > LAPLACE_MINP && fm >= fl+2*fs) + { + fs *= 2; + fl += fs; + fs = ((fs-2*LAPLACE_MINP)*(celt_int32)decay)>>15; + fs += LAPLACE_MINP; + val++; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= LAPLACE_MINP) + { + int di; + di = (fm-fl)>>(LAPLACE_LOG_MINP+1); + val += di; + fl += 2*di*LAPLACE_MINP; + } + if (fm < fl+fs) + val = -val; + else + fl += fs; + } + celt_assert(fl<32768); + celt_assert(fs>0); + celt_assert(fl<=fm); + celt_assert(fm + + + + Debug + Win32 + + + Release + Win32 + + + + {245603E3-F580-41A5-9632-B25FE3372CBF} + Win32Proj + libcelt + + + + StaticLibrary + true + Unicode + + + StaticLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + Level3 + Disabled + HAVE_CONFIG_H;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ..\msvc;%(AdditionalIncludeDirectories) + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + HAVE_CONFIG_H;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + ..\msvc;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/celt/libcelt/libcelt.vcxproj.filters b/native/codec/libraries/celt/libcelt/libcelt.vcxproj.filters new file mode 100644 index 0000000..904f0a4 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/libcelt.vcxproj.filters @@ -0,0 +1,153 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/native/codec/libraries/celt/libcelt/match-test.sh b/native/codec/libraries/celt/libcelt/match-test.sh new file mode 100755 index 0000000..f1714b2 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/match-test.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +#outfile=`mktemp` +#if [ $? != 0 ]; then +# echo "count not create temp output file" +# exit 0 +#fi +outfile=/dev/null + +if [ -f mono_test_file.sw ]; then + echo -n "mono test... " + ./testcelt 44100 1 256 32 mono_test_file.sw $outfile + if [ $? != 0 ]; then + exit 1 + fi +else + echo "no mono test file" +fi + +if [ -f stereo_test_file.sw ]; then + echo -n "stereo test... " + ./testcelt 44100 2 256 92 stereo_test_file.sw $outfile + if [ $? != 0 ]; then + exit 1 + fi +else + echo "no stereo test file" +fi + +exit 0 diff --git a/native/codec/libraries/celt/libcelt/mathops.c b/native/codec/libraries/celt/libcelt/mathops.c new file mode 100644 index 0000000..7852e1e --- /dev/null +++ b/native/codec/libraries/celt/libcelt/mathops.c @@ -0,0 +1,201 @@ +/* Copyright (c) 2002-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file mathops.h + @brief Various math functions +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" + +/*Compute floor(sqrt(_val)) with exact arithmetic. + This has been tested on all possible 32-bit inputs.*/ +unsigned isqrt32(celt_uint32 _val){ + unsigned b; + unsigned g; + int bshift; + /*Uses the second method from + http://www.azillionmonkeys.com/qed/sqroot.html + The main idea is to search for the largest binary digit b such that + (g+b)*(g+b) <= _val, and add it to the solution g.*/ + g=0; + bshift=EC_ILOG(_val)-1>>1; + b=1U<>=1; + bshift--; + } + while(bshift>=0); + return g; +} + +#ifdef FIXED_POINT + +celt_word32 frac_div32(celt_word32 a, celt_word32 b) +{ + celt_word16 rcp; + celt_word32 result, rem; + int shift = celt_ilog2(b)-29; + a = VSHR32(a,shift); + b = VSHR32(b,shift); + /* 16-bit reciprocal */ + rcp = ROUND16(celt_rcp(ROUND16(b,16)),3); + result = SHL32(MULT16_32_Q15(rcp, a),2); + rem = a-MULT32_32_Q31(result, b); + result += SHL32(MULT16_32_Q15(rcp, rem),2); + return result; +} + +/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */ +celt_word16 celt_rsqrt_norm(celt_word32 x) +{ + celt_word16 n; + celt_word16 r; + celt_word16 r2; + celt_word16 y; + /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */ + n = x-32768; + /* Get a rough initial guess for the root. + The optimal minimax quadratic approximation (using relative error) is + r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485). + Coefficients here, and the final result r, are Q14.*/ + r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713)))); + /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14. + We can compute the result from n and r using Q15 multiplies with some + adjustment, carefully done to avoid overflow. + Range of y is [-1564,1594]. */ + r2 = MULT16_16_Q15(r, r); + y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1); + /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5). + This yields the Q14 reciprocal square root of the Q16 x, with a maximum + relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a + peak absolute error of 2.26591/16384. */ + return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y, + SUB16(MULT16_16_Q15(y, 12288), 16384)))); +} + +/** Sqrt approximation (QX input, QX/2 output) */ +celt_word32 celt_sqrt(celt_word32 x) +{ + int k; + celt_word16 n; + celt_word32 rt; + static const celt_word16 C[5] = {23175, 11561, -3011, 1699, -664}; + if (x==0) + return 0; + k = (celt_ilog2(x)>>1)-7; + x = VSHR32(x, (k<<1)); + n = x-32768; + rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], + MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4]))))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static inline celt_word16 _celt_cos_pi_2(celt_word16 x) +{ + celt_word16 x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2 + )))))))); +} + +#undef L1 +#undef L2 +#undef L3 +#undef L4 + +celt_word16 celt_cos_norm(celt_word32 x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x0, "celt_rcp() only defined for positive values"); + i = celt_ilog2(x); + /* n is Q15 with range [0,1). */ + n = VSHR32(x,i-15)-32768; + /* Start with a linear approximation: + r = 1.8823529411764706-0.9411764705882353*n. + The coefficients and the result are Q14 in the range [15420,30840].*/ + r = ADD16(30840, MULT16_16_Q15(-15420, n)); + /* Perform two Newton iterations: + r -= r*((r*n)-1.Q15) + = r*((r*n)+(r-1.Q15)). */ + r = SUB16(r, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))); + /* We subtract an extra 1 in the second iteration to avoid overflow; it also + neatly compensates for truncation error in the rest of the process. */ + r = SUB16(r, ADD16(1, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))))); + /* r is now the Q15 solution to 2/(n+1), with a maximum relative error + of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute + error of 1.24665/32768. */ + return VSHR32(EXTEND32(r),i-16); +} + +#endif diff --git a/native/codec/libraries/celt/libcelt/mathops.h b/native/codec/libraries/celt/libcelt/mathops.h new file mode 100644 index 0000000..e1a0e83 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/mathops.h @@ -0,0 +1,234 @@ +/* Copyright (c) 2002-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file mathops.h + @brief Various math functions +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MATHOPS_H +#define MATHOPS_H + +#include "arch.h" +#include "entcode.h" +#include "os_support.h" + +/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ +#define FRAC_MUL16(a,b) ((16384+((celt_int32)(celt_int16)(a)*(celt_int16)(b)))>>15) + +unsigned isqrt32(celt_uint32 _val); + +#ifndef FIXED_POINT + +#define celt_sqrt(x) ((float)sqrt(x)) +#define celt_rsqrt(x) (1.f/celt_sqrt(x)) +#define celt_rsqrt_norm(x) (celt_rsqrt(x)) +#define celt_acos acos +#define celt_exp exp +#define celt_cos_norm(x) ((float)cos((.5f*M_PI)*(x))) +#define celt_atan atan +#define celt_rcp(x) (1.f/(x)) +#define celt_div(a,b) ((a)/(b)) +#define frac_div32(a,b) ((float)(a)/(b)) + +#ifdef FLOAT_APPROX + +/* Note: This assumes radix-2 floating point with the exponent at bits 23..30 and an offset of 127 + denorm, +/- inf and NaN are *not* handled */ + +/** Base-2 log approximation (log2(x)). */ +static inline float celt_log2(float x) +{ + int integer; + float frac; + union { + float f; + celt_uint32 i; + } in; + in.f = x; + integer = (in.i>>23)-127; + in.i -= integer<<23; + frac = in.f - 1.5f; + frac = -0.41445418f + frac*(0.95909232f + + frac*(-0.33951290f + frac*0.16541097f)); + return 1+integer+frac; +} + +/** Base-2 exponential approximation (2^x). */ +static inline float celt_exp2(float x) +{ + int integer; + float frac; + union { + float f; + celt_uint32 i; + } res; + integer = floor(x); + if (integer < -50) + return 0; + frac = x-integer; + /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ + res.f = 0.99992522f + frac * (0.69583354f + + frac * (0.22606716f + 0.078024523f*frac)); + res.i = (res.i + (integer<<23)) & 0x7fffffff; + return res.f; +} + +#else +#define celt_log2(x) ((float)(1.442695040888963387*log(x))) +#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x))) +#endif + +#endif + + + +#ifdef FIXED_POINT + +#include "os_support.h" + +#ifndef OVERRIDE_CELT_ILOG2 +/** Integer log in base2. Undefined for zero and negative numbers */ +static inline celt_int16 celt_ilog2(celt_int32 x) +{ + celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers"); + return EC_ILOG(x)-1; +} +#endif + + +#ifndef OVERRIDE_CELT_MAXABS16 +static inline celt_word16 celt_maxabs16(celt_word16 *x, int len) +{ + int i; + celt_word16 maxval = 0; + for (i=0;i14) + return 0x7f000000; + else if (integer < -15) + return 0; + frac = SHL16(x-SHL16(integer,10),4); + frac = ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac)))))); + return VSHR32(EXTEND32(frac), -integer-2); +} + +celt_word32 celt_rcp(celt_word32 x); + +#define celt_div(a,b) MULT32_32_Q31((celt_word32)(a),celt_rcp(b)) + +celt_word32 frac_div32(celt_word32 a, celt_word32 b); + +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +/* Atan approximation using a 4th order polynomial. Input is in Q15 format + and normalized by pi/4. Output is in Q15 format */ +static inline celt_word16 celt_atan01(celt_word16 x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* atan2() approximation valid for positive input values */ +static inline celt_word16 celt_atan2p(celt_word16 y, celt_word16 x) +{ + if (y < x) + { + celt_word32 arg; + arg = celt_div(SHL32(EXTEND32(y),15),x); + if (arg >= 32767) + arg = 32767; + return SHR16(celt_atan01(EXTRACT16(arg)),1); + } else { + celt_word32 arg; + arg = celt_div(SHL32(EXTEND32(x),15),y); + if (arg >= 32767) + arg = 32767; + return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1); + } +} + +#endif /* FIXED_POINT */ + + +#endif /* MATHOPS_H */ diff --git a/native/codec/libraries/celt/libcelt/mdct.c b/native/codec/libraries/celt/libcelt/mdct.c new file mode 100644 index 0000000..0242489 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/mdct.c @@ -0,0 +1,333 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifdef CUSTOM_MODES + +void clt_mdct_init(mdct_lookup *l,int N, int maxshift) +{ + int i; + int N4, N2; + kiss_twiddle_scalar *trig; + l->n = N; + N2 = N>>1; + N4 = N>>2; + l->maxshift = maxshift; + for (i=0;i<=maxshift;i++) + { + if (i==0) + l->kfft[i] = kiss_fft_alloc(N>>2>>i, 0, 0); + else + l->kfft[i] = kiss_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0]); +#ifndef ENABLE_TI_DSPLIB55 + if (l->kfft[i]==NULL) + return; +#endif + } + l->trig = trig = (kiss_twiddle_scalar*)celt_alloc((N4+1)*sizeof(kiss_twiddle_scalar)); + if (l->trig==NULL) + return; + /* We have enough points that sine isn't necessary */ +#if defined(FIXED_POINT) + for (i=0;i<=N4;i++) + trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2),N)); +#else + for (i=0;i<=N4;i++) + trig[i] = (kiss_twiddle_scalar)cos(2*M_PI*i/N); +#endif +} + +void clt_mdct_clear(mdct_lookup *l) +{ + int i; + for (i=0;i<=l->maxshift;i++) + kiss_fft_free(l->kfft[i]); + celt_free((kiss_twiddle_scalar*)l->trig); +} + +#endif /* CUSTOM_MODES */ + +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * restrict out, const celt_word16 *window, int overlap, int shift) +{ + int i; + int N, N2, N4; + kiss_twiddle_scalar sine; + VARDECL(kiss_fft_scalar, f); + SAVE_STACK; + N = l->n; + N >>= shift; + N2 = N>>1; + N4 = N>>2; + ALLOC(f, N2, kiss_fft_scalar); + /* sin(x) ~= x here */ +#ifdef FIXED_POINT + sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N; +#else + sine = (kiss_twiddle_scalar)2*M_PI*(.125f)/N; +#endif + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * restrict xp1 = in+(overlap>>1); + const kiss_fft_scalar * restrict xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * restrict yp = out; + const celt_word16 * restrict wp1 = window+(overlap>>1); + const celt_word16 * restrict wp2 = window+(overlap>>1)-1; + for(i=0;i<(overlap>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;itrig[0]; + for(i=0;ikfft[shift], (kiss_fft_cpx *)out, (kiss_fft_cpx *)f); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * restrict fp = f; + kiss_fft_scalar * restrict yp1 = out; + kiss_fft_scalar * restrict yp2 = out+N2-1; + const kiss_twiddle_scalar *t = &l->trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;in; + N >>= shift; + N2 = N>>1; + N4 = N>>2; + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N2, kiss_fft_scalar); + /* sin(x) ~= x here */ +#ifdef FIXED_POINT + sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N; +#else + sine = (kiss_twiddle_scalar)2*M_PI*(.125f)/N; +#endif + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * restrict xp1 = in; + const kiss_fft_scalar * restrict xp2 = in+N2-1; + kiss_fft_scalar * restrict yp = f2; + const kiss_twiddle_scalar *t = &l->trig[0]; + for(i=0;ikfft[shift], (kiss_fft_cpx *)f2, (kiss_fft_cpx *)f); + + /* Post-rotate */ + { + kiss_fft_scalar * restrict fp = f; + const kiss_twiddle_scalar *t = &l->trig[0]; + + for(i=0;i>1; + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * restrict fp1 = f2+N4-1; + kiss_fft_scalar * restrict xp1 = out+N2-1; + kiss_fft_scalar * restrict yp1 = out+N4-overlap/2; + const celt_word16 * restrict wp1 = window; + const celt_word16 * restrict wp2 = window+overlap-1; + for(i = 0; i< N4-overlap/2; i++) + { + *xp1 = *fp1; + xp1--; + fp1--; + } + for(; i < N4; i++) + { + kiss_fft_scalar x1; + x1 = *fp1--; + *yp1++ +=-MULT16_32_Q15(*wp1, x1); + *xp1-- += MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } + { + kiss_fft_scalar * restrict fp2 = f2+N4; + kiss_fft_scalar * restrict xp2 = out+N2; + kiss_fft_scalar * restrict yp2 = out+N-1-(N4-overlap/2); + const celt_word16 * restrict wp1 = window; + const celt_word16 * restrict wp2 = window+overlap-1; + for(i = 0; i< N4-overlap/2; i++) + { + *xp2 = *fp2; + xp2++; + fp2++; + } + for(; i < N4; i++) + { + kiss_fft_scalar x2; + x2 = *fp2++; + *yp2-- = MULT16_32_Q15(*wp1, x2); + *xp2++ = MULT16_32_Q15(*wp2, x2); + wp1++; + wp2--; + } + } + RESTORE_STACK; +} + + diff --git a/native/codec/libraries/celt/libcelt/mdct.h b/native/codec/libraries/celt/libcelt/mdct.h new file mode 100644 index 0000000..752c194 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/mdct.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef MDCT_H +#define MDCT_H + +#include "kiss_fft.h" +#include "arch.h" + +typedef struct { + int n; + int maxshift; + const kiss_fft_state *kfft[4]; + const kiss_twiddle_scalar * restrict trig; +} mdct_lookup; + +void clt_mdct_init(mdct_lookup *l,int N, int maxshift); +void clt_mdct_clear(mdct_lookup *l); + +/** Compute a forward MDCT and scale by 4/N */ +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar *out, const celt_word16 *window, int overlap, int shift); + +/** Compute a backward MDCT (no scaling) and performs weighted overlap-add + (scales implicitly by 1/2) */ +void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar *out, const celt_word16 * restrict window, int overlap, int shift); + +#endif diff --git a/native/codec/libraries/celt/libcelt/mfrngcod.h b/native/codec/libraries/celt/libcelt/mfrngcod.h new file mode 100644 index 0000000..5e7a5bb --- /dev/null +++ b/native/codec/libraries/celt/libcelt/mfrngcod.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2001-2008 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_mfrngcode_H) +# define _mfrngcode_H (1) +# include "entcode.h" + +/*Constants used by the entropy encoder/decoder.*/ + +/*The number of bits to output at a time.*/ +# define EC_SYM_BITS (8) +/*The total number of bits in each of the state registers.*/ +# define EC_CODE_BITS (32) +/*The maximum symbol value.*/ +# define EC_SYM_MAX ((1U<>EC_SYM_BITS) +/*Code for which propagating carries are possible.*/ +# define EC_CODE_CARRY (((celt_uint32)EC_SYM_MAX)<= Fs) + break; + + /* Find where the linear part ends (i.e. where the spacing is more than min_width */ + for (lin=0;lin= res) + break; + + low = (bark_freq[lin]+res/2)/res; + high = nBark-lin; + *nbEBands = low+high; + eBands = celt_alloc(sizeof(celt_int16)*(*nbEBands+2)); + + if (eBands==NULL) + return NULL; + + /* Linear spacing (min_width) */ + for (i=0;i0) + offset = eBands[low-1]*res - bark_freq[lin-1]; + /* Spacing follows critical bands */ + for (i=0;i frame_size) + eBands[*nbEBands] = frame_size; + for (i=1;i<*nbEBands-1;i++) + { + if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1]) + { + eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2; + } + } + /* Remove any empty bands. */ + for (i=j=0;i<*nbEBands;i++) + if(eBands[i+1]>eBands[j]) + eBands[++j]=eBands[i+1]; + *nbEBands=j; + + for (i=1;i<*nbEBands;i++) + { + /* Every band must be smaller than the last band. */ + celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]); + /* Each band must be no larger than twice the size of the previous one. */ + celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1])); + } + + return eBands; +} + +static void compute_allocation_table(CELTMode *mode) +{ + int i, j; + unsigned char *allocVectors; + int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + + mode->nbAllocVectors = BITALLOC_SIZE; + allocVectors = celt_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands)); + if (allocVectors==NULL) + return; + + /* Check for standard mode */ + if (mode->Fs == 400*(celt_int32)mode->shortMdctSize) + { + for (i=0;inbEBands;i++) + allocVectors[i] = band_allocation[i]; + mode->allocVectors = allocVectors; + return; + } + /* If not the standard mode, interpolate */ + /* Compute per-codec-band allocation from per-critical-band matrix */ + for (i=0;inbEBands;j++) + { + int k; + for (k=0;k mode->eBands[j]*(celt_int32)mode->Fs/mode->shortMdctSize) + break; + } + if (k>maxBands-1) + allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1]; + else { + celt_int32 a0, a1; + a1 = mode->eBands[j]*(celt_int32)mode->Fs/mode->shortMdctSize - 400*(celt_int32)eband5ms[k-1]; + a0 = 400*(celt_int32)eband5ms[k] - mode->eBands[j]*(celt_int32)mode->Fs/mode->shortMdctSize; + allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1] + + a1*band_allocation[i*maxBands+k])/(a0+a1); + } + } + } + + /*printf ("\n"); + for (i=0;inbEBands;j++) + printf ("%d ", allocVectors[i*mode->nbEBands+j]); + printf ("\n"); + } + exit(0);*/ + + mode->allocVectors = allocVectors; +} + +#endif /* CUSTOM_MODES */ + +CELTMode *celt_mode_create(celt_int32 Fs, int frame_size, int *error) +{ + int i; +#ifdef CUSTOM_MODES + CELTMode *mode=NULL; + int res; + celt_word16 *window; + celt_int16 *logN; + int LM; + ALLOC_STACK; +#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA) + if (global_stack==NULL) + goto failure; +#endif +#endif + +#ifndef CUSTOM_MODES_ONLY + for (i=0;iFs && + (frame_size<shortMdctSize*static_mode_list[i]->nbShortMdcts) + { + if (error) + *error = CELT_OK; + return (CELTMode*)static_mode_list[i]; + } + } + } +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef CUSTOM_MODES + if (error) + *error = CELT_BAD_ARG; + return NULL; +#else + + /* The good thing here is that permutation of the arguments will automatically be invalid */ + + if (Fs < 8000 || Fs > 96000) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + /* Frames of less than 1ms are not supported. */ + if ((celt_int32)frame_size*1000 < Fs) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + + if ((celt_int32)frame_size*75 >= Fs && (frame_size%16)==0) + { + LM = 3; + } else if ((celt_int32)frame_size*150 >= Fs && (frame_size%8)==0) + { + LM = 2; + } else if ((celt_int32)frame_size*300 >= Fs && (frame_size%4)==0) + { + LM = 1; + } else + { + LM = 0; + } + + /* Shorts longer than 3.3ms are not supported. */ + if ((celt_int32)(frame_size>>LM)*300 > Fs) + { + if (error) + *error = CELT_BAD_ARG; + return NULL; + } + + mode = celt_alloc(sizeof(CELTMode)); + if (mode==NULL) + goto failure; + mode->Fs = Fs; + + /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis + is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should + approximate that. */ + if(Fs < 12000) /* 8 kHz */ + { + mode->preemph[0] = QCONST16(0.3500061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(3.6765136719f, 13); + } else if(Fs < 24000) /* 16 kHz */ + { + mode->preemph[0] = QCONST16(0.6000061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(2.2598876953f, 13); + } else if(Fs < 40000) /* 32 kHz */ + { + mode->preemph[0] = QCONST16(0.7799987793f, 15); + mode->preemph[1] = -QCONST16(0.1000061035f, 15); + mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(1.3333740234f, 13); + } else /* 48 kHz */ + { + mode->preemph[0] = QCONST16(0.8500061035f, 15); + mode->preemph[1] = QCONST16(0.0f, 15); + mode->preemph[2] = QCONST16(1.f, SIG_SHIFT); + mode->preemph[3] = QCONST16(1.f, 13); + } + + mode->maxLM = LM; + mode->nbShortMdcts = 1<shortMdctSize = frame_size/mode->nbShortMdcts; + res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize); + + mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands); + if (mode->eBands==NULL) + goto failure; + + mode->effEBands = mode->nbEBands; + while (mode->eBands[mode->effEBands] > mode->shortMdctSize) + mode->effEBands--; + + /* Overlap must be divisible by 4 */ + mode->overlap = ((mode->shortMdctSize>>2)<<2); + + compute_allocation_table(mode); + if (mode->allocVectors==NULL) + goto failure; + + window = (celt_word16*)celt_alloc(mode->overlap*sizeof(celt_word16)); + if (window==NULL) + goto failure; + +#ifndef FIXED_POINT + for (i=0;ioverlap;i++) + window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)); +#else + for (i=0;ioverlap;i++) + window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)))); +#endif + mode->window = window; + + logN = (celt_int16*)celt_alloc(mode->nbEBands*sizeof(celt_int16)); + if (logN==NULL) + goto failure; + + for (i=0;inbEBands;i++) + logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES); + mode->logN = logN; + + compute_pulse_cache(mode, mode->maxLM); + + clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts, mode->maxLM); + if ((mode->mdct.trig==NULL) +#ifndef ENABLE_TI_DSPLIB55 + || (mode->mdct.kfft==NULL) +#endif + ) + goto failure; + + if (error) + *error = CELT_OK; + + return mode; +failure: + if (error) + *error = CELT_ALLOC_FAIL; + if (mode!=NULL) + celt_mode_destroy(mode); + return NULL; +#endif /* !CUSTOM_MODES */ +} + +void celt_mode_destroy(CELTMode *mode) +{ +#ifdef CUSTOM_MODES + int i; + if (mode == NULL) + return; +#ifndef CUSTOM_MODES_ONLY + for (i=0;ieBands); + celt_free((celt_int16*)mode->allocVectors); + + celt_free((celt_word16*)mode->window); + celt_free((celt_int16*)mode->logN); + + celt_free((celt_int16*)mode->cache.index); + celt_free((unsigned char*)mode->cache.bits); + celt_free((unsigned char*)mode->cache.caps); + clt_mdct_clear(&mode->mdct); + + celt_free((CELTMode *)mode); +#endif +} diff --git a/native/codec/libraries/celt/libcelt/modes.h b/native/codec/libraries/celt/libcelt/modes.h new file mode 100644 index 0000000..9e0384e --- /dev/null +++ b/native/codec/libraries/celt/libcelt/modes.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MODES_H +#define MODES_H + +#include "celt_types.h" +#include "celt.h" +#include "arch.h" +#include "mdct.h" +#include "entenc.h" +#include "entdec.h" + +#define CELT_BITSTREAM_VERSION 0x80000010 + +#define MAX_PERIOD 1024 + +#ifndef CHANNELS +# ifdef DISABLE_STEREO +# define CHANNELS(_C) (1) +# else +# define CHANNELS(_C) (_C) +# endif +#endif + +#ifndef OVERLAP +#define OVERLAP(mode) ((mode)->overlap) +#endif + +#ifndef FRAMESIZE +#define FRAMESIZE(mode) ((mode)->mdctSize) +#endif + +typedef struct { + int size; + const celt_int16 *index; + const unsigned char *bits; + const unsigned char *caps; +} PulseCache; + +/** Mode definition (opaque) + @brief Mode definition + */ +struct CELTMode { + celt_int32 Fs; + int overlap; + + int nbEBands; + int effEBands; + celt_word16 preemph[4]; + const celt_int16 *eBands; /**< Definition for each "pseudo-critical band" */ + + int nbAllocVectors; /**< Number of lines in the matrix below */ + const unsigned char *allocVectors; /**< Number of bits in each band for several rates */ + + /* Stuff that could go in the {en,de}coder, but we save space this way */ + mdct_lookup mdct; + + const celt_word16 *window; + + int maxLM; + int nbShortMdcts; + int shortMdctSize; + + const celt_int16 *logN; + + PulseCache cache; +}; + +#ifndef OPUS_BUILD +#define CELT_STATIC static +#else +#define CELT_STATIC +#endif + +#ifdef OPUS_BUILD +#define CELT_SET_SIGNALLING_REQUEST 10003 +#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, _celt_check_int(x) + +#define CELT_GET_MODE_REQUEST 10004 +/** Get the CELTMode used by an encoder or decoder */ +#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, _celt_check_mode_ptr_ptr(x) + +/* Prototypes for _ec versions of the encoder/decoder calls (not public) */ +int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); +int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); +int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, celt_int16 * restrict pcm, int frame_size, ec_dec *dec); +int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size, ec_dec *dec); +#endif /* OPUS_BUILD */ + +#endif diff --git a/native/codec/libraries/celt/libcelt/os_support.h b/native/codec/libraries/celt/libcelt/os_support.h new file mode 100644 index 0000000..ada0887 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/os_support.h @@ -0,0 +1,101 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#ifdef CUSTOM_SUPPORT +# include "custom_support.h" +#endif + +#include +#include +#include + +/** CELT wrapper for calloc(). To do your own dynamic allocation, all you need to do is replace this function, celt_realloc and celt_free + NOTE: celt_alloc needs to CLEAR THE MEMORY */ +#ifndef OVERRIDE_CELT_ALLOC +static inline void *celt_alloc (int size) +{ + /* WARNING: this is not equivalent to malloc(). If you want to use malloc() + or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise + you will experience strange bugs */ + return calloc(size,1); +} +#endif + +/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ +#ifndef OVERRIDE_CELT_ALLOC_SCRATCH +static inline void *celt_alloc_scratch (int size) +{ + /* Scratch space doesn't need to be cleared */ + return calloc(size,1); +} +#endif + +/** CELT wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function, celt_realloc and celt_alloc */ +#ifndef OVERRIDE_CELT_FREE +static inline void celt_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Same as celt_free(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ +#ifndef OVERRIDE_CELT_FREE_SCRATCH +static inline void celt_free_scratch (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_CELT_COPY +#define CELT_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_CELT_MOVE +#define CELT_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n bytes of memory to value of c, starting at address s */ +#ifndef OVERRIDE_CELT_MEMSET +#define CELT_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst)))) +#endif + +/*#ifdef __GNUC__ +#pragma GCC poison printf sprintf +#pragma GCC poison malloc free realloc calloc +#endif*/ + +#endif /* OS_SUPPORT_H */ + diff --git a/native/codec/libraries/celt/libcelt/pitch.c b/native/codec/libraries/celt/libcelt/pitch.c new file mode 100644 index 0000000..052f76f --- /dev/null +++ b/native/codec/libraries/celt/libcelt/pitch.c @@ -0,0 +1,373 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.c + @brief Pitch analysis + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Always enable postfilter for Opus */ +#if defined(OPUS_BUILD) && !defined(ENABLE_POSTFILTER) +#define ENABLE_POSTFILTER +#endif + +#include "pitch.h" +#include "os_support.h" +#include "modes.h" +#include "stack_alloc.h" +#include "mathops.h" + +static void find_best_pitch(celt_word32 *xcorr, celt_word32 maxcorr, celt_word16 *y, + int yshift, int len, int max_pitch, int best_pitch[2]) +{ + int i, j; + celt_word32 Syy=1; + celt_word16 best_num[2]; + celt_word32 best_den[2]; +#ifdef FIXED_POINT + int xshift; + + xshift = celt_ilog2(maxcorr)-14; +#endif + + best_num[0] = -1; + best_num[1] = -1; + best_den[0] = 0; + best_den[1] = 0; + best_pitch[0] = 0; + best_pitch[1] = 1; + for (j=0;j0) + { + celt_word16 num; + celt_word32 xcorr16; + xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift)); + num = MULT16_16_Q15(xcorr16,xcorr16); + if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy)) + { + if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy)) + { + best_num[1] = best_num[0]; + best_den[1] = best_den[0]; + best_pitch[1] = best_pitch[0]; + best_num[0] = num; + best_den[0] = Syy; + best_pitch[0] = i; + } else { + best_num[1] = num; + best_den[1] = Syy; + best_pitch[1] = i; + } + } + } + Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift); + Syy = MAX32(1, Syy); + } +} + +#include "plc.h" +void pitch_downsample(celt_sig * restrict x[], celt_word16 * restrict x_lp, + int len, int _C) +{ + int i; + celt_word32 ac[5]; + celt_word16 tmp=Q15ONE; + celt_word16 lpc[4], mem[4]={0,0,0,0}; + const int C = CHANNELS(_C); + for (i=1;i>1;i++) + x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), SIG_SHIFT+3); + x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), SIG_SHIFT+3); + if (C==2) + { + for (i=1;i>1;i++) + x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), SIG_SHIFT+3); + x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), SIG_SHIFT+3); + } + + _celt_autocorr(x_lp, ac, NULL, 0, + 4, len>>1); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=4;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc, ac, 4); + for (i=0;i<4;i++) + { + tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp); + lpc[i] = MULT16_16_Q15(lpc[i], tmp); + } + fir(x_lp, lpc, x_lp, len>>1, 4, mem); + + mem[0]=0; + lpc[0]=QCONST16(.8f,12); + fir(x_lp, lpc, x_lp, len>>1, 1, mem); + +} + +void pitch_search(const celt_word16 * restrict x_lp, celt_word16 * restrict y, + int len, int max_pitch, int *pitch) +{ + int i, j; + int lag; + int best_pitch[2]={0}; + VARDECL(celt_word16, x_lp4); + VARDECL(celt_word16, y_lp4); + VARDECL(celt_word32, xcorr); + celt_word32 maxcorr=1; + int offset; + int shift=0; + + SAVE_STACK; + + lag = len+max_pitch; + + ALLOC(x_lp4, len>>2, celt_word16); + ALLOC(y_lp4, lag>>2, celt_word16); + ALLOC(xcorr, max_pitch>>1, celt_word32); + + /* Downsample by 2 again */ + for (j=0;j>2;j++) + x_lp4[j] = x_lp[2*j]; + for (j=0;j>2;j++) + y_lp4[j] = y[2*j]; + +#ifdef FIXED_POINT + shift = celt_ilog2(MAX16(1, MAX16(celt_maxabs16(x_lp4, len>>2), celt_maxabs16(y_lp4, lag>>2))))-11; + if (shift>0) + { + for (j=0;j>2;j++) + x_lp4[j] = SHR16(x_lp4[j], shift); + for (j=0;j>2;j++) + y_lp4[j] = SHR16(y_lp4[j], shift); + /* Use double the shift for a MAC */ + shift *= 2; + } else { + shift = 0; + } +#endif + + /* Coarse search with 4x decimation */ + + for (i=0;i>2;i++) + { + celt_word32 sum = 0; + for (j=0;j>2;j++) + sum = MAC16_16(sum, x_lp4[j],y_lp4[i+j]); + xcorr[i] = MAX32(-1, sum); + maxcorr = MAX32(maxcorr, sum); + } + find_best_pitch(xcorr, maxcorr, y_lp4, 0, len>>2, max_pitch>>2, best_pitch); + + /* Finer search with 2x decimation */ + maxcorr=1; + for (i=0;i>1;i++) + { + celt_word32 sum=0; + xcorr[i] = 0; + if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2) + continue; + for (j=0;j>1;j++) + sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift); + xcorr[i] = MAX32(-1, sum); + maxcorr = MAX32(maxcorr, sum); + } + find_best_pitch(xcorr, maxcorr, y, shift, len>>1, max_pitch>>1, best_pitch); + + /* Refine by pseudo-interpolation */ + if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1) + { + celt_word32 a, b, c; + a = xcorr[best_pitch[0]-1]; + b = xcorr[best_pitch[0]]; + c = xcorr[best_pitch[0]+1]; + if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a)) + offset = 1; + else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c)) + offset = -1; + else + offset = 0; + } else { + offset = 0; + } + *pitch = 2*best_pitch[0]-offset; + + RESTORE_STACK; +} + +#ifdef ENABLE_POSTFILTER +static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; +celt_word16 remove_doubling(celt_word16 *x, int maxperiod, int minperiod, + int N, int *_T0, int prev_period, celt_word16 prev_gain) +{ + int k, i, T, T0; + celt_word16 g, g0; + celt_word16 pg; + celt_word32 xy,xx,yy; + celt_word32 xcorr[3]; + celt_word32 best_xy, best_yy; + int offset; + int minperiod0; + + minperiod0 = minperiod; + maxperiod /= 2; + minperiod /= 2; + *_T0 /= 2; + prev_period /= 2; + N /= 2; + x += maxperiod; + if (*_T0>=maxperiod) + *_T0=maxperiod-1; + + T = T0 = *_T0; + xx=xy=yy=0; + for (i=0;i>1; + t = VSHR32(x2y2, 2*(sh-7)); + g = g0 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1); + } +#else + g = g0 = xy/sqrt(1+xx*yy); +#endif + /* Look for any pitch at T/k */ + for (k=2;k<=15;k++) + { + int T1, T1b; + celt_word16 g1; + celt_word16 cont=0; + T1 = (2*T0+k)/(2*k); + if (T1 < minperiod) + break; + /* Look for another strong correlation at T1b */ + if (k==2) + { + if (T1+T0>maxperiod) + T1b = T0; + else + T1b = T0+T1; + } else + { + T1b = (2*second_check[k]*T0+k)/(2*k); + } + xy=yy=0; + for (i=0;i>1; + t = VSHR32(x2y2, 2*(sh-7)); + g1 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1); + } +#else + g1 = xy/sqrt(1+2.f*xx*1.f*yy); +#endif + if (abs(T1-prev_period)<=1) + cont = prev_gain; + else if (abs(T1-prev_period)<=2 && 5*k*k < T0) + cont = HALF32(prev_gain); + else + cont = 0; + if (g1 > QCONST16(.3f,15) + MULT16_16_Q15(QCONST16(.4f,15),g0)-cont) + { + best_xy = xy; + best_yy = yy; + T = T1; + g = g1; + } + } + if (best_yy <= best_xy) + pg = Q15ONE; + else + pg = SHR32(frac_div32(best_xy,best_yy+1),16); + + for (k=0;k<3;k++) + { + int T1 = T+k-1; + xy = 0; + for (i=0;i MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0])) + offset = 1; + else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2])) + offset = -1; + else + offset = 0; + if (pg > g) + pg = g; + *_T0 = 2*T+offset; + + if (*_T0>1; j++) + { + celt_word32 tmp1, tmp2; + tmp1 = lpc[j]; + tmp2 = lpc[i-1-j]; + lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2); + lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1); + } + + error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error); + /* Bail out once we get 30 dB gain */ +#ifdef FIXED_POINT + if (error=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = x[i]; + y[i] = ROUND16(sum, SIG_SHIFT); + } +} + +void iir(const celt_word32 *x, + const celt_word16 *den, + celt_word32 *y, + int N, + int ord, + celt_word16 *mem) +{ + int i,j; + for (i=0;i=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = ROUND16(sum,SIG_SHIFT); + y[i] = sum; + } +} + +void _celt_autocorr( + const celt_word16 *x, /* in: [0...n-1] samples x */ + celt_word32 *ac, /* out: [0...lag-1] ac values */ + const celt_word16 *window, + int overlap, + int lag, + int n + ) +{ + celt_word32 d; + int i; + VARDECL(celt_word16, xx); + SAVE_STACK; + ALLOC(xx, n, celt_word16); + for (i=0;i=0) + { + for (i = lag, d = 0; i < n; i++) + d += xx[i] * xx[i-lag]; + ac[lag] = d; + /*printf ("%f ", ac[lag]);*/ + lag--; + } + /*printf ("\n");*/ + ac[0] += 10; + + RESTORE_STACK; +} diff --git a/native/codec/libraries/celt/libcelt/plc.h b/native/codec/libraries/celt/libcelt/plc.h new file mode 100644 index 0000000..70a5ba2 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/plc.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PLC_H +#define PLC_H + +#include "arch.h" + +#define LPC_ORDER 24 + +void _celt_lpc(celt_word16 *_lpc, const celt_word32 *ac, int p); + +void fir(const celt_word16 *x, + const celt_word16 *num, + celt_word16 *y, + int N, + int ord, + celt_word16 *mem); + +void iir(const celt_word32 *x, + const celt_word16 *den, + celt_word32 *y, + int N, + int ord, + celt_word16 *mem); + + +void _celt_autocorr(const celt_word16 *x, celt_word32 *ac, const celt_word16 *window, int overlap, int lag, int n); + + +#endif /* PLC_H */ diff --git a/native/codec/libraries/celt/libcelt/quant_bands.c b/native/codec/libraries/celt/libcelt/quant_bands.c new file mode 100644 index 0000000..f33bf3f --- /dev/null +++ b/native/codec/libraries/celt/libcelt/quant_bands.c @@ -0,0 +1,574 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "quant_bands.h" +#include "laplace.h" +#include +#include "os_support.h" +#include "arch.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "rate.h" + +#ifdef FIXED_POINT +/* Mean energy in each band quantized in Q6 */ +static const signed char eMeans[25] = { + 103,100, 92, 85, 81, + 77, 72, 70, 78, 75, + 73, 71, 78, 74, 69, + 72, 70, 74, 76, 71, + 60, 60, 60, 60, 60 +}; +#else +/* Mean energy in each band quantized in Q6 and converted back to float */ +static const celt_word16 eMeans[25] = { + 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, + 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, + 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, + 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f, + 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f +}; +#endif +/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */ +#ifdef FIXED_POINT +static const celt_word16 pred_coef[4] = {29440, 26112, 21248, 16384}; +static const celt_word16 beta_coef[4] = {30147, 22282, 12124, 6554}; +static const celt_word16 beta_intra = 4915; +#else +static const celt_word16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.}; +static const celt_word16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.}; +static const celt_word16 beta_intra = 4915/32768.; +#endif + +/*Parameters of the Laplace-like probability models used for the coarse energy. + There is one pair of parameters for each frame size, prediction type + (inter/intra), and band number. + The first number of each pair is the probability of 0, and the second is the + decay rate, both in Q8 precision.*/ +static const unsigned char e_prob_model[4][2][42] = { + /*120 sample frames.*/ + { + /*Inter*/ + { + 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, + 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, + 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11 + }, + /*Intra*/ + { + 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, + 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, + 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50 + } + }, + /*240 sample frames.*/ + { + /*Inter*/ + { + 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, + 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, + 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9 + }, + /*Intra*/ + { + 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, + 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, + 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45 + } + }, + /*480 sample frames.*/ + { + /*Inter*/ + { + 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, + 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, + 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10 + }, + /*Intra*/ + { + 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, + 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, + 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42 + } + }, + /*960 sample frames.*/ + { + /*Inter*/ + { + 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, + 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, + 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15 + }, + /*Intra*/ + { + 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, + 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, + 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40 + } + } +}; + +static const unsigned char small_energy_icdf[3]={2,1,0}; + +static celt_word32 loss_distortion(const celt_word16 *eBands, celt_word16 *oldEBands, int start, int end, int len, int C) +{ + int c, i; + celt_word32 dist = 0; + c=0; do { + for (i=start;inbEBands]; + oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); +#ifdef FIXED_POINT + f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7); + decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT), + SUB32((celt_word32)oldEBands[i+c*m->nbEBands],max_decay))); +#else + f = x-coef*oldE-prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (int)floor(.5f+f); + decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay; +#endif + /* Prevent the energy from going down too quickly (e.g. for bands + that have just one bin) */ + if (qi < 0 && x < decay_bound) + { + qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT); + if (qi > 0) + qi = 0; + } + qi0 = qi; + /* If we don't have enough bits to encode all the energy, just assume + something safe. */ + tell = ec_tell(enc); + bits_left = budget-tell-3*C*(end-i); + if (i!=start && bits_left < 30) + { + if (bits_left < 24) + qi = IMIN(1, qi); + if (bits_left < 16) + qi = IMAX(-1, qi); + } + if (budget-tell >= 15) + { + int pi; + pi = 2*IMIN(i,20); + ec_laplace_encode(enc, &qi, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell >= 2) + { + qi = IMAX(-1, IMIN(qi, 1)); + ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2); + } + else if(budget-tell >= 1) + { + qi = IMIN(0, qi); + ec_enc_bit_logp(enc, -qi, 1); + } + else + qi = -1; + error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT); + badness += abs(qi0-qi); + q = SHL32(EXTEND32(qi),DB_SHIFT); + + tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } + return badness; +} + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const celt_word16 *eBands, celt_word16 *oldEBands, celt_uint32 budget, + celt_word16 *error, ec_enc *enc, int _C, int LM, int nbAvailableBytes, + int force_intra, celt_word32 *delayedIntra, int two_pass, int loss_rate) +{ + const int C = CHANNELS(_C); + int intra; + celt_word16 max_decay; + VARDECL(celt_word16, oldEBands_intra); + VARDECL(celt_word16, error_intra); + ec_enc enc_start_state; + celt_uint32 tell; + int badness1=0; + celt_int32 intra_bias; + celt_word32 new_distortion; + SAVE_STACK; + + intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C); + intra_bias = ((budget**delayedIntra*loss_rate)/(C*512)); + new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C); + + tell = ec_tell(enc); + if (tell+3 > budget) + two_pass = intra = 0; + + /* Encode the global flags using a simple probability model + (first symbols in the stream) */ + +#ifdef FIXED_POINT + max_decay = MIN32(QCONST16(16.f,DB_SHIFT), SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3)); +#else + max_decay = MIN32(16.f, .125f*nbAvailableBytes); +#endif + + enc_start_state = *enc; + + ALLOC(oldEBands_intra, C*m->nbEBands, celt_word16); + ALLOC(error_intra, C*m->nbEBands, celt_word16); + CELT_COPY(oldEBands_intra, oldEBands, C*m->nbEBands); + + if (two_pass || intra) + { + badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget, + tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay); + } + + if (!intra) + { + ec_enc enc_intra_state; + int tell_intra; + celt_uint32 nstart_bytes; + celt_uint32 nintra_bytes; + int badness2; + VARDECL(unsigned char, intra_bits); + + tell_intra = ec_tell_frac(enc); + + enc_intra_state = *enc; + + nstart_bytes = ec_range_bytes(&enc_start_state); + nintra_bytes = ec_range_bytes(&enc_intra_state); + ALLOC(intra_bits, nintra_bytes-nstart_bytes, unsigned char); + /* Copy bits from intra bit-stream */ + CELT_COPY(intra_bits, + ec_get_buffer(&enc_intra_state) + nstart_bytes, + nintra_bytes - nstart_bytes); + + *enc = enc_start_state; + + badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget, + tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay); + + if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ec_tell_frac(enc)+intra_bias > tell_intra))) + { + *enc = enc_intra_state; + /* Copy intra bits to bit-stream */ + CELT_COPY(ec_get_buffer(&enc_intra_state) + nstart_bytes, + intra_bits, nintra_bytes - nstart_bytes); + CELT_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + CELT_COPY(error, error_intra, C*m->nbEBands); + intra = 1; + } + } else { + CELT_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + CELT_COPY(error, error_intra, C*m->nbEBands); + } + + if (intra) + *delayedIntra = new_distortion; + else + *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra), + new_distortion); + + RESTORE_STACK; +} + +void quant_fine_energy(const CELTMode *m, int start, int end, celt_word16 *oldEBands, celt_word16 *error, int *fine_quant, ec_enc *enc, int _C) +{ + int i, c; + const int C = CHANNELS(_C); + + /* Encode finer resolution */ + for (i=start;inbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]); +#else + q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac); +#endif + if (q2 > frac-1) + q2 = frac-1; + if (q2<0) + q2 = 0; + ec_enc_bits(enc, q2, fine_quant[i]); +#ifdef FIXED_POINT + offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT)); +#else + offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f; +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + /*printf ("%f ", error[i] - offset);*/ + } while (++c < C); + } +} + +void quant_energy_finalise(const CELTMode *m, int start, int end, celt_word16 *oldEBands, celt_word16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int _C) +{ + int i, prio, c; + const int C = CHANNELS(_C); + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + celt_word16 offset; + q2 = error[i+c*m->nbEBands]<0 ? 0 : 1; + ec_enc_bits(enc, q2, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_word16 *oldEBands, int intra, ec_dec *dec, int _C, int LM) +{ + const unsigned char *prob_model = e_prob_model[LM][intra]; + int i, c; + celt_word32 prev[2] = {0, 0}; + celt_word16 coef; + celt_word16 beta; + const int C = CHANNELS(_C); + celt_int32 budget; + celt_int32 tell; + + + if (intra) + { + coef = 0; + beta = beta_intra; + } else { + beta = beta_coef[LM]; + coef = pred_coef[LM]; + } + + budget = dec->storage*8; + + /* Decode at a fixed coarse resolution */ + for (i=start;i=15) + { + int pi; + pi = 2*IMIN(i,20); + qi = ec_laplace_decode(dec, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell>=2) + { + qi = ec_dec_icdf(dec, small_energy_icdf, 2); + qi = (qi>>1)^-(qi&1); + } + else if(budget-tell>=1) + { + qi = -ec_dec_bit_logp(dec, 1); + } + else + qi = -1; + q = SHL32(EXTEND32(qi),DB_SHIFT); + + oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); + tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } +} + +void unquant_fine_energy(const CELTMode *m, int start, int end, celt_word16 *oldEBands, int *fine_quant, ec_dec *dec, int _C) +{ + int i, c; + const int C = CHANNELS(_C); + /* Decode finer resolution */ + for (i=start;inbEBands] += offset; + } while (++c < C); + } +} + +void unquant_energy_finalise(const CELTMode *m, int start, int end, celt_word16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int _C) +{ + int i, prio, c; + const int C = CHANNELS(_C); + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + celt_word16 offset; + q2 = ec_dec_bits(dec, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, celt_word16 *oldEBands, int _C) +{ + int c, i; + const int C = CHANNELS(_C); + c=0; + do { + for (i=0;inbEBands] = 0; + for (;inbEBands], + SHL16((celt_word16)eMeans[i],6)); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) + eBands[i+c*m->nbEBands] = 0; + } while (++c < C); +} + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, celt_word16 *bandLogE, int _C) +{ + int c, i; + const int C = CHANNELS(_C); + c=0; + do { + for (i=0;inbEBands] = + celt_log2(SHL32(bandE[i+c*m->nbEBands],2)) + - SHL16((celt_word16)eMeans[i],6); + for (i=effEnd;inbEBands+i] = -QCONST16(14.f,DB_SHIFT); + } while (++c < C); +} diff --git a/native/codec/libraries/celt/libcelt/quant_bands.h b/native/codec/libraries/celt/libcelt/quant_bands.h new file mode 100644 index 0000000..c1749b2 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/quant_bands.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef QUANT_BANDS +#define QUANT_BANDS + +#include "arch.h" +#include "modes.h" +#include "entenc.h" +#include "entdec.h" +#include "mathops.h" + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, celt_word16 *bandLogE, int _C); + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, celt_word16 *oldEBands, int _C); + +unsigned char *quant_prob_alloc(const CELTMode *m); +void quant_prob_free(const celt_int16 *freq); + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const celt_word16 *eBands, celt_word16 *oldEBands, celt_uint32 budget, + celt_word16 *error, ec_enc *enc, int _C, int LM, + int nbAvailableBytes, int force_intra, celt_word32 *delayedIntra, + int two_pass, int loss_rate); + +void quant_fine_energy(const CELTMode *m, int start, int end, celt_word16 *oldEBands, celt_word16 *error, int *fine_quant, ec_enc *enc, int _C); + +void quant_energy_finalise(const CELTMode *m, int start, int end, celt_word16 *oldEBands, celt_word16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int _C); + +void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_word16 *oldEBands, int intra, ec_dec *dec, int _C, int LM); + +void unquant_fine_energy(const CELTMode *m, int start, int end, celt_word16 *oldEBands, int *fine_quant, ec_dec *dec, int _C); + +void unquant_energy_finalise(const CELTMode *m, int start, int end, celt_word16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int _C); + +#endif /* QUANT_BANDS */ diff --git a/native/codec/libraries/celt/libcelt/rate.c b/native/codec/libraries/celt/libcelt/rate.c new file mode 100644 index 0000000..24037c0 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/rate.c @@ -0,0 +1,638 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "modes.h" +#include "cwrs.h" +#include "arch.h" +#include "os_support.h" + +#include "entcode.h" +#include "rate.h" + + +static const unsigned char LOG2_FRAC_TABLE[24]={ + 0, + 8,13, + 16,19,21,23, + 24,26,27,28,29,30,31,32, + 32,33,34,34,35,36,36,37,37 +}; + +#ifdef CUSTOM_MODES + +/*Determines if V(N,K) fits in a 32-bit unsigned integer. + N and K are themselves limited to 15 bits.*/ +static int fits_in32(int _n, int _k) +{ + static const celt_int16 maxN[15] = { + 32767, 32767, 32767, 1476, 283, 109, 60, 40, + 29, 24, 20, 18, 16, 14, 13}; + static const celt_int16 maxK[15] = { + 32767, 32767, 32767, 32767, 1172, 238, 95, 53, + 36, 27, 22, 18, 16, 15, 13}; + if (_n>=14) + { + if (_k>=14) + return 0; + else + return _n <= maxN[_k]; + } else { + return _k <= maxK[_n]; + } +} + +void compute_pulse_cache(CELTMode *m, int LM) +{ + int C; + int i; + int j; + int curr=0; + int nbEntries=0; + int entryN[100], entryK[100], entryI[100]; + const celt_int16 *eBands = m->eBands; + PulseCache *cache = &m->cache; + celt_int16 *cindex; + unsigned char *bits; + unsigned char *cap; + + cindex = celt_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2)); + cache->index = cindex; + + /* Scan for all unique band sizes */ + for (i=0;i<=LM+1;i++) + { + for (j=0;jnbEBands;j++) + { + int k; + int N = (eBands[j+1]-eBands[j])<>1; + cindex[i*m->nbEBands+j] = -1; + /* Find other bands that have the same size */ + for (k=0;k<=i;k++) + { + int n; + for (n=0;nnbEBands && (k!=i || n>1) + { + cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n]; + break; + } + } + } + if (cache->index[i*m->nbEBands+j] == -1 && N!=0) + { + int K; + entryN[nbEntries] = N; + K = 0; + while (fits_in32(N,get_pulses(K+1)) && KnbEBands+j] = curr; + entryI[nbEntries] = curr; + + curr += K+1; + nbEntries++; + } + } + } + bits = celt_alloc(sizeof(unsigned char)*curr); + cache->bits = bits; + cache->size = curr; + /* Compute the cache for all unique sizes */ + for (i=0;icaps = cap = celt_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands); + for (i=0;i<=LM;i++) + { + for (C=1;C<=2;C++) + { + for (j=0;jnbEBands;j++) + { + int N0; + int max_bits; + N0 = m->eBands[j+1]-m->eBands[j]; + /* N=1 bands only have a sign bit and fine bits. */ + if (N0< 2 && !(N0&1)) + { + N0>>=1; + LM0--; + } + /* N0=1 bands can't be split down to N<2. */ + else if (N0 <= 1) + { + LM0=IMIN(i,1); + N0<<=LM0; + } + /* Compute the cost for the lowest-level PVQ of a fully split + band. */ + pcache = bits + cindex[(LM0+1)*m->nbEBands+j]; + max_bits = pcache[pcache[0]]+1; + /* Add in the cost of coding regular splits. */ + N = N0; + for(k=0;klogN[j]+(LM0+k<>1)-QTHETA_OFFSET; + /* The number of qtheta bits we'll allocate if the remainder + is to be max_bits. + The average measured cost for theta is 0.89701 times qb, + approximated here as 459/512. */ + num=459*(celt_int32)((2*N-1)*offset+max_bits); + den=((celt_int32)(2*N-1)<<9)-459; + qb = IMIN((num+(den>>1))/den, 57); + celt_assert(qb >= 0); + max_bits += qb; + N <<= 1; + } + /* Add in the cost of a stereo split, if necessary. */ + if (C==2) + { + max_bits <<= 1; + offset = (m->logN[j]+(i<>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET); + ndof = 2*N-1-(N==2); + /* The average measured cost for theta with the step PDF is + 0.95164 times qb, approximated here as 487/512. */ + num = (N==2?512:487)*(celt_int32)(max_bits+ndof*offset); + den = ((celt_int32)ndof<<9)-(N==2?512:487); + qb = IMIN((num+(den>>1))/den, (N==2?64:61)); + celt_assert(qb >= 0); + max_bits += qb; + } + /* Add the fine bits we'll use. */ + /* Compensate for the extra DoF in stereo */ + ndof = C*N + ((C==2 && N>2) ? 1 : 0); + /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = (m->logN[j] + (i<>1)-FINE_OFFSET; + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += 1<>2; + /* The number of fine bits we'll allocate if the remainder is + to be max_bits. */ + num = max_bits+ndof*offset; + den = ndof-1<>1))/den, MAX_FINE_BITS); + celt_assert(qb >= 0); + max_bits += C*qb<eBands[j+1]-m->eBands[j]<= 0); + celt_assert(max_bits < 256); + *cap++ = (unsigned char)max_bits; + } + } + } +} + +#endif /* CUSTOM_MODES */ + + +#define ALLOC_STEPS 6 + +static inline int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start, + const int *bits1, const int *bits2, const int *thresh, const int *cap, celt_int32 total, celt_int32 *_balance, + int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits, + int *ebits, int *fine_priority, int _C, int LM, ec_ctx *ec, int encode, int prev) +{ + celt_int32 psum; + int lo, hi; + int i, j; + int logM; + const int C = CHANNELS(_C); + int stereo; + int codedBands=-1; + int alloc_floor; + celt_int32 left, percoeff; + int done; + int balance; + SAVE_STACK; + + alloc_floor = C<1; + + logM = LM<>1; + psum = 0; + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (mid*(celt_int32)bits2[j]>>ALLOC_STEPS); + if (tmp >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(tmp, cap[j]); + } else { + if (tmp >= alloc_floor) + psum += alloc_floor; + } + } + if (psum > total) + hi = mid; + else + lo = mid; + } + psum = 0; + /*printf ("interp bisection gave %d\n", lo);*/ + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (lo*bits2[j]>>ALLOC_STEPS); + if (tmp < thresh[j] && !done) + { + if (tmp >= alloc_floor) + tmp = alloc_floor; + else + tmp = 0; + } else + done = 1; + /* Don't allocate more than we can actually use */ + tmp = IMIN(tmp, cap[j]); + bits[j] = tmp; + psum += tmp; + } + + /* Decide which bands to skip, working backwards from the end. */ + for (codedBands=end;;codedBands--) + { + int band_width; + int band_bits; + int rem; + j = codedBands-1; + /* Never skip the first band, nor a band that has been boosted by + dynalloc. + In the first case, we'd be coding a bit to signal we're going to waste + all the other bits. + In the second case, we'd be coding a bit to redistribute all the bits + we just signaled should be cocentrated in this band. */ + if (j<=skip_start) + { + /* Give the bit we reserved to end skipping back. */ + total += skip_rsv; + break; + } + /*Figure out how many left-over bits we would be adding to this band. + This can include bits we've stolen back from higher, skipped bands.*/ + left = total-psum; + percoeff = left/(m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0); + band_width = m->eBands[codedBands]-m->eBands[j]; + band_bits = (int)(bits[j] + percoeff*band_width + rem); + /*Only code a skip decision if we're above the threshold for this band. + Otherwise it is force-skipped. + This ensures that we have enough bits to code the skip flag.*/ + if (band_bits >= IMAX(thresh[j], alloc_floor+(1< ((j>4) + { + ec_enc_bit_logp(ec, 1, 1); + break; + } + ec_enc_bit_logp(ec, 0, 1); + } else if (ec_dec_bit_logp(ec, 1)) { + break; + } + /*We used a bit to skip this band.*/ + psum += 1< 0) + intensity_rsv = LOG2_FRAC_TABLE[j-start]; + psum += intensity_rsv; + if (band_bits >= alloc_floor) + { + /*If we have enough for a fine energy bit per channel, use it.*/ + psum += alloc_floor; + bits[j] = alloc_floor; + } else { + /*Otherwise this band gets nothing at all.*/ + bits[j] = 0; + } + } + + celt_assert(codedBands > start); + /* Code the intensity and dual stereo parameters. */ + if (intensity_rsv > 0) + { + if (encode) + { + *intensity = IMIN(*intensity, codedBands); + ec_enc_uint(ec, *intensity-start, codedBands+1-start); + } + else + *intensity = start+ec_dec_uint(ec, codedBands+1-start); + } + else + *intensity = 0; + if (*intensity <= start) + { + total += dual_stereo_rsv; + dual_stereo_rsv = 0; + } + if (dual_stereo_rsv > 0) + { + if (encode) + ec_enc_bit_logp(ec, *dual_stereo, 1); + else + *dual_stereo = ec_dec_bit_logp(ec, 1); + } + else + *dual_stereo = 0; + + /* Allocate the remaining bits */ + left = total-psum; + percoeff = left/(m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + for (j=start;jeBands[j+1]-m->eBands[j])); + for (j=start;jeBands[j+1]-m->eBands[j]); + bits[j] += tmp; + left -= tmp; + } + /*for (j=0;j= 0); + N0 = m->eBands[j+1]-m->eBands[j]; + N=N0<1) + { + excess = IMAX(bits[j]-cap[j],0); + bits[j] -= excess; + + /* Compensate for the extra DoF in stereo */ + den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0)); + + NClogN = den*(m->logN[j] + logM); + + /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = (NClogN>>1)-den*FINE_OFFSET; + + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += den<>2; + + /* Changing the offset for allocating the second and third + fine energy bit */ + if (bits[j] + offset < den*2<>2; + else if (bits[j] + offset < den*3<>3; + + /* Divide with rounding */ + ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1))) / (den< (bits[j]>>BITRES)) + ebits[j] = bits[j] >> stereo >> BITRES; + + /* More than that is useless because that's about as far as PVQ can go */ + ebits[j] = IMIN(ebits[j], MAX_FINE_BITS); + + /* If we rounded down or capped this band, make it a candidate for the + final fine energy pass */ + fine_priority[j] = ebits[j]*(den<= bits[j]+offset; + + /* Remove the allocated fine bits; the rest are assigned to PVQ */ + bits[j] -= C*ebits[j]< 0) + { + int extra_fine; + int extra_bits; + extra_fine = IMIN(excess >> stereo+BITRES, MAX_FINE_BITS-ebits[j]); + ebits[j] += extra_fine; + extra_bits = extra_fine*C<= excess-balance; + excess -= extra_bits; + } + balance = excess; + + celt_assert(bits[j] >= 0); + celt_assert(ebits[j] >= 0); + } + /* Save any remaining bits over the cap for the rebalancing in + quant_all_bands(). */ + *_balance = balance; + + /* The skipped bands use all their bits for fine energy. */ + for (;j> stereo >> BITRES; + celt_assert(C*ebits[j]<nbEBands; + skip_start = start; + /* Reserve a bit to signal the end of manually skipped bands. */ + skip_rsv = total >= 1<total) + intensity_rsv = 0; + else + { + total -= intensity_rsv; + dual_stereo_rsv = total>=1<eBands[j+1]-m->eBands[j])<>4); + /* Tilt of the allocation curve */ + trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1) + <<(LM+BITRES)>>6; + /* Giving less resolution to single-coefficient bands because they get + more benefit from having one coarse value per coefficient*/ + if ((m->eBands[j+1]-m->eBands[j])<nbAllocVectors - 1; + do + { + int done = 0; + int psum = 0; + int mid = (lo+hi) >> 1; + for (j=end;j-->start;) + { + int bitsj; + int N = m->eBands[j+1]-m->eBands[j]; + bitsj = C*N*m->allocVectors[mid*len+j]<>2; + if (bitsj > 0) + bitsj = IMAX(0, bitsj + trim_offset[j]); + bitsj += offsets[j]; + if (bitsj >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(bitsj, cap[j]); + } else { + if (bitsj >= C< total) + hi = mid - 1; + else + lo = mid + 1; + /*printf ("lo = %d, hi = %d\n", lo, hi);*/ + } + while (lo <= hi); + hi = lo--; + /*printf ("interp between %d and %d\n", lo, hi);*/ + for (j=start;jeBands[j+1]-m->eBands[j]; + bits1j = C*N*m->allocVectors[lo*len+j]<>2; + bits2j = hi>=m->nbAllocVectors ? + cap[j] : C*N*m->allocVectors[hi*len+j]<>2; + if (bits1j > 0) + bits1j = IMAX(0, bits1j + trim_offset[j]); + if (bits2j > 0) + bits2j = IMAX(0, bits2j + trim_offset[j]); + if (lo > 0) + bits1j += offsets[j]; + bits2j += offsets[j]; + if (offsets[j]>0) + skip_start = j; + bits2j = IMAX(0,bits2j-bits1j); + bits1[j] = bits1j; + bits2[j] = bits2j; + } + codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap, + total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv, + pulses, ebits, fine_priority, C, LM, ec, encode, prev); + RESTORE_STACK; + return codedBands; +} + diff --git a/native/codec/libraries/celt/libcelt/rate.h b/native/codec/libraries/celt/libcelt/rate.h new file mode 100644 index 0000000..8feaa86 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/rate.h @@ -0,0 +1,107 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RATE_H +#define RATE_H + +#define MAX_PSEUDO 40 +#define LOG_MAX_PSEUDO 6 + +#define MAX_PULSES 128 + +#define MAX_FINE_BITS 8 + +#define FINE_OFFSET 21 +#define QTHETA_OFFSET 4 +#define QTHETA_OFFSET_TWOPHASE 16 + +#define BITOVERFLOW 30000 + +#include "cwrs.h" +#include "modes.h" + +void compute_pulse_cache(CELTMode *m, int LM); + +static inline int get_pulses(int i) +{ + return i<8 ? i : (8 + (i&7)) << ((i>>3)-1); +} + +static inline int bits2pulses(const CELTMode *m, int band, int LM, int bits) +{ + int i; + int lo, hi; + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + + lo = 0; + hi = cache[0]; + bits--; + for (i=0;i>1; + /* OPT: Make sure this is implemented with a conditional move */ + if (cache[mid] >= bits) + hi = mid; + else + lo = mid; + } + if (bits- (lo == 0 ? -1 : cache[lo]) <= cache[hi]-bits) + return lo; + else + return hi; +} + +static inline int pulses2bits(const CELTMode *m, int band, int LM, int pulses) +{ + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + return pulses == 0 ? 0 : cache[pulses]+1; +} + +/** Computes a cache of the pulses->bits mapping in each band */ +celt_int16 **compute_alloc_cache(CELTMode *m, int M); + +/** Compute the pulse allocation, i.e. how many pulses will go in each + * band. + @param m mode + @param offsets Requested increase or decrease in the number of bits for + each band + @param total Number of bands + @param pulses Number of pulses per band (returned) + @return Total number of bits allocated +*/ +int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero, + celt_int32 total, celt_int32 *balance, int *pulses, int *ebits, int *fine_priority, int _C, int LM, ec_ctx *ec, int encode, int prev); + + +#endif diff --git a/native/codec/libraries/celt/libcelt/stack_alloc.h b/native/codec/libraries/celt/libcelt/stack_alloc.h new file mode 100644 index 0000000..69daf06 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/stack_alloc.h @@ -0,0 +1,147 @@ +/* Copyright (C) 2002-2003 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + + +#if defined(VAR_ARRAYS) + +#define VARDECL(type, var) +#define ALLOC(var, size, type) type var[size] +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK + +#elif defined(USE_ALLOCA) + +#define VARDECL(type, var) type *var + +# ifdef WIN32 +# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size))) +# else +# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size))) +# endif + +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK + +#else + +#ifdef CELT_C +char *global_stack=0; +#else +extern char *global_stack; +#endif /*CELT_C*/ + +#ifdef ENABLE_VALGRIND + +#include + +#ifdef CELT_C +char *global_stack_top=0; +#else +extern char *global_stack_top; +#endif /*CELT_C*/ + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char)))) +#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)) +#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=celt_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack; + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char)))) +#define RESTORE_STACK (global_stack = _saved_stack) +#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? celt_alloc_scratch(GLOBAL_STACK_SIZE) : global_stack); _saved_stack = global_stack; + +#endif /*ENABLE_VALGRIND*/ + +#include "os_support.h" +#define VARDECL(type, var) type *var +#define ALLOC(var, size, type) var = PUSH(global_stack, size, type) +#define SAVE_STACK char *_saved_stack = global_stack; + +#endif /*VAR_ARRAYS*/ + + +#endif /*STACK_ALLOC_H*/ diff --git a/native/codec/libraries/celt/libcelt/static_modes_fixed.c b/native/codec/libraries/celt/libcelt/static_modes_fixed.c new file mode 100644 index 0000000..0a18237 --- /dev/null +++ b/native/codec/libraries/celt/libcelt/static_modes_fixed.c @@ -0,0 +1,130 @@ +/* The contents of this file is automatically generated and contains static + definitions for some pre-defined modes */ +#include "modes.h" +#include "rate.h" + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const celt_word16 window120[120] = { +2, 20, 55, 108, 178, 266, 372, 494, 635, 792, 966, 1157, 1365, 1590, 1831, 2089, 2362, 2651, 2956, 3276, 3611, 3961, 4325, 4703, 5094, 5499, 5916, 6346, 6788, 7241, 7705, 8179, 8663, 9156, 9657, 10167, 10684, 11207, 11736, 12271, 12810, 13353, 13899, 14447, 14997, 15547, 16098, 16648, 17197, 17744, 18287, 18827, 19363, 19893, 20418, 20936, 21447, 21950, 22445, 22931, 23407, 23874, 24330, 24774, 25208, 25629, 26039, 26435, 26819, 27190, 27548, 27893, 28224, 28541, 28845, 29135, 29411, 29674, 29924, 30160, 30384, 30594, 30792, 30977, 31151, 31313, 31463, 31602, 31731, 31849, 31958, 32057, 32148, 32229, 32303, 32370, 32429, 32481, 32528, 32568, 32604, 32634, 32661, 32683, 32701, 32717, 32729, 32740, 32748, 32754, 32758, 32762, 32764, 32766, 32767, 32767, 32767, 32767, 32767, 32767, }; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const celt_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const celt_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, 82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, 41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, 41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, 318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, 305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, 240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, }; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, 31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, 51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, 66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, 64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, 94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, 124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, 97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, 142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, 28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, 153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, 229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, 166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, 86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, 25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, 185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, 110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, 74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, 163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, 228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, 90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, 87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, 106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, 224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, 182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, 178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, 240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, 160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, 138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, 204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, 185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, 207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, 188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, 204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, 140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{32767, 0}, {32766, -429}, {32757, -858}, {32743, -1287}, {32724, -1715}, {32698, -2143}, {32667, -2570}, {32631, -2998}, {32588, -3425}, {32541, -3851}, {32488, -4277}, {32429, -4701}, {32364, -5125}, {32295, -5548}, {32219, -5971}, {32138, -6393}, {32051, -6813}, {31960, -7231}, {31863, -7650}, {31760, -8067}, {31652, -8481}, {31539, -8895}, {31419, -9306}, {31294, -9716}, {31165, -10126}, {31030, -10532}, {30889, -10937}, {30743, -11340}, {30592, -11741}, {30436, -12141}, {30274, -12540}, {30107, -12935}, {29936, -13328}, {29758, -13718}, {29577, -14107}, {29390, -14493}, {29197, -14875}, {29000, -15257}, {28797, -15635}, {28590, -16010}, {28379, -16384}, {28162, -16753}, {27940, -17119}, {27714, -17484}, {27482, -17845}, {27246, -18205}, {27006, -18560}, {26760, -18911}, {26510, -19260}, {26257, -19606}, {25997, -19947}, {25734, -20286}, {25466, -20621}, {25194, -20952}, {24918, -21281}, {24637, -21605}, {24353, -21926}, {24063, -22242}, {23770, -22555}, {23473, -22865}, {23171, -23171}, {22866, -23472}, {22557, -23769}, {22244, -24063}, {21927, -24352}, {21606, -24636}, {21282, -24917}, {20954, -25194}, {20622, -25465}, {20288, -25733}, {19949, -25997}, {19607, -26255}, {19261, -26509}, {18914, -26760}, {18561, -27004}, {18205, -27246}, {17846, -27481}, {17485, -27713}, {17122, -27940}, {16755, -28162}, {16385, -28378}, {16012, -28590}, {15636, -28797}, {15258, -28999}, {14878, -29197}, {14494, -29389}, {14108, -29576}, {13720, -29757}, {13329, -29934}, {12937, -30107}, {12540, -30274}, {12142, -30435}, {11744, -30592}, {11342, -30743}, {10939, -30889}, {10534, -31030}, {10127, -31164}, {9718, -31294}, {9307, -31418}, {8895, -31537}, {8482, -31652}, {8067, -31759}, {7650, -31862}, {7233, -31960}, {6815, -32051}, {6393, -32138}, {5973, -32219}, {5549, -32294}, {5127, -32364}, {4703, -32429}, {4278, -32487}, {3852, -32541}, {3426, -32588}, {2999, -32630}, {2572, -32667}, {2144, -32698}, {1716, -32724}, {1287, -32742}, {860, -32757}, {430, -32766}, {0, -32767}, {-429, -32766}, {-858, -32757}, {-1287, -32743}, {-1715, -32724}, {-2143, -32698}, {-2570, -32667}, {-2998, -32631}, {-3425, -32588}, {-3851, -32541}, {-4277, -32488}, {-4701, -32429}, {-5125, -32364}, {-5548, -32295}, {-5971, -32219}, {-6393, -32138}, {-6813, -32051}, {-7231, -31960}, {-7650, -31863}, {-8067, -31760}, {-8481, -31652}, {-8895, -31539}, {-9306, -31419}, {-9716, -31294}, {-10126, -31165}, {-10532, -31030}, {-10937, -30889}, {-11340, -30743}, {-11741, -30592}, {-12141, -30436}, {-12540, -30274}, {-12935, -30107}, {-13328, -29936}, {-13718, -29758}, {-14107, -29577}, {-14493, -29390}, {-14875, -29197}, {-15257, -29000}, {-15635, -28797}, {-16010, -28590}, {-16384, -28379}, {-16753, -28162}, {-17119, -27940}, {-17484, -27714}, {-17845, -27482}, {-18205, -27246}, {-18560, -27006}, {-18911, -26760}, {-19260, -26510}, {-19606, -26257}, {-19947, -25997}, {-20286, -25734}, {-20621, -25466}, {-20952, -25194}, {-21281, -24918}, {-21605, -24637}, {-21926, -24353}, {-22242, -24063}, {-22555, -23770}, {-22865, -23473}, {-23171, -23171}, {-23472, -22866}, {-23769, -22557}, {-24063, -22244}, {-24352, -21927}, {-24636, -21606}, {-24917, -21282}, {-25194, -20954}, {-25465, -20622}, {-25733, -20288}, {-25997, -19949}, {-26255, -19607}, {-26509, -19261}, {-26760, -18914}, {-27004, -18561}, {-27246, -18205}, {-27481, -17846}, {-27713, -17485}, {-27940, -17122}, {-28162, -16755}, {-28378, -16385}, {-28590, -16012}, {-28797, -15636}, {-28999, -15258}, {-29197, -14878}, {-29389, -14494}, {-29576, -14108}, {-29757, -13720}, {-29934, -13329}, {-30107, -12937}, {-30274, -12540}, {-30435, -12142}, {-30592, -11744}, {-30743, -11342}, {-30889, -10939}, {-31030, -10534}, {-31164, -10127}, {-31294, -9718}, {-31418, -9307}, {-31537, -8895}, {-31652, -8482}, {-31759, -8067}, {-31862, -7650}, {-31960, -7233}, {-32051, -6815}, {-32138, -6393}, {-32219, -5973}, {-32294, -5549}, {-32364, -5127}, {-32429, -4703}, {-32487, -4278}, {-32541, -3852}, {-32588, -3426}, {-32630, -2999}, {-32667, -2572}, {-32698, -2144}, {-32724, -1716}, {-32742, -1287}, {-32757, -860}, {-32766, -430}, {-32767, 0}, {-32766, 429}, {-32757, 858}, {-32743, 1287}, {-32724, 1715}, {-32698, 2143}, {-32667, 2570}, {-32631, 2998}, {-32588, 3425}, {-32541, 3851}, {-32488, 4277}, {-32429, 4701}, {-32364, 5125}, {-32295, 5548}, {-32219, 5971}, {-32138, 6393}, {-32051, 6813}, {-31960, 7231}, {-31863, 7650}, {-31760, 8067}, {-31652, 8481}, {-31539, 8895}, {-31419, 9306}, {-31294, 9716}, {-31165, 10126}, {-31030, 10532}, {-30889, 10937}, {-30743, 11340}, {-30592, 11741}, {-30436, 12141}, {-30274, 12540}, {-30107, 12935}, {-29936, 13328}, {-29758, 13718}, {-29577, 14107}, {-29390, 14493}, {-29197, 14875}, {-29000, 15257}, {-28797, 15635}, {-28590, 16010}, {-28379, 16384}, {-28162, 16753}, {-27940, 17119}, {-27714, 17484}, {-27482, 17845}, {-27246, 18205}, {-27006, 18560}, {-26760, 18911}, {-26510, 19260}, {-26257, 19606}, {-25997, 19947}, {-25734, 20286}, {-25466, 20621}, {-25194, 20952}, {-24918, 21281}, {-24637, 21605}, {-24353, 21926}, {-24063, 22242}, {-23770, 22555}, {-23473, 22865}, {-23171, 23171}, {-22866, 23472}, {-22557, 23769}, {-22244, 24063}, {-21927, 24352}, {-21606, 24636}, {-21282, 24917}, {-20954, 25194}, {-20622, 25465}, {-20288, 25733}, {-19949, 25997}, {-19607, 26255}, {-19261, 26509}, {-18914, 26760}, {-18561, 27004}, {-18205, 27246}, {-17846, 27481}, {-17485, 27713}, {-17122, 27940}, {-16755, 28162}, {-16385, 28378}, {-16012, 28590}, {-15636, 28797}, {-15258, 28999}, {-14878, 29197}, {-14494, 29389}, {-14108, 29576}, {-13720, 29757}, {-13329, 29934}, {-12937, 30107}, {-12540, 30274}, {-12142, 30435}, {-11744, 30592}, {-11342, 30743}, {-10939, 30889}, {-10534, 31030}, {-10127, 31164}, {-9718, 31294}, {-9307, 31418}, {-8895, 31537}, {-8482, 31652}, {-8067, 31759}, {-7650, 31862}, {-7233, 31960}, {-6815, 32051}, {-6393, 32138}, {-5973, 32219}, {-5549, 32294}, {-5127, 32364}, {-4703, 32429}, {-4278, 32487}, {-3852, 32541}, {-3426, 32588}, {-2999, 32630}, {-2572, 32667}, {-2144, 32698}, {-1716, 32724}, {-1287, 32742}, {-860, 32757}, {-430, 32766}, {0, 32767}, {429, 32766}, {858, 32757}, {1287, 32743}, {1715, 32724}, {2143, 32698}, {2570, 32667}, {2998, 32631}, {3425, 32588}, {3851, 32541}, {4277, 32488}, {4701, 32429}, {5125, 32364}, {5548, 32295}, {5971, 32219}, {6393, 32138}, {6813, 32051}, {7231, 31960}, {7650, 31863}, {8067, 31760}, {8481, 31652}, {8895, 31539}, {9306, 31419}, {9716, 31294}, {10126, 31165}, {10532, 31030}, {10937, 30889}, {11340, 30743}, {11741, 30592}, {12141, 30436}, {12540, 30274}, {12935, 30107}, {13328, 29936}, {13718, 29758}, {14107, 29577}, {14493, 29390}, {14875, 29197}, {15257, 29000}, {15635, 28797}, {16010, 28590}, {16384, 28379}, {16753, 28162}, {17119, 27940}, {17484, 27714}, {17845, 27482}, {18205, 27246}, {18560, 27006}, {18911, 26760}, {19260, 26510}, {19606, 26257}, {19947, 25997}, {20286, 25734}, {20621, 25466}, {20952, 25194}, {21281, 24918}, {21605, 24637}, {21926, 24353}, {22242, 24063}, {22555, 23770}, {22865, 23473}, {23171, 23171}, {23472, 22866}, {23769, 22557}, {24063, 22244}, {24352, 21927}, {24636, 21606}, {24917, 21282}, {25194, 20954}, {25465, 20622}, {25733, 20288}, {25997, 19949}, {26255, 19607}, {26509, 19261}, {26760, 18914}, {27004, 18561}, {27246, 18205}, {27481, 17846}, {27713, 17485}, {27940, 17122}, {28162, 16755}, {28378, 16385}, {28590, 16012}, {28797, 15636}, {28999, 15258}, {29197, 14878}, {29389, 14494}, {29576, 14108}, {29757, 13720}, {29934, 13329}, {30107, 12937}, {30274, 12540}, {30435, 12142}, {30592, 11744}, {30743, 11342}, {30889, 10939}, {31030, 10534}, {31164, 10127}, {31294, 9718}, {31418, 9307}, {31537, 8895}, {31652, 8482}, {31759, 8067}, {31862, 7650}, {31960, 7233}, {32051, 6815}, {32138, 6393}, {32219, 5973}, {32294, 5549}, {32364, 5127}, {32429, 4703}, {32487, 4278}, {32541, 3852}, {32588, 3426}, {32630, 2999}, {32667, 2572}, {32698, 2144}, {32724, 1716}, {32742, 1287}, {32757, 860}, {32766, 430}, }; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const celt_int16 fft_bitrev480[480] = { +0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330, 450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225, 345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95, 215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440, 110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310, 430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205, 325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61, 181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406, 76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276, 396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171, 291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41, 161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386, 56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242, 362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137, 257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7, 127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457, 22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352, 472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222, 342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117, 237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423, 93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318, 438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188, 308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83, 203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403, 73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298, 418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154, 274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49, 169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369, 39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264, 384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134, 254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29, 149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479, }; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const celt_int16 fft_bitrev240[240] = { +0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165, 225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110, 170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55, 115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211, 46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156, 216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101, 161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32, 92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202, 37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147, 207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78, 138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23, 83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193, 28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124, 184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69, 129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14, 74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239, }; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const celt_int16 fft_bitrev120[120] = { +0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80, 110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46, 76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26, 56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97, 22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63, 93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43, 73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9, 39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119, }; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const celt_int16 fft_bitrev60[60] = { +0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31, 46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22, 37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13, 28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59, }; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +-1, /* shift */ +{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +1, /* shift */ +{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +2, /* shift */ +{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +3, /* shift */ +{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const celt_word16 mdct_twiddles960[481] = { +32767, 32767, 32767, 32767, 32766, 32763, 32762, 32759, 32757, 32753, 32751, 32747, 32743, 32738, 32733, 32729, 32724, 32717, 32711, 32705, 32698, 32690, 32683, 32676, 32667, 32658, 32650, 32640, 32631, 32620, 32610, 32599, 32588, 32577, 32566, 32554, 32541, 32528, 32515, 32502, 32487, 32474, 32459, 32444, 32429, 32413, 32397, 32381, 32364, 32348, 32331, 32313, 32294, 32277, 32257, 32239, 32219, 32200, 32180, 32159, 32138, 32118, 32096, 32074, 32051, 32029, 32006, 31984, 31960, 31936, 31912, 31888, 31863, 31837, 31812, 31786, 31760, 31734, 31707, 31679, 31652, 31624, 31596, 31567, 31539, 31508, 31479, 31450, 31419, 31388, 31357, 31326, 31294, 31262, 31230, 31198, 31164, 31131, 31097, 31063, 31030, 30994, 30959, 30924, 30889, 30853, 30816, 30779, 30743, 30705, 30668, 30629, 30592, 30553, 30515, 30475, 30435, 30396, 30356, 30315, 30274, 30233, 30191, 30149, 30107, 30065, 30022, 29979, 29936, 29891, 29847, 29803, 29758, 29713, 29668, 29622, 29577, 29529, 29483, 29436, 29390, 29341, 29293, 29246, 29197, 29148, 29098, 29050, 29000, 28949, 28899, 28848, 28797, 28746, 28694, 28642, 28590, 28537, 28485, 28432, 28378, 28324, 28271, 28217, 28162, 28106, 28051, 27995, 27940, 27884, 27827, 27770, 27713, 27657, 27598, 27540, 27481, 27423, 27365, 27305, 27246, 27187, 27126, 27066, 27006, 26945, 26883, 26822, 26760, 26698, 26636, 26574, 26510, 26448, 26383, 26320, 26257, 26191, 26127, 26062, 25997, 25931, 25866, 25800, 25734, 25667, 25601, 25533, 25466, 25398, 25330, 25262, 25194, 25125, 25056, 24987, 24917, 24848, 24778, 24707, 24636, 24566, 24495, 24424, 24352, 24280, 24208, 24135, 24063, 23990, 23917, 23842, 23769, 23695, 23622, 23546, 23472, 23398, 23322, 23246, 23171, 23095, 23018, 22942, 22866, 22788, 22711, 22634, 22557, 22478, 22400, 22322, 22244, 22165, 22085, 22006, 21927, 21846, 21766, 21687, 21606, 21524, 21443, 21363, 21282, 21199, 21118, 21035, 20954, 20870, 20788, 20705, 20621, 20538, 20455, 20371, 20286, 20202, 20118, 20034, 19947, 19863, 19777, 19692, 19606, 19520, 19434, 19347, 19260, 19174, 19088, 18999, 18911, 18825, 18737, 18648, 18560, 18472, 18384, 18294, 18205, 18116, 18025, 17936, 17846, 17757, 17666, 17576, 17485, 17395, 17303, 17212, 17122, 17030, 16937, 16846, 16755, 16662, 16569, 16477, 16385, 16291, 16198, 16105, 16012, 15917, 15824, 15730, 15636, 15541, 15447, 15352, 15257, 15162, 15067, 14973, 14875, 14781, 14685, 14589, 14493, 14396, 14300, 14204, 14107, 14010, 13914, 13815, 13718, 13621, 13524, 13425, 13328, 13230, 13133, 13033, 12935, 12836, 12738, 12638, 12540, 12441, 12341, 12241, 12142, 12044, 11943, 11843, 11744, 11643, 11542, 11442, 11342, 11241, 11139, 11039, 10939, 10836, 10736, 10635, 10534, 10431, 10330, 10228, 10127, 10024, 9921, 9820, 9718, 9614, 9512, 9410, 9306, 9204, 9101, 8998, 8895, 8791, 8689, 8585, 8481, 8377, 8274, 8171, 8067, 7962, 7858, 7753, 7650, 7545, 7441, 7336, 7231, 7129, 7023, 6917, 6813, 6709, 6604, 6498, 6393, 6288, 6182, 6077, 5973, 5867, 5760, 5656, 5549, 5445, 5339, 5232, 5127, 5022, 4914, 4809, 4703, 4596, 4490, 4384, 4278, 4171, 4065, 3958, 3852, 3745, 3640, 3532, 3426, 3318, 3212, 3106, 2998, 2891, 2786, 2679, 2570, 2465, 2358, 2251, 2143, 2037, 1929, 1823, 1715, 1609, 1501, 1393, 1287, 1180, 1073, 964, 858, 751, 644, 535, 429, 322, 214, 107, 0, }; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{27853, 0, 4096, 8192, }, /* preemph */ +eband5ms, /* eBands */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +window120, /* window */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +logN400, /* logN */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/native/codec/libraries/celt/libcelt/static_modes_float.c b/native/codec/libraries/celt/libcelt/static_modes_float.c new file mode 100644 index 0000000..d37345a --- /dev/null +++ b/native/codec/libraries/celt/libcelt/static_modes_float.c @@ -0,0 +1,134 @@ +/* The contents of this file is automatically generated and contains static + definitions for some pre-defined modes */ +#include "modes.h" +#include "rate.h" + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const celt_word16 window120[120] = { +0.000067, 0.000606, 0.001682, 0.003295, 0.005444, 0.008128, 0.011344, 0.015091, 0.019365, 0.024164, 0.029483, 0.035320, 0.041669, 0.048525, 0.055884, 0.063738, 0.072082, 0.080907, 0.090208, 0.099974, 0.110198, 0.120869, 0.131977, 0.143512, 0.155462, 0.167814, 0.180555, 0.193673, 0.207152, 0.220977, 0.235132, 0.249602, 0.264369, 0.279414, 0.294720, 0.310268, 0.326038, 0.342009, 0.358162, 0.374474, 0.390925, 0.407491, 0.424152, 0.440884, 0.457665, 0.474471, 0.491280, 0.508068, 0.524813, 0.541491, 0.558080, 0.574557, 0.590900, 0.607088, 0.623100, 0.638913, 0.654509, 0.669868, 0.684971, 0.699800, 0.714339, 0.728571, 0.742480, 0.756054, 0.769279, 0.782143, 0.794634, 0.806744, 0.818465, 0.829787, 0.840707, 0.851218, 0.861317, 0.871002, 0.880271, 0.889125, 0.897564, 0.905591, 0.913209, 0.920423, 0.927237, 0.933660, 0.939697, 0.945357, 0.950649, 0.955584, 0.960171, 0.964422, 0.968349, 0.971963, 0.975279, 0.978309, 0.981066, 0.983565, 0.985819, 0.987842, 0.989649, 0.991253, 0.992669, 0.993910, 0.994990, 0.995923, 0.996722, 0.997399, 0.997967, 0.998437, 0.998822, 0.999132, 0.999376, 0.999565, 0.999708, 0.999812, 0.999886, 0.999936, 0.999967, 0.999985, 0.999995, 0.999999, 1.000000, 1.000000, }; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const celt_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const celt_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, 82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, 41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, 41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, 318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, 305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, 240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, }; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, 31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, 51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, 66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, 64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, 94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, 124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, 97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, 142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, 28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, 153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, 229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, 166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, 86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, 25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, 185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, 110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, 74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, 163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, 228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, 90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, 87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, 106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, 224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, 182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, 178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, 240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, 160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, 138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, 204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, 185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, 207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, 188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, 204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, 140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{1.000000, -0.000000}, {0.999914, -0.013090}, {0.999657, -0.026177}, {0.999229, -0.039260}, {0.998630, -0.052336}, {0.997859, -0.065403}, {0.996917, -0.078459}, {0.995805, -0.091502}, {0.994522, -0.104528}, {0.993068, -0.117537}, {0.991445, -0.130526}, {0.989651, -0.143493}, {0.987688, -0.156434}, {0.985556, -0.169350}, {0.983255, -0.182236}, {0.980785, -0.195090}, {0.978148, -0.207912}, {0.975342, -0.220697}, {0.972370, -0.233445}, {0.969231, -0.246153}, {0.965926, -0.258819}, {0.962455, -0.271440}, {0.958820, -0.284015}, {0.955020, -0.296542}, {0.951057, -0.309017}, {0.946930, -0.321439}, {0.942641, -0.333807}, {0.938191, -0.346117}, {0.933580, -0.358368}, {0.928810, -0.370557}, {0.923880, -0.382683}, {0.918791, -0.394744}, {0.913545, -0.406737}, {0.908143, -0.418660}, {0.902585, -0.430511}, {0.896873, -0.442289}, {0.891007, -0.453990}, {0.884988, -0.465615}, {0.878817, -0.477159}, {0.872496, -0.488621}, {0.866025, -0.500000}, {0.859406, -0.511293}, {0.852640, -0.522499}, {0.845728, -0.533615}, {0.838671, -0.544639}, {0.831470, -0.555570}, {0.824126, -0.566406}, {0.816642, -0.577145}, {0.809017, -0.587785}, {0.801254, -0.598325}, {0.793353, -0.608761}, {0.785317, -0.619094}, {0.777146, -0.629320}, {0.768842, -0.639439}, {0.760406, -0.649448}, {0.751840, -0.659346}, {0.743145, -0.669131}, {0.734322, -0.678801}, {0.725374, -0.688355}, {0.716302, -0.697790}, {0.707107, -0.707107}, {0.697790, -0.716302}, {0.688355, -0.725374}, {0.678801, -0.734322}, {0.669131, -0.743145}, {0.659346, -0.751840}, {0.649448, -0.760406}, {0.639439, -0.768842}, {0.629320, -0.777146}, {0.619094, -0.785317}, {0.608761, -0.793353}, {0.598325, -0.801254}, {0.587785, -0.809017}, {0.577145, -0.816642}, {0.566406, -0.824126}, {0.555570, -0.831470}, {0.544639, -0.838671}, {0.533615, -0.845728}, {0.522499, -0.852640}, {0.511293, -0.859406}, {0.500000, -0.866025}, {0.488621, -0.872496}, {0.477159, -0.878817}, {0.465615, -0.884988}, {0.453990, -0.891007}, {0.442289, -0.896873}, {0.430511, -0.902585}, {0.418660, -0.908143}, {0.406737, -0.913545}, {0.394744, -0.918791}, {0.382683, -0.923880}, {0.370557, -0.928810}, {0.358368, -0.933580}, {0.346117, -0.938191}, {0.333807, -0.942641}, {0.321439, -0.946930}, {0.309017, -0.951057}, {0.296542, -0.955020}, {0.284015, -0.958820}, {0.271440, -0.962455}, {0.258819, -0.965926}, {0.246153, -0.969231}, {0.233445, -0.972370}, {0.220697, -0.975342}, {0.207912, -0.978148}, {0.195090, -0.980785}, {0.182236, -0.983255}, {0.169350, -0.985556}, {0.156434, -0.987688}, {0.143493, -0.989651}, {0.130526, -0.991445}, {0.117537, -0.993068}, {0.104528, -0.994522}, {0.091502, -0.995805}, {0.078459, -0.996917}, {0.065403, -0.997859}, {0.052336, -0.998630}, {0.039260, -0.999229}, {0.026177, -0.999657}, {0.013090, -0.999914}, {0.000000, -1.000000}, {-0.013090, -0.999914}, {-0.026177, -0.999657}, {-0.039260, -0.999229}, {-0.052336, -0.998630}, {-0.065403, -0.997859}, {-0.078459, -0.996917}, {-0.091502, -0.995805}, {-0.104528, -0.994522}, {-0.117537, -0.993068}, {-0.130526, -0.991445}, {-0.143493, -0.989651}, {-0.156434, -0.987688}, {-0.169350, -0.985556}, {-0.182236, -0.983255}, {-0.195090, -0.980785}, {-0.207912, -0.978148}, {-0.220697, -0.975342}, {-0.233445, -0.972370}, {-0.246153, -0.969231}, {-0.258819, -0.965926}, {-0.271440, -0.962455}, {-0.284015, -0.958820}, {-0.296542, -0.955020}, {-0.309017, -0.951057}, {-0.321439, -0.946930}, {-0.333807, -0.942641}, {-0.346117, -0.938191}, {-0.358368, -0.933580}, {-0.370557, -0.928810}, {-0.382683, -0.923880}, {-0.394744, -0.918791}, {-0.406737, -0.913545}, {-0.418660, -0.908143}, {-0.430511, -0.902585}, {-0.442289, -0.896873}, {-0.453990, -0.891007}, {-0.465615, -0.884988}, {-0.477159, -0.878817}, {-0.488621, -0.872496}, {-0.500000, -0.866025}, {-0.511293, -0.859406}, {-0.522499, -0.852640}, {-0.533615, -0.845728}, {-0.544639, -0.838671}, {-0.555570, -0.831470}, {-0.566406, -0.824126}, {-0.577145, -0.816642}, {-0.587785, -0.809017}, {-0.598325, -0.801254}, {-0.608761, -0.793353}, {-0.619094, -0.785317}, {-0.629320, -0.777146}, {-0.639439, -0.768842}, {-0.649448, -0.760406}, {-0.659346, -0.751840}, {-0.669131, -0.743145}, {-0.678801, -0.734322}, {-0.688355, -0.725374}, {-0.697790, -0.716302}, {-0.707107, -0.707107}, {-0.716302, -0.697790}, {-0.725374, -0.688355}, {-0.734322, -0.678801}, {-0.743145, -0.669131}, {-0.751840, -0.659346}, {-0.760406, -0.649448}, {-0.768842, -0.639439}, {-0.777146, -0.629320}, {-0.785317, -0.619094}, {-0.793353, -0.608761}, {-0.801254, -0.598325}, {-0.809017, -0.587785}, {-0.816642, -0.577145}, {-0.824126, -0.566406}, {-0.831470, -0.555570}, {-0.838671, -0.544639}, {-0.845728, -0.533615}, {-0.852640, -0.522499}, {-0.859406, -0.511293}, {-0.866025, -0.500000}, {-0.872496, -0.488621}, {-0.878817, -0.477159}, {-0.884988, -0.465615}, {-0.891007, -0.453990}, {-0.896873, -0.442289}, {-0.902585, -0.430511}, {-0.908143, -0.418660}, {-0.913545, -0.406737}, {-0.918791, -0.394744}, {-0.923880, -0.382683}, {-0.928810, -0.370557}, {-0.933580, -0.358368}, {-0.938191, -0.346117}, {-0.942641, -0.333807}, {-0.946930, -0.321439}, {-0.951057, -0.309017}, {-0.955020, -0.296542}, {-0.958820, -0.284015}, {-0.962455, -0.271440}, {-0.965926, -0.258819}, {-0.969231, -0.246153}, {-0.972370, -0.233445}, {-0.975342, -0.220697}, {-0.978148, -0.207912}, {-0.980785, -0.195090}, {-0.983255, -0.182236}, {-0.985556, -0.169350}, {-0.987688, -0.156434}, {-0.989651, -0.143493}, {-0.991445, -0.130526}, {-0.993068, -0.117537}, {-0.994522, -0.104528}, {-0.995805, -0.091502}, {-0.996917, -0.078459}, {-0.997859, -0.065403}, {-0.998630, -0.052336}, {-0.999229, -0.039260}, {-0.999657, -0.026177}, {-0.999914, -0.013090}, {-1.000000, -0.000000}, {-0.999914, 0.013090}, {-0.999657, 0.026177}, {-0.999229, 0.039260}, {-0.998630, 0.052336}, {-0.997859, 0.065403}, {-0.996917, 0.078459}, {-0.995805, 0.091502}, {-0.994522, 0.104528}, {-0.993068, 0.117537}, {-0.991445, 0.130526}, {-0.989651, 0.143493}, {-0.987688, 0.156434}, {-0.985556, 0.169350}, {-0.983255, 0.182236}, {-0.980785, 0.195090}, {-0.978148, 0.207912}, {-0.975342, 0.220697}, {-0.972370, 0.233445}, {-0.969231, 0.246153}, {-0.965926, 0.258819}, {-0.962455, 0.271440}, {-0.958820, 0.284015}, {-0.955020, 0.296542}, {-0.951057, 0.309017}, {-0.946930, 0.321439}, {-0.942641, 0.333807}, {-0.938191, 0.346117}, {-0.933580, 0.358368}, {-0.928810, 0.370557}, {-0.923880, 0.382683}, {-0.918791, 0.394744}, {-0.913545, 0.406737}, {-0.908143, 0.418660}, {-0.902585, 0.430511}, {-0.896873, 0.442289}, {-0.891007, 0.453990}, {-0.884988, 0.465615}, {-0.878817, 0.477159}, {-0.872496, 0.488621}, {-0.866025, 0.500000}, {-0.859406, 0.511293}, {-0.852640, 0.522499}, {-0.845728, 0.533615}, {-0.838671, 0.544639}, {-0.831470, 0.555570}, {-0.824126, 0.566406}, {-0.816642, 0.577145}, {-0.809017, 0.587785}, {-0.801254, 0.598325}, {-0.793353, 0.608761}, {-0.785317, 0.619094}, {-0.777146, 0.629320}, {-0.768842, 0.639439}, {-0.760406, 0.649448}, {-0.751840, 0.659346}, {-0.743145, 0.669131}, {-0.734322, 0.678801}, {-0.725374, 0.688355}, {-0.716302, 0.697790}, {-0.707107, 0.707107}, {-0.697790, 0.716302}, {-0.688355, 0.725374}, {-0.678801, 0.734322}, {-0.669131, 0.743145}, {-0.659346, 0.751840}, {-0.649448, 0.760406}, {-0.639439, 0.768842}, {-0.629320, 0.777146}, {-0.619094, 0.785317}, {-0.608761, 0.793353}, {-0.598325, 0.801254}, {-0.587785, 0.809017}, {-0.577145, 0.816642}, {-0.566406, 0.824126}, {-0.555570, 0.831470}, {-0.544639, 0.838671}, {-0.533615, 0.845728}, {-0.522499, 0.852640}, {-0.511293, 0.859406}, {-0.500000, 0.866025}, {-0.488621, 0.872496}, {-0.477159, 0.878817}, {-0.465615, 0.884988}, {-0.453990, 0.891007}, {-0.442289, 0.896873}, {-0.430511, 0.902585}, {-0.418660, 0.908143}, {-0.406737, 0.913545}, {-0.394744, 0.918791}, {-0.382683, 0.923880}, {-0.370557, 0.928810}, {-0.358368, 0.933580}, {-0.346117, 0.938191}, {-0.333807, 0.942641}, {-0.321439, 0.946930}, {-0.309017, 0.951057}, {-0.296542, 0.955020}, {-0.284015, 0.958820}, {-0.271440, 0.962455}, {-0.258819, 0.965926}, {-0.246153, 0.969231}, {-0.233445, 0.972370}, {-0.220697, 0.975342}, {-0.207912, 0.978148}, {-0.195090, 0.980785}, {-0.182236, 0.983255}, {-0.169350, 0.985556}, {-0.156434, 0.987688}, {-0.143493, 0.989651}, {-0.130526, 0.991445}, {-0.117537, 0.993068}, {-0.104528, 0.994522}, {-0.091502, 0.995805}, {-0.078459, 0.996917}, {-0.065403, 0.997859}, {-0.052336, 0.998630}, {-0.039260, 0.999229}, {-0.026177, 0.999657}, {-0.013090, 0.999914}, {-0.000000, 1.000000}, {0.013090, 0.999914}, {0.026177, 0.999657}, {0.039260, 0.999229}, {0.052336, 0.998630}, {0.065403, 0.997859}, {0.078459, 0.996917}, {0.091502, 0.995805}, {0.104528, 0.994522}, {0.117537, 0.993068}, {0.130526, 0.991445}, {0.143493, 0.989651}, {0.156434, 0.987688}, {0.169350, 0.985556}, {0.182236, 0.983255}, {0.195090, 0.980785}, {0.207912, 0.978148}, {0.220697, 0.975342}, {0.233445, 0.972370}, {0.246153, 0.969231}, {0.258819, 0.965926}, {0.271440, 0.962455}, {0.284015, 0.958820}, {0.296542, 0.955020}, {0.309017, 0.951057}, {0.321439, 0.946930}, {0.333807, 0.942641}, {0.346117, 0.938191}, {0.358368, 0.933580}, {0.370557, 0.928810}, {0.382683, 0.923880}, {0.394744, 0.918791}, {0.406737, 0.913545}, {0.418660, 0.908143}, {0.430511, 0.902585}, {0.442289, 0.896873}, {0.453990, 0.891007}, {0.465615, 0.884988}, {0.477159, 0.878817}, {0.488621, 0.872496}, {0.500000, 0.866025}, {0.511293, 0.859406}, {0.522499, 0.852640}, {0.533615, 0.845728}, {0.544639, 0.838671}, {0.555570, 0.831470}, {0.566406, 0.824126}, {0.577145, 0.816642}, {0.587785, 0.809017}, {0.598325, 0.801254}, {0.608761, 0.793353}, {0.619094, 0.785317}, {0.629320, 0.777146}, {0.639439, 0.768842}, {0.649448, 0.760406}, {0.659346, 0.751840}, {0.669131, 0.743145}, {0.678801, 0.734322}, {0.688355, 0.725374}, {0.697790, 0.716302}, {0.707107, 0.707107}, {0.716302, 0.697790}, {0.725374, 0.688355}, {0.734322, 0.678801}, {0.743145, 0.669131}, {0.751840, 0.659346}, {0.760406, 0.649448}, {0.768842, 0.639439}, {0.777146, 0.629320}, {0.785317, 0.619094}, {0.793353, 0.608761}, {0.801254, 0.598325}, {0.809017, 0.587785}, {0.816642, 0.577145}, {0.824126, 0.566406}, {0.831470, 0.555570}, {0.838671, 0.544639}, {0.845728, 0.533615}, {0.852640, 0.522499}, {0.859406, 0.511293}, {0.866025, 0.500000}, {0.872496, 0.488621}, {0.878817, 0.477159}, {0.884988, 0.465615}, {0.891007, 0.453990}, {0.896873, 0.442289}, {0.902585, 0.430511}, {0.908143, 0.418660}, {0.913545, 0.406737}, {0.918791, 0.394744}, {0.923880, 0.382683}, {0.928810, 0.370557}, {0.933580, 0.358368}, {0.938191, 0.346117}, {0.942641, 0.333807}, {0.946930, 0.321439}, {0.951057, 0.309017}, {0.955020, 0.296542}, {0.958820, 0.284015}, {0.962455, 0.271440}, {0.965926, 0.258819}, {0.969231, 0.246153}, {0.972370, 0.233445}, {0.975342, 0.220697}, {0.978148, 0.207912}, {0.980785, 0.195090}, {0.983255, 0.182236}, {0.985556, 0.169350}, {0.987688, 0.156434}, {0.989651, 0.143493}, {0.991445, 0.130526}, {0.993068, 0.117537}, {0.994522, 0.104528}, {0.995805, 0.091502}, {0.996917, 0.078459}, {0.997859, 0.065403}, {0.998630, 0.052336}, {0.999229, 0.039260}, {0.999657, 0.026177}, {0.999914, 0.013090}, }; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const celt_int16 fft_bitrev480[480] = { +0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330, 450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225, 345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95, 215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440, 110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310, 430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205, 325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61, 181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406, 76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276, 396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171, 291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41, 161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386, 56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242, 362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137, 257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7, 127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457, 22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352, 472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222, 342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117, 237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423, 93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318, 438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188, 308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83, 203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403, 73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298, 418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154, 274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49, 169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369, 39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264, 384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134, 254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29, 149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479, }; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const celt_int16 fft_bitrev240[240] = { +0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165, 225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110, 170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55, 115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211, 46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156, 216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101, 161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32, 92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202, 37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147, 207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78, 138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23, 83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193, 28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124, 184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69, 129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14, 74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239, }; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const celt_int16 fft_bitrev120[120] = { +0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80, 110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46, 76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26, 56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97, 22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63, 93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43, 73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9, 39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119, }; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const celt_int16 fft_bitrev60[60] = { +0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31, 46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22, 37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13, 28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59, }; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +0.002083, /* scale */ +-1, /* shift */ +{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +0.004167, /* scale */ +1, /* shift */ +{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +0.008333, /* scale */ +2, /* shift */ +{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +0.016667, /* scale */ +3, /* shift */ +{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const celt_word16 mdct_twiddles960[481] = { +1.000000, 0.999995, 0.999979, 0.999952, 0.999914, 0.999866, 0.999807, 0.999738, 0.999657, 0.999566, 0.999465, 0.999352, 0.999229, 0.999095, 0.998951, 0.998795, 0.998630, 0.998453, 0.998266, 0.998068, 0.997859, 0.997640, 0.997409, 0.997169, 0.996917, 0.996655, 0.996382, 0.996099, 0.995805, 0.995500, 0.995185, 0.994859, 0.994522, 0.994174, 0.993816, 0.993448, 0.993068, 0.992679, 0.992278, 0.991867, 0.991445, 0.991012, 0.990569, 0.990116, 0.989651, 0.989177, 0.988691, 0.988195, 0.987688, 0.987171, 0.986643, 0.986105, 0.985556, 0.984997, 0.984427, 0.983846, 0.983255, 0.982653, 0.982041, 0.981418, 0.980785, 0.980142, 0.979487, 0.978823, 0.978148, 0.977462, 0.976766, 0.976059, 0.975342, 0.974615, 0.973877, 0.973129, 0.972370, 0.971601, 0.970821, 0.970031, 0.969231, 0.968420, 0.967599, 0.966768, 0.965926, 0.965074, 0.964211, 0.963338, 0.962455, 0.961562, 0.960658, 0.959744, 0.958820, 0.957885, 0.956940, 0.955985, 0.955020, 0.954044, 0.953059, 0.952063, 0.951057, 0.950040, 0.949014, 0.947977, 0.946930, 0.945873, 0.944806, 0.943729, 0.942641, 0.941544, 0.940437, 0.939319, 0.938191, 0.937054, 0.935906, 0.934748, 0.933580, 0.932403, 0.931215, 0.930017, 0.928810, 0.927592, 0.926364, 0.925127, 0.923880, 0.922622, 0.921355, 0.920078, 0.918791, 0.917494, 0.916188, 0.914872, 0.913545, 0.912210, 0.910864, 0.909508, 0.908143, 0.906768, 0.905384, 0.903989, 0.902585, 0.901172, 0.899748, 0.898315, 0.896873, 0.895421, 0.893959, 0.892487, 0.891007, 0.889516, 0.888016, 0.886507, 0.884988, 0.883459, 0.881921, 0.880374, 0.878817, 0.877251, 0.875675, 0.874090, 0.872496, 0.870892, 0.869279, 0.867657, 0.866025, 0.864385, 0.862734, 0.861075, 0.859406, 0.857729, 0.856042, 0.854345, 0.852640, 0.850926, 0.849202, 0.847470, 0.845728, 0.843977, 0.842217, 0.840448, 0.838671, 0.836884, 0.835088, 0.833283, 0.831470, 0.829647, 0.827816, 0.825975, 0.824126, 0.822268, 0.820401, 0.818526, 0.816642, 0.814748, 0.812847, 0.810936, 0.809017, 0.807089, 0.805153, 0.803208, 0.801254, 0.799291, 0.797321, 0.795341, 0.793353, 0.791357, 0.789352, 0.787339, 0.785317, 0.783287, 0.781248, 0.779201, 0.777146, 0.775082, 0.773010, 0.770930, 0.768842, 0.766745, 0.764640, 0.762527, 0.760406, 0.758277, 0.756139, 0.753994, 0.751840, 0.749678, 0.747508, 0.745331, 0.743145, 0.740951, 0.738750, 0.736540, 0.734322, 0.732097, 0.729864, 0.727623, 0.725374, 0.723118, 0.720854, 0.718582, 0.716302, 0.714015, 0.711720, 0.709417, 0.707107, 0.704789, 0.702464, 0.700131, 0.697790, 0.695443, 0.693087, 0.690725, 0.688355, 0.685977, 0.683592, 0.681200, 0.678801, 0.676394, 0.673980, 0.671559, 0.669131, 0.666695, 0.664252, 0.661803, 0.659346, 0.656882, 0.654411, 0.651933, 0.649448, 0.646956, 0.644457, 0.641952, 0.639439, 0.636920, 0.634393, 0.631860, 0.629320, 0.626774, 0.624221, 0.621661, 0.619094, 0.616521, 0.613941, 0.611354, 0.608761, 0.606162, 0.603556, 0.600944, 0.598325, 0.595699, 0.593068, 0.590430, 0.587785, 0.585135, 0.582478, 0.579815, 0.577145, 0.574470, 0.571788, 0.569100, 0.566406, 0.563706, 0.561000, 0.558288, 0.555570, 0.552846, 0.550116, 0.547381, 0.544639, 0.541892, 0.539138, 0.536379, 0.533615, 0.530844, 0.528068, 0.525286, 0.522499, 0.519706, 0.516907, 0.514103, 0.511293, 0.508478, 0.505657, 0.502831, 0.500000, 0.497163, 0.494321, 0.491474, 0.488621, 0.485763, 0.482900, 0.480032, 0.477159, 0.474280, 0.471397, 0.468508, 0.465615, 0.462716, 0.459812, 0.456904, 0.453990, 0.451072, 0.448149, 0.445221, 0.442289, 0.439351, 0.436409, 0.433463, 0.430511, 0.427555, 0.424595, 0.421629, 0.418660, 0.415686, 0.412707, 0.409724, 0.406737, 0.403745, 0.400749, 0.397748, 0.394744, 0.391735, 0.388722, 0.385705, 0.382683, 0.379658, 0.376628, 0.373595, 0.370557, 0.367516, 0.364471, 0.361421, 0.358368, 0.355311, 0.352250, 0.349185, 0.346117, 0.343045, 0.339969, 0.336890, 0.333807, 0.330720, 0.327630, 0.324537, 0.321439, 0.318339, 0.315235, 0.312128, 0.309017, 0.305903, 0.302786, 0.299665, 0.296542, 0.293415, 0.290285, 0.287152, 0.284015, 0.280876, 0.277734, 0.274589, 0.271440, 0.268289, 0.265135, 0.261979, 0.258819, 0.255657, 0.252492, 0.249324, 0.246153, 0.242980, 0.239804, 0.236626, 0.233445, 0.230262, 0.227076, 0.223888, 0.220697, 0.217504, 0.214309, 0.211112, 0.207912, 0.204710, 0.201505, 0.198299, 0.195090, 0.191880, 0.188667, 0.185452, 0.182236, 0.179017, 0.175796, 0.172574, 0.169350, 0.166123, 0.162895, 0.159666, 0.156434, 0.153201, 0.149967, 0.146730, 0.143493, 0.140253, 0.137012, 0.133770, 0.130526, 0.127281, 0.124034, 0.120787, 0.117537, 0.114287, 0.111035, 0.107782, 0.104528, 0.101273, 0.098017, 0.094760, 0.091502, 0.088242, 0.084982, 0.081721, 0.078459, 0.075196, 0.071933, 0.068668, 0.065403, 0.062137, 0.058871, 0.055604, 0.052336, 0.049068, 0.045799, 0.042530, 0.039260, 0.035990, 0.032719, 0.029448, 0.026177, 0.022905, 0.019634, 0.016362, 0.013090, 0.009817, 0.006545, 0.003272, 0.000000, }; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{0.850006, 0.000000, 1.000000, 1.000000, }, /* preemph */ +eband5ms, /* eBands */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +window120, /* window */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +logN400, /* logN */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/native/codec/libraries/celt/libcelt/testcelt.c b/native/codec/libraries/celt/libcelt/testcelt.c new file mode 100644 index 0000000..d889a5b --- /dev/null +++ b/native/codec/libraries/celt/libcelt/testcelt.c @@ -0,0 +1,206 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt.h" +#include "arch.h" +#include +#include +#include +#include + +#define MAX_PACKET 1275 + +int main(int argc, char *argv[]) +{ + int err; + char *inFile, *outFile; + FILE *fin, *fout; + CELTMode *mode=NULL; + CELTEncoder *enc; + CELTDecoder *dec; + int len; + celt_int32 frame_size, channels; + int bytes_per_packet; + unsigned char data[MAX_PACKET]; + int rate; + int complexity; +#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH) + int i; + double rmsd = 0; +#endif + int count = 0; + celt_int32 skip; + celt_int16 *in, *out; + if (argc != 9 && argc != 8 && argc != 7) + { + fprintf (stderr, "Usage: testcelt " + " [ [packet loss rate]] " + " \n"); + return 1; + } + + rate = atoi(argv[1]); + channels = atoi(argv[2]); + frame_size = atoi(argv[3]); + mode = celt_mode_create(rate, frame_size, NULL); + if (mode == NULL) + { + fprintf(stderr, "failed to create a mode\n"); + return 1; + } + + bytes_per_packet = atoi(argv[4]); + if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET) + { + fprintf (stderr, "bytes per packet must be between 0 and %d\n", + MAX_PACKET); + return 1; + } + + inFile = argv[argc-2]; + fin = fopen(inFile, "rb"); + if (!fin) + { + fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); + return 1; + } + outFile = argv[argc-1]; + fout = fopen(outFile, "wb+"); + if (!fout) + { + fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); + return 1; + } + + enc = celt_encoder_create_custom(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the encoder: %s\n", celt_strerror(err)); + return 1; + } + dec = celt_decoder_create_custom(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the decoder: %s\n", celt_strerror(err)); + return 1; + } + celt_decoder_ctl(dec, CELT_GET_LOOKAHEAD(&skip)); + + if (argc>7) + { + complexity=atoi(argv[5]); + celt_encoder_ctl(enc,CELT_SET_COMPLEXITY(complexity)); + } + + in = (celt_int16*)malloc(frame_size*channels*sizeof(celt_int16)); + out = (celt_int16*)malloc(frame_size*channels*sizeof(celt_int16)); + + while (!feof(fin)) + { + int ret; + err = fread(in, sizeof(short), frame_size*channels, fin); + if (feof(fin)) + break; + len = celt_encode(enc, in, frame_size, data, bytes_per_packet); + if (len <= 0) + fprintf (stderr, "celt_encode() failed: %s\n", celt_strerror(len)); + + /* This is for simulating bit errors */ +#if 0 + int errors = 0; + int eid = 0; + /* This simulates random bit error */ + for (i=0;i 0) + { + rmsd = sqrt(rmsd/(1.0*frame_size*channels*count)); + fprintf (stderr, "Error: encoder doesn't match decoder\n"); + fprintf (stderr, "RMS mismatch is %f\n", rmsd); + return 1; + } else { + fprintf (stderr, "Encoder matches decoder!!\n"); + } +#endif + return 0; +} + diff --git a/native/codec/libraries/celt/libcelt/vq.c b/native/codec/libraries/celt/libcelt/vq.c new file mode 100644 index 0000000..22aa03b --- /dev/null +++ b/native/codec/libraries/celt/libcelt/vq.c @@ -0,0 +1,430 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "cwrs.h" +#include "vq.h" +#include "arch.h" +#include "os_support.h" +#include "bands.h" +#include "rate.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +static void exp_rotation1(celt_norm *X, int len, int stride, celt_word16 c, celt_word16 s) +{ + int i; + celt_norm *Xptr; + Xptr = X; + for (i=0;i=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(SHR32(MULT16_16(c,x2) + MULT16_16(s,x1), 15)); + *Xptr-- = EXTRACT16(SHR32(MULT16_16(c,x1) - MULT16_16(s,x2), 15)); + } +} + +static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread) +{ + static const int SPREAD_FACTOR[3]={15,10,5}; + int i; + celt_word16 c, s; + celt_word16 gain, theta; + int stride2=0; + int factor; + /*int i; + if (len>=30) + { + for (i=0;i=len || spread==SPREAD_NONE) + return; + factor = SPREAD_FACTOR[spread-1]; + + gain = celt_div((celt_word32)MULT16_16(Q15_ONE,len),(celt_word32)(len+factor*K)); + /* FIXME: Make that HALF16 instead of HALF32 */ + theta = HALF32(MULT16_16_Q15(gain,gain)); + + c = celt_cos_norm(EXTEND32(theta)); + s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */ + + if (len>=8*stride) + { + stride2 = 1; + /* This is just a simple way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. + I _think_ it is bit-exact */ + while ((stride2*stride2+stride2)*stride + (stride>>2) < len) + stride2++; + } + /*TODO: We should be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ + len /= stride; + for (i=0;i=30) + { + for (i=0;i>1; +#endif + t = VSHR32(Ryy, (k-7)<<1); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + i=0; + do + X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1)); + while (++i < N); +} + +static unsigned extract_collapse_mask(int *iy, int N, int B) +{ + unsigned collapse_mask; + int N0; + int i; + if (B<=1) + return 1; + /*TODO: We should be passing around log2(B), not B, for both this and for + exp_rotation().*/ + N0 = N/B; + collapse_mask = 0; + i=0; do { + int j; + j=0; do { + collapse_mask |= (iy[i*N0+j]!=0)<0) + signx[j]=1; + else { + signx[j]=-1; + X[j]=-X[j]; + } + iy[j] = 0; + y[j] = 0; + } while (++j (N>>1)) + { + celt_word16 rcp; + j=0; do { + sum += X[j]; + } while (++j=1, "Allocated too many pulses in the quick pass"); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ +#ifdef FIXED_POINT_DEBUG + celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass"); +#endif + if (pulsesLeft > N+3) + { + celt_word16 tmp = pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + s = 1; + for (i=0;i= best_num/best_den, but that way + we can do it without any division */ + /* OPT: Make sure to use conditional moves here */ + if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num)) + { + best_den = Ryy; + best_num = Rxy; + best_id = j; + } + } while (++j>1; +#endif + t = VSHR32(E, (k-7)<<1); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i +#include + +#define CELT_C +#include "../libcelt/stack_alloc.h" +#include "../libcelt/entenc.c" +#include "../libcelt/entdec.c" +#include "../libcelt/entcode.c" +#include "../libcelt/cwrs.c" +#include "../libcelt/mathops.c" + +#define NMAX (14) +#define KMAX (32767) + +static const int kmax[15]={ + 32767,32767,32767,32767, 1172, + 238, 95, 53, 36, 27, + 22, 18, 16, 15, 13 +}; + + +int main(int _argc,char **_argv){ + int n; + ALLOC_STACK; + for(n=2;n<=NMAX;n++){ + int dk; + int k; + dk=kmax[n]>7?kmax[n]/7:1; + k=1-dk; + do{ + celt_uint32 uu[KMAX+2U]; + celt_uint32 inc; + celt_uint32 nc; + celt_uint32 i; + k=kmax[n]-dk");*/ + ii=icwrs(n,k,&v,y,u); + if(ii!=i){ + fprintf(stderr,"Combination-index mismatch (%lu!=%lu).\n", + (long)ii,(long)i); + return 1; + } + if(v!=nc){ + fprintf(stderr,"Combination count mismatch (%lu!=%lu).\n", + (long)v,(long)nc); + return 2; + } +#ifndef SMALL_FOOTPRINT + if(n==2){ + cwrsi2(k,i,yy); + for(j=0;j<2;j++)if(yy[j]!=y[j]){ + fprintf(stderr,"N=2 pulse vector mismatch ({%i,%i}!={%i,%i}).\n", + yy[0],yy[1],y[0],y[1]); + return 3; + } + ii=icwrs2(yy,&kk); + if(ii!=i){ + fprintf(stderr,"N=2 combination-index mismatch (%lu!=%lu).\n", + (long)ii,(long)i); + return 4; + } + if(kk!=k){ + fprintf(stderr,"N=2 pulse count mismatch (%i,%i).\n",kk,k); + return 5; + } + v=ncwrs2(k); + if(v!=nc){ + fprintf(stderr,"N=2 combination count mismatch (%lu,%lu).\n", + (long)v,(long)nc); + return 6; + } + } + else if(n==3){ + cwrsi3(k,i,yy); + for(j=0;j<3;j++)if(yy[j]!=y[j]){ + fprintf(stderr,"N=3 pulse vector mismatch " + "({%i,%i,%i}!={%i,%i,%i}).\n",yy[0],yy[1],yy[2],y[0],y[1],y[2]); + return 7; + } + ii=icwrs3(yy,&kk); + if(ii!=i){ + fprintf(stderr,"N=3 combination-index mismatch (%lu!=%lu).\n", + (long)ii,(long)i); + return 8; + } + if(kk!=k){ + fprintf(stderr,"N=3 pulse count mismatch (%i!=%i).\n",kk,k); + return 9; + } + v=ncwrs3(k); + if(v!=nc){ + fprintf(stderr,"N=3 combination count mismatch (%lu!=%lu).\n", + (long)v,(long)nc); + return 10; + } + } + else if(n==4){ + cwrsi4(k,i,yy); + for(j=0;j<4;j++)if(yy[j]!=y[j]){ + fprintf(stderr,"N=4 pulse vector mismatch " + "({%i,%i,%i,%i}!={%i,%i,%i,%i}.\n", + yy[0],yy[1],yy[2],yy[3],y[0],y[1],y[2],y[3]); + return 11; + } + ii=icwrs4(yy,&kk); + if(ii!=i){ + fprintf(stderr,"N=4 combination-index mismatch (%lu!=%lu).\n", + (long)ii,(long)i); + return 12; + } + if(kk!=k){ + fprintf(stderr,"N=4 pulse count mismatch (%i!=%i).\n",kk,k); + return 13; + } + v=ncwrs4(k); + if(v!=nc){ + fprintf(stderr,"N=4 combination count mismatch (%lu!=%lu).\n", + (long)v,(long)nc); + return 14; + } + } + else if(n==5){ + cwrsi5(k,i,yy); + for(j=0;j<5;j++)if(yy[j]!=y[j]){ + fprintf(stderr,"N=5 pulse vector mismatch " + "({%i,%i,%i,%i,%i}!={%i,%i,%i,%i,%i}).\n", + yy[0],yy[1],yy[2],yy[3],yy[4],y[0],y[1],y[2],y[3],y[4]); + return 15; + } + ii=icwrs5(yy,&kk); + if(ii!=i){ + fprintf(stderr,"N=5 combination-index mismatch (%lu!=%lu).\n", + (long)ii,(long)i); + return 16; + } + if(kk!=k){ + fprintf(stderr,"N=5 pulse count mismatch (%i!=%i).\n",kk,k); + return 17; + } + v=ncwrs5(k); + if(v!=nc){ + fprintf(stderr,"N=5 combination count mismatch (%lu!=%lu).\n", + (long)v,(long)nc); + return 18; + } + } +#endif /* SMALL_FOOTPRINT */ + + /*printf(" %6u\n",i);*/ + } + /*printf("\n");*/ + } + while(k +#include "kiss_fft.h" + +#define CELT_C +#include "../libcelt/stack_alloc.h" +#include "../libcelt/kiss_fft.c" +#include "../libcelt/mathops.c" +#include "../libcelt/entcode.c" + + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifdef FIXED_DEBUG +long long celt_mips=0; +#endif +int ret = 0; + +void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse) +{ + int bin,k; + double errpow=0,sigpow=0, snr; + + for (bin=0;bin1) { + int k; + for (k=1;k +#include +#include +#include +#include "entcode.h" +#include "entenc.h" +#include "entdec.h" +#include + +#include "../libcelt/entenc.c" +#include "../libcelt/entdec.c" +#include "../libcelt/entcode.c" + +#ifndef M_LOG2E +# define M_LOG2E 1.4426950408889634074 +#endif +#define DATA_SIZE 10000000 +#define DATA_SIZE2 10000 + +int main(int _argc,char **_argv){ + ec_enc enc; + ec_dec dec; + long nbits; + long nbits2; + double entropy; + int ft; + int ftb; + int sym; + int sz; + int i; + int ret; + unsigned int seed; + unsigned char *ptr; + ret=0; + entropy=0; + if (_argc > 2) { + fprintf(stderr, "Usage: %s []\n", _argv[0]); + return 1; + } + if (_argc > 1) + seed = atoi(_argv[1]); + else + seed = time(NULL); + /*Testing encoding of raw bit values.*/ + ptr = malloc(DATA_SIZE); + ec_enc_init(&enc,ptr, DATA_SIZE); + for(ft=2;ft<1024;ft++){ + for(i=0;i>(rand()%11))+1)+10; + sz=rand()/((RAND_MAX>>(rand()%9))+1); + data=(unsigned *)malloc(sz*sizeof(*data)); + tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); + ec_enc_init(&enc,ptr,DATA_SIZE2); + zeros = rand()%13==0; + tell[0]=ec_tell_frac(&enc); + for(j=0;j>(rand()%9))+1); + logp1=(unsigned *)malloc(sz*sizeof(*logp1)); + data=(unsigned *)malloc(sz*sizeof(*data)); + tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); + enc_method=(unsigned *)malloc(sz*sizeof(*enc_method)); + ec_enc_init(&enc,ptr,DATA_SIZE2); + tell[0]=ec_tell_frac(&enc); + for(j=0;j>1)+1); + logp1[j]=(rand()%15)+1; + enc_method[j]=rand()/((RAND_MAX>>2)+1); + switch(enc_method[j]){ + case 0:{ + ec_encode(&enc,data[j]?(1<>2)+1); + switch(dec_method){ + case 0:{ + fs=ec_decode(&dec,1<=(1<=(1< +#include +#include "laplace.h" +#define CELT_C +#include "../libcelt/stack_alloc.h" + +#include "../libcelt/entenc.c" +#include "../libcelt/entdec.c" +#include "../libcelt/entcode.c" +#include "../libcelt/laplace.c" + +#define DATA_SIZE 40000 + +int ec_laplace_get_start_freq(int decay) +{ + celt_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1); + int fs = (ft*(16384-decay))/(16384+decay); + return fs+LAPLACE_MINP; +} + +int main(void) +{ + int i; + int ret = 0; + ec_enc enc; + ec_dec dec; + unsigned char *ptr; + int val[10000], decay[10000]; + ALLOC_STACK; + ptr = malloc(DATA_SIZE); + ec_enc_init(&enc,ptr,DATA_SIZE); + + val[0] = 3; decay[0] = 6000; + val[1] = 0; decay[1] = 5800; + val[2] = -1; decay[2] = 5600; + for (i=3;i<10000;i++) + { + val[i] = rand()%15-7; + decay[i] = rand()%11000+5000; + } + for (i=0;i<10000;i++) + ec_laplace_encode(&enc, &val[i], + ec_laplace_get_start_freq(decay[i]), decay[i]); + + ec_enc_done(&enc); + + ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc)); + + for (i=0;i<10000;i++) + { + int d = ec_laplace_decode(&dec, + ec_laplace_get_start_freq(decay[i]), decay[i]); + if (d != val[i]) + { + fprintf (stderr, "Got %d instead of %d\n", d, val[i]); + ret = 1; + } + } + + return ret; +} diff --git a/native/codec/libraries/celt/tests/mathops-test.c b/native/codec/libraries/celt/tests/mathops-test.c new file mode 100644 index 0000000..23a152c --- /dev/null +++ b/native/codec/libraries/celt/tests/mathops-test.c @@ -0,0 +1,172 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.c" +#include "entcode.c" +#include +#include + +#ifdef FIXED_POINT +#define WORD "%d" +#else +#define WORD "%f" +#endif + +#ifdef FIXED_DEBUG +long long celt_mips=0; +#endif +int ret = 0; + +void testdiv(void) +{ + celt_int32 i; + for (i=1;i<=327670;i++) + { + double prod; + celt_word32 val; + val = celt_rcp(i); +#ifdef FIXED_POINT + prod = (1./32768./65526.)*val*i; +#else + prod = val*i; +#endif + if (fabs(prod-1) > .00025) + { + fprintf (stderr, "div failed: 1/%d="WORD" (product = %f)\n", i, val, prod); + ret = 1; + } + } +} + +void testsqrt(void) +{ + celt_int32 i; + for (i=1;i<=1000000000;i++) + { + double ratio; + celt_word16 val; + val = celt_sqrt(i); + ratio = val/sqrt(i); + if (fabs(ratio - 1) > .0005 && fabs(val-sqrt(i)) > 2) + { + fprintf (stderr, "sqrt failed: sqrt(%d)="WORD" (ratio = %f)\n", i, val, ratio); + ret = 1; + } + i+= i>>10; + } +} + +#ifndef FIXED_POINT +void testlog2(void) +{ + float x; + for (x=0.001;x<1677700.0;x+=(x/8.0)) + { + float error = fabs((1.442695040888963387*log(x))-celt_log2(x)); + if (error>0.0009) + { + fprintf (stderr, "celt_log2 failed: fabs((1.442695040888963387*log(x))-celt_log2(x))>0.001 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} + +void testexp2(void) +{ + float x; + for (x=-11.0;x<24.0;x+=0.0007) + { + float error = fabs(x-(1.442695040888963387*log(celt_exp2(x)))); + if (error>0.0002) + { + fprintf (stderr, "celt_exp2 failed: fabs(x-(1.442695040888963387*log(celt_exp2(x))))>0.0005 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} + +void testexp2log2(void) +{ + float x; + for (x=-11.0;x<24.0;x+=0.0007) + { + float error = fabs(x-(celt_log2(celt_exp2(x)))); + if (error>0.001) + { + fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_log2(celt_exp2(x))))>0.001 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} +#else +void testlog2(void) +{ + celt_word32 x; + for (x=8;x<1073741824;x+=(x>>3)) + { + float error = fabs((1.442695040888963387*log(x/16384.0))-celt_log2(x)/1024.0); + if (error>0.003) + { + fprintf (stderr, "celt_log2 failed: x = %ld, error = %f\n", (long)x,error); + ret = 1; + } + } +} + +void testexp2(void) +{ + celt_word16 x; + for (x=-32768;x<-30720;x++) + { + float error1 = fabs(x/2048.0-(1.442695040888963387*log(celt_exp2(x)/65536.0))); + float error2 = fabs(exp(0.6931471805599453094*x/2048.0)-celt_exp2(x)/65536.0); + if (error1>0.0002&&error2>0.00004) + { + fprintf (stderr, "celt_exp2 failed: x = "WORD", error1 = %f, error2 = %f\n", x,error1,error2); + ret = 1; + } + } +} + +void testexp2log2(void) +{ + celt_word32 x; + for (x=8;x<65536;x+=(x>>3)) + { + float error = fabs(x-0.25*celt_exp2(celt_log2(x)<<1))/16384; + if (error>0.004) + { + fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_exp2(celt_log2(x))))>0.001 (x = %ld, error = %f)\n", (long)x,error); + ret = 1; + } + } +} + +void testilog2(void) +{ + celt_word32 x; + for (x=1;x<=268435455;x+=127) + { + celt_word32 error = abs(celt_ilog2(x)-(int)floor(log2(x))); + if (error!=0) + { + printf("celt_ilog2 failed: celt_ilog2(x)!=floor(log2(x)) (x = %d, error = %d)\n",x,error); + ret = 1; + } + } +} +#endif + +int main(void) +{ + testdiv(); + testsqrt(); + testlog2(); + testexp2(); + testexp2log2(); +#ifdef FIXED_POINT + testilog2(); +#endif + return ret; +} diff --git a/native/codec/libraries/celt/tests/mdct-test.c b/native/codec/libraries/celt/tests/mdct-test.c new file mode 100644 index 0000000..1b875c7 --- /dev/null +++ b/native/codec/libraries/celt/tests/mdct-test.c @@ -0,0 +1,169 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define SKIP_CONFIG_H + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#endif + +#include +#include "mdct.h" +#define CELT_C +#include "../libcelt/stack_alloc.h" + +#include "../libcelt/kiss_fft.c" +#include "../libcelt/mdct.c" +#include "../libcelt/mathops.c" +#include "../libcelt/entcode.c" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifdef FIXED_DEBUG +long long celt_mips=0; +#endif +int ret = 0; +void check(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse) +{ + int bin,k; + double errpow=0,sigpow=0; + double snr; + for (bin=0;bin1) { + int k; + for (k=1;k +#include + +#define CELT_C +#include "../libcelt/stack_alloc.h" +#include "../libcelt/kiss_fft.c" +#include "../libcelt/kiss_fftr.c" + +#ifdef FIXED_DEBUG +long long celt_mips=0; +#endif +int ret=0; + +static +kiss_fft_scalar rand_scalar(void) +{ + return (rand()%32767)-16384; +} + +static +double snr_compare( kiss_fft_cpx * vec1,kiss_fft_scalar * vec2, int n) +{ + int k; + double sigpow=1e-10, noisepow=1e-10, err,snr; + + vec1[0].i = vec1[n].r; + for (k=0;k +#include +#include "celt_types.h" +#include "bands.h" +#include +#define MAX_SIZE 100 + +int ret=0; +void test_rotation(int N, int K) +{ + int i; + double err = 0, ener = 0, snr, snr0; + celt_word16 x0[MAX_SIZE]; + celt_word16 x1[MAX_SIZE]; + int nb_rotations = (N+4*K)/(8*K); + for (i=0;i 20) + ret = 1; +} + +int main(void) +{ + test_rotation(15, 3); + test_rotation(23, 5); + test_rotation(50, 3); + test_rotation(80, 1); + return ret; +} diff --git a/native/codec/libraries/celt/tests/tandem-test.c b/native/codec/libraries/celt/tests/tandem-test.c new file mode 100644 index 0000000..3070d1d --- /dev/null +++ b/native/codec/libraries/celt/tests/tandem-test.c @@ -0,0 +1,204 @@ +/* (C) 2009 Gregory Maxwell + + This test runs pink noise through the encoder and decoder many times + while feeding the output back into the input. It checks that after + a number of cycles the energy has not increased or decreased by too + large an amount. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt.h" +#include "arch.h" +#include +#include +#include +#include +#include +#include + +#ifndef _MSC_VER +#include +#endif + +int async_tandem(int rate, int frame_size, int channels, int bitrate_min, + int bitrate_max) +{ + int error; + unsigned char data[648]; + CELTMode *mode = NULL; + CELTEncoder *enc; + short carry[2]; + short pcm[960 * 2]; + CELTDecoder *dec; + int bmin, bmax; + float ms; + int ret, i, j, bytes_per_frame; + int increment = 1; + + bmin = floor((bitrate_min / (rate / (float) frame_size)) / 8.0); + bmax = ceil((bitrate_max / (rate / (float) frame_size)) / 8.0); + if (bmin < 8) + bmin = 8; + if (bmax > 640) + bmax = 640; + if (bmin >= bmax) + bmax = bmin + 8; + + increment += (bmax - bmin) / 128; + + printf ("Testing asynchronous tandeming (%dHz, %dch, %d samples, %d - %d bytes).\n", + rate, channels, frame_size, bmin, bmax); + + mode = celt_mode_create(rate, frame_size, &error); + if (mode == NULL || error) { + fprintf(stderr, "Error: failed to create a mode: %s\n", celt_strerror(error)); + exit(1); + } + + dec = celt_decoder_create_custom(mode, channels, &error); + if (error){ + fprintf(stderr, "Error: celt_decoder_create returned %s\n", celt_strerror(error)); + exit(1); + } + enc = celt_encoder_create_custom(mode, channels, &error); + if (error){ + fprintf(stderr, "Error: celt_encoder_create returned %s\n", celt_strerror(error)); + exit(1); + } + + for (j = 0; j < frame_size * channels; j++) + pcm[j] = 0; + + for (bytes_per_frame = bmin; bytes_per_frame <= bmax; + bytes_per_frame += increment) { + /*Prime the encoder and decoder */ + for (i = 0; i < (1024 + (frame_size >> 1)) / frame_size + 2; i++) { + + for (j = 0; j < channels; j++) + pcm[j] = pcm[frame_size * channels - (channels - j + 1)]; + for (j = channels; j < frame_size * channels - 1; j++) + pcm[j] = ((rand() % 4096) - 2048) + .9 * pcm[j - channels]; + + ret = celt_encode(enc, pcm, frame_size, data, bytes_per_frame); + if (ret != bytes_per_frame) { + fprintf(stderr, "Error: celt_encode returned %s\n", celt_strerror(ret)); + exit(1); + } + + ret = celt_decode(dec, data, ret, pcm, frame_size); + if (ret < 0) { + fprintf(stderr, "Error: celt_decode returned %s\n", celt_strerror(ret)); + } + } + + for (j = 0; j < channels; j++) + pcm[j] = pcm[frame_size * channels - (channels - j)]; + for (j = channels; j < frame_size * channels - 1; j++) + pcm[j] = ((rand() % 4096) - 2048) + .9 * pcm[j - channels]; + + for (i = 0; i < 8; i++) { + for (j = 0; j < channels; j++) + carry[j] = pcm[frame_size * channels - (channels - j)]; + memmove(pcm + channels, pcm, sizeof(short) * frame_size * channels); + for (j = 0; j < channels; j++) + pcm[j] = carry[j]; + + ret = celt_encode(enc, pcm, frame_size, data, bytes_per_frame); + if (ret != bytes_per_frame) { + fprintf(stderr, "Error: at %d bytes_per_frame celt_encode returned %s\n", + bytes_per_frame, celt_strerror(ret)); + exit(1); + } + + ret = celt_decode(dec, data, ret, pcm, frame_size); + if (ret < 0) { + fprintf(stderr, "Error: at %d bytes_per_frame celt_decode returned %s\n", + bytes_per_frame, celt_strerror(ret)); + exit(1); + } + } + ms = 0; + for (j = 0; j < frame_size * channels; j++) + ms += pcm[j] * pcm[j]; + ms = sqrt(ms / (frame_size * channels)); + if (ms > 7000 || ms < 1000) { + fprintf(stderr, "Error: Signal out of expected range. %d %d %d %d %f\n", + rate, channels, frame_size, bytes_per_frame, ms); + exit(1); + } + } + + celt_encoder_destroy(enc); + celt_decoder_destroy(dec); + celt_mode_destroy(mode); + + return 0; +} + +int main(int argc, char *argv[]) +{ +#ifdef CUSTOM_MODES + int sizes[8]={960,512,480,256,240,128,120,64}; +#else + int sizes[4]={960,480,240,120}; +#endif + unsigned int seed; + int ch, n; + + if (argc > 2) { + fprintf(stderr, "Usage: %s []\n", argv[0]); + return 1; + } + + if (argc > 1) + seed = atoi(argv[1]); + else + seed = (time(NULL) ^ ((getpid() % 65536) << 16)); + + srand(seed); + printf("CELT codec tests. Random seed: %u (%.4X)\n", seed, rand() % 65536); + +#ifdef CUSTOM_MODES + for (n = 0; n < 8; n++) { + for (ch = 1; ch <= 2; ch++) { + async_tandem(48000, sizes[n], ch, 12000 * ch, 128000 * ch); + async_tandem(44100, sizes[n], ch, 12000 * ch, 128000 * ch); + if(n>0)async_tandem(32000, sizes[n], ch, 12000 * ch, 128000 * ch); + if(n>2)async_tandem(16000, sizes[n], ch, 12000 * ch, 64000 * ch); + } + } +#else + for (n = 0; n < 4; n++) { + for (ch = 1; ch <= 2; ch++) { + async_tandem(48000, sizes[n], ch, 12000 * ch, 128000 * ch); + } + } +#endif + return 0; +} diff --git a/native/codec/libraries/celt/tests/type-test.c b/native/codec/libraries/celt/tests/type-test.c new file mode 100644 index 0000000..e0b1e62 --- /dev/null +++ b/native/codec/libraries/celt/tests/type-test.c @@ -0,0 +1,23 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt_types.h" +#include + +int main(void) +{ + celt_int16 i = 1; + i <<= 14; + if (i>>14 != 1) + { + fprintf(stderr, "celt_int16 isn't 16 bits\n"); + return 1; + } + if (sizeof(celt_int16)*2 != sizeof(celt_int32)) + { + fprintf(stderr, "16*2 != 32\n"); + return 1; + } + return 0; +} diff --git a/native/codec/libraries/celt/tools/Makefile.am b/native/codec/libraries/celt/tools/Makefile.am new file mode 100644 index 0000000..65099ce --- /dev/null +++ b/native/codec/libraries/celt/tools/Makefile.am @@ -0,0 +1,21 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# $Id: Makefile.am,v 1.11 2004/02/18 06:59:40 jm Exp $ + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +INCLUDES = -I$(top_srcdir)/libcelt -I$(top_builddir)/ @OGG_CFLAGS@ + +EXTRA_DIST = getopt_win.h getopt.c getopt1.c wave_out.c wave_out.h skeleton.h + +include_HEADERS = +noinst_HEADERS = wav_io.h + +bin_PROGRAMS = celtenc celtdec + +celtenc_SOURCES = celtenc.c wav_io.c skeleton.c +celtenc_LDADD = $(top_builddir)/libcelt/libcelt@LIBCELT_SUFFIX@.la $(OGG_LIBS) + +celtdec_SOURCES = celtdec.c wav_io.c +celtdec_LDADD = $(top_builddir)/libcelt/libcelt@LIBCELT_SUFFIX@.la $(OGG_LIBS) diff --git a/native/codec/libraries/celt/tools/alsa_device.c b/native/codec/libraries/celt/tools/alsa_device.c new file mode 100644 index 0000000..aaf5db6 --- /dev/null +++ b/native/codec/libraries/celt/tools/alsa_device.c @@ -0,0 +1,429 @@ +/* + Copyright (C) 2004-2006 Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "alsa_device.h" +#include +#include + +struct AlsaDevice_ { + char *device_name; + int channels; + int period; + snd_pcm_t *capture_handle; + snd_pcm_t *playback_handle; + int readN, writeN; + struct pollfd *read_fd, *write_fd; +}; + +#define PERIODS 3 +AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period) +{ + int dir; + int err; + snd_pcm_hw_params_t *hw_params; + snd_pcm_sw_params_t *sw_params; + snd_pcm_uframes_t period_size = period; + snd_pcm_uframes_t buffer_size = PERIODS*period; + static snd_output_t *jcd_out; + AlsaDevice *dev = malloc(sizeof(*dev)); + if (!dev) + return NULL; + dev->device_name = malloc(1+strlen(device_name)); + if (!dev->device_name) + { + free(dev); + return NULL; + } + strcpy(dev->device_name, device_name); + dev->channels = channels; + dev->period = period; + err = snd_output_stdio_attach(&jcd_out, stdout, 0); + + if ((err = snd_pcm_open (&dev->capture_handle, dev->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { + fprintf (stderr, "cannot open audio device %s (%s)\n", + dev->device_name, + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_any (dev->capture_handle, hw_params)) < 0) { + fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_access (dev->capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf (stderr, "cannot set access type (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_format (dev->capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + fprintf (stderr, "cannot set sample format (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_rate_near (dev->capture_handle, hw_params, &rate, 0)) < 0) { + fprintf (stderr, "cannot set sample rate (%s)\n", + snd_strerror (err)); + assert(0); + } + /*fprintf (stderr, "rate = %d\n", rate);*/ + + if ((err = snd_pcm_hw_params_set_channels (dev->capture_handle, hw_params, channels)) < 0) { + fprintf (stderr, "cannot set channel count (%s)\n", + snd_strerror (err)); + assert(0); + } + + period_size = period; + dir = 0; + if ((err = snd_pcm_hw_params_set_period_size_near (dev->capture_handle, hw_params, &period_size, &dir)) < 0) { + fprintf (stderr, "cannot set period size (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_periods (dev->capture_handle, hw_params, PERIODS, 0)) < 0) { + fprintf (stderr, "cannot set number of periods (%s)\n", + snd_strerror (err)); + assert(0); + } + + buffer_size = period_size * PERIODS; + dir=0; + if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->capture_handle, hw_params, &buffer_size)) < 0) { + fprintf (stderr, "cannot set buffer time (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params (dev->capture_handle, hw_params)) < 0) { + fprintf (stderr, "cannot set capture parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + /*snd_pcm_dump_setup(dev->capture_handle, jcd_out);*/ + snd_pcm_hw_params_free (hw_params); + + if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { + fprintf (stderr, "cannot allocate software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_current (dev->capture_handle, sw_params)) < 0) { + fprintf (stderr, "cannot initialize software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_avail_min (dev->capture_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set minimum available count (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params (dev->capture_handle, sw_params)) < 0) { + fprintf (stderr, "cannot set software parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + + if ((err = snd_pcm_open (&dev->playback_handle, dev->device_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + fprintf (stderr, "cannot open audio device %s (%s)\n", + dev->device_name, + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_any (dev->playback_handle, hw_params)) < 0) { + fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_access (dev->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf (stderr, "cannot set access type (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_format (dev->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + fprintf (stderr, "cannot set sample format (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_rate_near (dev->playback_handle, hw_params, &rate, 0)) < 0) { + fprintf (stderr, "cannot set sample rate (%s)\n", + snd_strerror (err)); + assert(0); + } + /*fprintf (stderr, "rate = %d\n", rate);*/ + + if ((err = snd_pcm_hw_params_set_channels (dev->playback_handle, hw_params, channels)) < 0) { + fprintf (stderr, "cannot set channel count (%s)\n", + snd_strerror (err)); + assert(0); + } + + period_size = period; + dir = 0; + if ((err = snd_pcm_hw_params_set_period_size_near (dev->playback_handle, hw_params, &period_size, &dir)) < 0) { + fprintf (stderr, "cannot set period size (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_hw_params_set_periods (dev->playback_handle, hw_params, PERIODS, 0)) < 0) { + fprintf (stderr, "cannot set number of periods (%s)\n", + snd_strerror (err)); + assert(0); + } + buffer_size = period_size * PERIODS; + dir=0; + if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->playback_handle, hw_params, &buffer_size)) < 0) { + fprintf (stderr, "cannot set buffer time (%s)\n", + snd_strerror (err)); + assert(0); + } + + + if ((err = snd_pcm_hw_params (dev->playback_handle, hw_params)) < 0) { + fprintf (stderr, "cannot set playback parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + /*snd_pcm_dump_setup(dev->playback_handle, jcd_out);*/ + snd_pcm_hw_params_free (hw_params); + + + if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { + fprintf (stderr, "cannot allocate software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_current (dev->playback_handle, sw_params)) < 0) { + fprintf (stderr, "cannot initialize software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_avail_min (dev->playback_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set minimum available count (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_start_threshold (dev->playback_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set start mode (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params (dev->playback_handle, sw_params)) < 0) { + fprintf (stderr, "cannot set software parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + + snd_pcm_link(dev->capture_handle, dev->playback_handle); + if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + assert(0); + } + + dev->readN = snd_pcm_poll_descriptors_count(dev->capture_handle); + dev->writeN = snd_pcm_poll_descriptors_count(dev->playback_handle); + + dev->read_fd = malloc(dev->readN*sizeof(*dev->read_fd)); + /*printf ("descriptors: %d %d\n", dev->readN, dev->writeN);*/ + if (snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd, dev->readN) != dev->readN) + { + fprintf (stderr, "cannot obtain capture file descriptors (%s)\n", + snd_strerror (err)); + assert(0); + } + + dev->write_fd = malloc(dev->writeN*sizeof(*dev->read_fd)); + if (snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd, dev->writeN) != dev->writeN) + { + fprintf (stderr, "cannot obtain playback file descriptors (%s)\n", + snd_strerror (err)); + assert(0); + } + return dev; +} + +void alsa_device_close(AlsaDevice *dev) +{ + snd_pcm_close(dev->capture_handle); + snd_pcm_close(dev->playback_handle); + free(dev->device_name); + free(dev); +} + +int alsa_device_read(AlsaDevice *dev, short *pcm, int len) +{ + int err; + /*fprintf (stderr, "-");*/ + if ((err = snd_pcm_readi (dev->capture_handle, pcm, len)) != len) + { + if (err<0) + { + //fprintf(stderr, "error %d, EPIPE = %d\n", err, EPIPE); + if (err == -EPIPE) + { + fprintf (stderr, "An overrun has occured, reseting capture\n"); + } else + { + fprintf (stderr, "read from audio interface failed (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_start (dev->capture_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + /*alsa_device_read(dev,pcm,len);*/ + } else { + fprintf (stderr, "Couldn't read as many samples as I wanted (%d instead of %d)\n", err, len); + } + return 1; + } + return 0; +} + +int alsa_device_write(AlsaDevice *dev, const short *pcm, int len) +{ + int err; + /*fprintf (stderr, "+");*/ + if ((err = snd_pcm_writei (dev->playback_handle, pcm, len)) != len) + { + if (err<0) + { + if (err == -EPIPE) + { + fprintf (stderr, "An underrun has occured, reseting playback, len=%d\n", len); + } else + { + fprintf (stderr, "write to audio interface failed (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + } else { + fprintf (stderr, "Couldn't write as many samples as I wanted (%d instead of %d)\n", err, len); + } + /*alsa_device_write(dev,pcm,len);*/ + return 1; + } + return 0; +} + +int alsa_device_capture_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + unsigned short revents=0; + int err; + if ((err = snd_pcm_poll_descriptors_revents(dev->capture_handle, pfds, dev->readN, &revents)) < 0) + { + //cerr << "error in snd_pcm_poll_descriptors_revents for capture: " << snd_strerror (err) << endl; + //FIXME: This is a kludge + fprintf (stderr, "error in alsa_device_capture_ready: %s\n", snd_strerror (err)); + return pfds[0].revents & POLLIN; + } + //cerr << (revents & POLLERR) << endl; + return revents & POLLIN; +} + +int alsa_device_playback_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + unsigned short revents=0; + int err; + if ((err = snd_pcm_poll_descriptors_revents(dev->playback_handle, pfds+dev->readN, dev->writeN, &revents)) < 0) + { + //cerr << "error in snd_pcm_poll_descriptors_revents for playback: " << snd_strerror (err) << endl; + //FIXME: This is a kludge + fprintf (stderr, "error in alsa_device_playback_ready: %s\n", snd_strerror (err)); + return pfds[1].revents & POLLOUT; + } + //cerr << (revents & POLLERR) << endl; + return revents & POLLOUT; +} + +void alsa_device_start(AlsaDevice *dev) +{ + int i; + short pcm[dev->period*dev->channels]; + for (i=0;iperiod*dev->channels;i++) + pcm[i] = 0; + alsa_device_write(dev, pcm, dev->period); + alsa_device_write(dev, pcm, dev->period); + snd_pcm_start(dev->capture_handle); + snd_pcm_start(dev->playback_handle); +} + +int alsa_device_nfds(AlsaDevice *dev) +{ + return dev->writeN+dev->readN; +} + +void alsa_device_getfds(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + int i; + assert (nfds >= dev->writeN+dev->readN); + for (i=0;ireadN;i++) + pfds[i] = dev->read_fd[i]; + for (i=0;iwriteN;i++) + pfds[i+dev->readN] = dev->write_fd[i]; +} diff --git a/native/codec/libraries/celt/tools/alsa_device.h b/native/codec/libraries/celt/tools/alsa_device.h new file mode 100644 index 0000000..03e1e5d --- /dev/null +++ b/native/codec/libraries/celt/tools/alsa_device.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2004-2006 Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef ALSA_DEVICE_H +#define ALSA_DEVICE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct AlsaDevice_; + +typedef struct AlsaDevice_ AlsaDevice; + +AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period); + +void alsa_device_close(AlsaDevice *dev); + +int alsa_device_read(AlsaDevice *dev, short *pcm, int len); + +int alsa_device_write(AlsaDevice *dev, const short *pcm, int len); + +int alsa_device_capture_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +int alsa_device_playback_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +void alsa_device_start(AlsaDevice *dev); + +int alsa_device_nfds(AlsaDevice *dev); + +void alsa_device_getfds(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/celt/tools/celtclient.c b/native/codec/libraries/celt/tools/celtclient.c new file mode 100644 index 0000000..60e994f --- /dev/null +++ b/native/codec/libraries/celt/tools/celtclient.c @@ -0,0 +1,256 @@ +/*************************************************************************** + Copyright (C) 2004-2006 by Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + Copyright (C) 2008-2009 Gregory Maxwell + Copyright (c) 2007-2009 Xiph.Org Foundation + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +****************************************************************************/ + +/* Compile with something like: + * gcc -oceltclient celtclient.c alsa_device.c -I../libcelt/ -lspeexdsp -lasound -lcelt -lm + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include /* close() */ +#include /* memset() */ + +#include "alsa_device.h" +#include +#include + +#include + +#define MAX_MSG 1500 +#define SAMPLING_RATE 48000 +#define FRAME_SIZE 256 +#define PACKETSIZE 43 +#define CHANNELS 1 +#define HAS_SPEEX_AEC + +#if CHANNELS == 2 +/* FIXME: The Speex AEC has multichannel support; but that API isn't being + used here yet. */ +#undef HAS_SPEEX_AEC +#endif + +#ifdef HAS_SPEEX_AEC +#include +#endif + +int main(int argc, char *argv[]) +{ + + int sd, rc, n; + int i; + struct sockaddr_in cliAddr, remoteAddr; + char msg[MAX_MSG]; + struct hostent *h; + int local_port, remote_port; + int nfds; + struct pollfd *pfds; + AlsaDevice *audio_dev; + int tmp; + + if (argc != 5) + { + fprintf(stderr, "Usage %s plughw:0,0 remote_host local_udp_port remote_udp_port\n",argv[0]); + exit(1); + } + + h = gethostbyname(argv[2]); + if(h==NULL) { + fprintf(stderr, "%s: unknown host '%s' \n", argv[0], argv[2]); + exit(1); + } + + local_port = atoi(argv[3]); + remote_port = atoi(argv[4]); + + printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name, + inet_ntoa(*(struct in_addr *)h->h_addr_list[0])); + + { + remoteAddr.sin_family = h->h_addrtype; + memcpy((char *) &remoteAddr.sin_addr.s_addr, + h->h_addr_list[0], h->h_length); + remoteAddr.sin_port = htons(remote_port); + } + /* socket creation */ + sd=socket(AF_INET, SOCK_DGRAM, 0); + if(sd<0) { + printf("%s: cannot open socket \n",argv[0]); + exit(1); + } + + /* bind any port */ + cliAddr.sin_family = AF_INET; + cliAddr.sin_addr.s_addr = htonl(INADDR_ANY); + cliAddr.sin_port = htons(local_port); + + rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr)); + if(rc<0) { + printf("%s: cannot bind port\n", argv[0]); + exit(1); + } + + /* Setup audio device */ + audio_dev = alsa_device_open(argv[1], SAMPLING_RATE, CHANNELS, FRAME_SIZE); + + /* Setup the encoder and decoder in wideband */ + CELTEncoder *enc_state; + CELTDecoder *dec_state; + CELTMode *mode = celt_mode_create(SAMPLING_RATE, FRAME_SIZE, NULL); + enc_state = celt_encoder_create_custom(mode, CHANNELS, NULL); + dec_state = celt_decoder_create_custom(mode, CHANNELS, NULL); + struct sched_param param; + /*param.sched_priority = 40; */ + param.sched_priority = sched_get_priority_min(SCHED_FIFO); + if (sched_setscheduler(0,SCHED_FIFO,¶m)) + perror("sched_setscheduler"); + + int send_timestamp = 0; + int recv_started=0; + + /* Setup all file descriptors for poll()ing */ + nfds = alsa_device_nfds(audio_dev); + pfds = malloc(sizeof(*pfds)*(nfds+1)); + alsa_device_getfds(audio_dev, pfds, nfds); + pfds[nfds].fd = sd; + pfds[nfds].events = POLLIN; + + /* Setup jitter buffer using decoder */ + JitterBuffer *jitter; + jitter = jitter_buffer_init(FRAME_SIZE); + tmp = FRAME_SIZE; + jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MARGIN, &tmp); +#ifdef HAS_SPEEX_AEC + /* Echo canceller with 200 ms tail length */ + SpeexEchoState *echo_state = speex_echo_state_init(FRAME_SIZE, 10*FRAME_SIZE); + tmp = SAMPLING_RATE; + speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp); +#endif + alsa_device_start(audio_dev); + + /* Infinite loop on capture, playback and receiving packets */ + while (1) + { + /* Wait for either 1) capture 2) playback 3) socket data */ + poll(pfds, nfds+1, -1); + /* Received packets */ + if (pfds[nfds].revents & POLLIN) + { + n = recv(sd, msg, MAX_MSG, 0); + int recv_timestamp = ((int*)msg)[0]; + + JitterBufferPacket packet; + packet.data = msg+4; + packet.len = n-4; + packet.timestamp = recv_timestamp; + packet.span = FRAME_SIZE; + packet.sequence = 0; + /* Put content of the packet into the jitter buffer, except for the pseudo-header */ + jitter_buffer_put(jitter, &packet); + recv_started = 1; + + } + /* Ready to play a frame (playback) */ + if (alsa_device_playback_ready(audio_dev, pfds, nfds)) + { + short pcm[FRAME_SIZE*CHANNELS]; + if (recv_started) + { + JitterBufferPacket packet; + /* Get audio from the jitter buffer */ + packet.data = msg; + packet.len = MAX_MSG; + jitter_buffer_tick(jitter); + jitter_buffer_get(jitter, &packet, FRAME_SIZE, NULL); + if (packet.len==0) + packet.data=NULL; + celt_decode(dec_state, packet.data, packet.len, pcm, FRAME_SIZE); + } else { + for (i=0;i +#if !defined WIN32 && !defined _WIN32 +#include +#endif +#ifdef HAVE_GETOPT_H +#include +#endif +#ifndef HAVE_GETOPT_LONG +#include "getopt_win.h" +#endif +#include +#include + +#include +#include + +#if defined WIN32 || defined _WIN32 +#include "wave_out.h" +/* We need the following two to set stdout to binary */ +#include +#include +#endif +#include + +#ifdef __MINGW32__ +#include "wave_out.c" +#endif + +#ifdef HAVE_SYS_SOUNDCARD_H +#include +#include +#include +#include +#include + +#elif defined HAVE_SYS_AUDIOIO_H +#include +#include +#include +#include +#ifndef AUDIO_ENCODING_SLINEAR +#define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_LINEAR /* Solaris */ +#endif + +#endif + +#include +#include "wav_io.h" +#include + +#define MAX_FRAME_SIZE 2048 + +#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ + ((buf[base+2]<<16)&0xff0000)| \ + ((buf[base+1]<<8)&0xff00)| \ + (buf[base]&0xff)) + +static void print_comments(char *comments, int length) +{ + char *c=comments; + int len, i, nb_fields; + char *end; + + if (length<8) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + end = c+length; + len=readint(c, 0); + c+=4; + if (len < 0 || c+len>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + fwrite(c, 1, len, stderr); + c+=len; + fprintf (stderr, "\n"); + if (c+4>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + nb_fields=readint(c, 0); + c+=4; + for (i=0;iend) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + len=readint(c, 0); + c+=4; + if (len < 0 || c+len>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + fwrite(c, 1, len, stderr); + c+=len; + fprintf (stderr, "\n"); + } +} + +FILE *out_file_open(char *outFile, int rate, int *channels) +{ + FILE *fout=NULL; + /*Open output file*/ + if (strlen(outFile)==0) + { +#if defined HAVE_SYS_SOUNDCARD_H + int audio_fd, format, stereo; + audio_fd=open("/dev/dsp", O_WRONLY); + if (audio_fd<0) + { + perror("Cannot open /dev/dsp"); + exit(1); + } + + format=AFMT_S16_NE; + if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1) + { + perror("SNDCTL_DSP_SETFMT"); + close(audio_fd); + exit(1); + } + + stereo=0; + if (*channels==2) + stereo=1; + if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1) + { + perror("SNDCTL_DSP_STEREO"); + close(audio_fd); + exit(1); + } + if (stereo!=0) + { + if (*channels==1) + fprintf (stderr, "Cannot set mono mode, will decode in stereo\n"); + *channels=2; + } + + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1) + { + perror("SNDCTL_DSP_SPEED"); + close(audio_fd); + exit(1); + } + fout = fdopen(audio_fd, "w"); +#elif defined HAVE_SYS_AUDIOIO_H + audio_info_t info; + int audio_fd; + + audio_fd = open("/dev/audio", O_WRONLY); + if (audio_fd<0) + { + perror("Cannot open /dev/audio"); + exit(1); + } + + AUDIO_INITINFO(&info); +#ifdef AUMODE_PLAY /* NetBSD/OpenBSD */ + info.mode = AUMODE_PLAY; +#endif + info.play.encoding = AUDIO_ENCODING_SLINEAR; + info.play.precision = 16; + info.play.sample_rate = rate; + info.play.channels = *channels; + + if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) + { + perror ("AUDIO_SETINFO"); + exit(1); + } + fout = fdopen(audio_fd, "w"); +#elif defined WIN32 || defined _WIN32 + { + unsigned int celt_channels = *channels; + if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, celt_channels)) + { + fprintf (stderr, "Can't access %s\n", "WAVE OUT"); + exit(1); + } + } +#else + fprintf (stderr, "No soundcard support\n"); + exit(1); +#endif + } else { + if (strcmp(outFile,"-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdout), _O_BINARY); +#endif + fout=stdout; + } + else + { + fout = fopen(outFile, "wb"); + if (!fout) + { + perror(outFile); + exit(1); + } + if (strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0) + write_wav_header(fout, rate, *channels, 0, 0); + } + } + return fout; +} + +void usage(void) +{ + printf ("Usage: celtdec [options] input_file.oga [output_file]\n"); + printf ("\n"); + printf ("Decodes a CELT file and produce a WAV file or raw file\n"); + printf ("\n"); + printf ("input_file can be:\n"); + printf (" filename.oga regular CELT file\n"); + printf (" - stdin\n"); + printf ("\n"); + printf ("output_file can be:\n"); + printf (" filename.wav Wav file\n"); + printf (" filename.* Raw PCM file (any extension other that .wav)\n"); + printf (" - stdout\n"); + printf (" (nothing) Will be played to soundcard\n"); + printf ("\n"); + printf ("Options:\n"); + printf (" --mono Force decoding in mono\n"); + printf (" --stereo Force decoding in stereo\n"); + printf (" --rate n Force decoding at sampling rate n Hz\n"); + printf (" --packet-loss n Simulate n %% random packet loss\n"); + printf (" -V Verbose mode (show bit-rate)\n"); + printf (" -h, --help This help\n"); + printf (" -v, --version Version information\n"); + printf ("\n"); +} + +void version(void) +{ + printf ("celtenc (CELT %s encoder)\n",CELT_VERSION); + printf ("Copyright (C) 2008 Jean-Marc Valin\n"); +} + +void version_short(void) +{ + printf ("celtenc (CELT %s encoder)\n",CELT_VERSION); + printf ("Copyright (C) 2008 Jean-Marc Valin\n"); +} + +static CELTDecoder *process_header(ogg_packet *op, celt_int32 enh_enabled, celt_int32 *frame_size, int *granule_frame_size, celt_int32 *rate, int *nframes, int forceMode, int *channels, int *overlap, int *extra_headers, int quiet, CELTMode **mode) +{ + CELTDecoder *st; + CELTHeader header; + int bitstream; + + celt_header_from_packet(op->packet, op->bytes, &header); + + if (header.nb_channels>2 || header.nb_channels<1) + { + fprintf (stderr, "Unsupported number of channels: %d\n", header.nb_channels); + return NULL; + } + *mode = celt_mode_create(header.sample_rate, header.frame_size, NULL); + if (*mode == NULL) + { + fprintf (stderr, "Mode initialization failed.\n"); + return NULL; + } + + /* FIXME: Set that to zero when we freeze */ + bitstream = 0x80001000; + if (bitstream!=header.version_id) + fprintf(stderr, "WARNING: Input was encoded with a CELT bitstream version %d. This decoder uses %d. Output will probably be corrupted.\n",header.version_id,bitstream); + + *channels = header.nb_channels; + *overlap=header.overlap; + st = celt_decoder_create_custom(*mode, header.nb_channels, NULL); + if (!st) + { + fprintf (stderr, "Decoder initialization failed.\n"); + return NULL; + } + + /*celt_mode_info(*mode, CELT_GET_FRAME_SIZE, frame_size);*/ + *frame_size = header.frame_size; + *granule_frame_size = *frame_size; + + if (!*rate) + *rate = header.sample_rate; + + *nframes = 1; + + if (!quiet) + { + fprintf (stderr, "Decoding %d Hz audio in", *rate); + + if (*channels==1) + fprintf (stderr, " (mono"); + else + fprintf (stderr, " (stereo"); + fprintf(stderr, ")\n"); + } + + *extra_headers = header.extra_headers; + + return st; +} + +int main(int argc, char **argv) +{ + int c; + int option_index = 0; + char *inFile, *outFile; + FILE *fin, *fout=NULL; + short out[MAX_FRAME_SIZE]; + short output[MAX_FRAME_SIZE]; + int frame_size=0, granule_frame_size=0; + void *st=NULL; + CELTMode *mode=NULL; + int packet_count=0; + int stream_init = 0; + int quiet = 0; + ogg_int64_t page_granule=0, last_granule=0; + int skip_samples=0, page_nb_packets; + struct option long_options[] = + { + {"help", no_argument, NULL, 0}, + {"quiet", no_argument, NULL, 0}, + {"version", no_argument, NULL, 0}, + {"version-short", no_argument, NULL, 0}, + {"rate", required_argument, NULL, 0}, + {"mono", no_argument, NULL, 0}, + {"stereo", no_argument, NULL, 0}, + {"packet-loss", required_argument, NULL, 0}, + {0, 0, 0, 0} + }; + ogg_sync_state oy; + ogg_page og; + ogg_packet op; + ogg_stream_state os; + int enh_enabled; + int nframes=2; + int print_bitrate=0; + int close_in=0; + int eos=0; + int forceMode=-1; + int audio_size=0; + float loss_percent=-1; + int channels=-1; + int rate=0; + int extra_headers=0; + int wav_format=0; + int lookahead=0; + int celt_serialno = -1; + int firstpacket = 1; + + enh_enabled = 1; + + /*Process options*/ + while(1) + { + c = getopt_long (argc, argv, "hvV", + long_options, &option_index); + if (c==-1) + break; + + switch(c) + { + case 0: + if (strcmp(long_options[option_index].name,"help")==0) + { + usage(); + exit(0); + } else if (strcmp(long_options[option_index].name,"quiet")==0) + { + quiet = 1; + } else if (strcmp(long_options[option_index].name,"version")==0) + { + version(); + exit(0); + } else if (strcmp(long_options[option_index].name,"version-short")==0) + { + version_short(); + exit(0); + } else if (strcmp(long_options[option_index].name,"mono")==0) + { + channels=1; + } else if (strcmp(long_options[option_index].name,"stereo")==0) + { + channels=2; + } else if (strcmp(long_options[option_index].name,"rate")==0) + { + rate=atoi (optarg); + } else if (strcmp(long_options[option_index].name,"packet-loss")==0) + { + loss_percent = atof(optarg); + } + break; + case 'h': + usage(); + exit(0); + break; + case 'v': + version(); + exit(0); + break; + case 'V': + print_bitrate=1; + break; + case '?': + usage(); + exit(1); + break; + } + } + if (argc-optind!=2 && argc-optind!=1) + { + usage(); + exit(1); + } + inFile=argv[optind]; + + if (argc-optind==2) + outFile=argv[optind+1]; + else + outFile = ""; + wav_format = strlen(outFile)>=4 && ( + strcmp(outFile+strlen(outFile)-4,".wav")==0 + || strcmp(outFile+strlen(outFile)-4,".WAV")==0); + /*Open input file*/ + if (strcmp(inFile, "-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdin), _O_BINARY); +#endif + fin=stdin; + } + else + { + fin = fopen(inFile, "rb"); + if (!fin) + { + perror(inFile); + exit(1); + } + close_in=1; + } + + + /*Init Ogg data struct*/ + ogg_sync_init(&oy); + + /*Main decoding loop*/ + + while (1) + { + char *data; + int i, nb_read; + /*Get the ogg buffer for writing*/ + data = ogg_sync_buffer(&oy, 200); + /*Read bitstream from input file*/ + nb_read = fread(data, sizeof(char), 200, fin); + ogg_sync_wrote(&oy, nb_read); + + /*Loop for all complete pages we got (most likely only one)*/ + while (ogg_sync_pageout(&oy, &og)==1) + { + if (stream_init == 0) { + ogg_stream_init(&os, ogg_page_serialno(&og)); + stream_init = 1; + } + if (ogg_page_serialno(&og) != os.serialno) { + /* so all streams are read. */ + ogg_stream_reset_serialno(&os, ogg_page_serialno(&og)); + } + /*Add page to the bitstream*/ + ogg_stream_pagein(&os, &og); + page_granule = ogg_page_granulepos(&og); + page_nb_packets = ogg_page_packets(&og); + if (page_granule>0 && frame_size) + { + /* FIXME: shift the granule values if --force-* is specified */ + skip_samples = frame_size*(page_nb_packets*granule_frame_size*nframes - (page_granule-last_granule))/granule_frame_size; + if (ogg_page_eos(&og)) + skip_samples = -skip_samples; + /*else if (!ogg_page_bos(&og)) + skip_samples = 0;*/ + } else + { + skip_samples = 0; + } + /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/ + last_granule = page_granule; + /*Extract all available packets*/ + while (!eos && ogg_stream_packetout(&os, &op) == 1) + { + if (op.bytes>=8 && !memcmp(op.packet, "CELT ", 8)) { + celt_serialno = os.serialno; + } + if (celt_serialno == -1 || os.serialno != celt_serialno) + break; + /*If first packet, process as CELT header*/ + if (packet_count==0) + { + st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &lookahead, &extra_headers, quiet, &mode); + if (!st) + exit(1); + if (!nframes) + nframes=1; + fout = out_file_open(outFile, rate, &channels); + + } else if (packet_count==1) + { + if (!quiet) + print_comments((char*)op.packet, op.bytes); + } else if (packet_count<=1+extra_headers) + { + /* Ignore extra headers */ + } else { + int lost=0; + if (loss_percent>0 && 100*((float)rand())/RAND_MAX0) + { +#if defined WIN32 || defined _WIN32 + if (strlen(outFile)==0) + WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels); + else +#endif + fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout); + + audio_size+=sizeof(short)*new_frame_size*channels; + } + } + } + } + packet_count++; + } + } + if (feof(fin)) + break; + + } + + if (fout && wav_format) + { + if (fseek(fout,4,SEEK_SET)==0) + { + int tmp; + tmp = le_int(audio_size+36); + fwrite(&tmp,4,1,fout); + if (fseek(fout,32,SEEK_CUR)==0) + { + tmp = le_int(audio_size); + fwrite(&tmp,4,1,fout); + } else + { + fprintf (stderr, "First seek worked, second didn't\n"); + } + } else { + fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n"); + } + } + + if (st) + { + celt_decoder_destroy(st); + celt_mode_destroy(mode); + } else { + fprintf (stderr, "This doesn't look like a CELT file\n"); + } + if (stream_init) + ogg_stream_clear(&os); + ogg_sync_clear(&oy); + +#if defined WIN32 || defined _WIN32 + if (strlen(outFile)==0) + WIN_Audio_close (); +#endif + + if (close_in) + fclose(fin); + if (fout != NULL) + fclose(fout); + + return 0; +} diff --git a/native/codec/libraries/celt/tools/celtenc.c b/native/codec/libraries/celt/tools/celtenc.c new file mode 100644 index 0000000..685c62c --- /dev/null +++ b/native/codec/libraries/celt/tools/celtenc.c @@ -0,0 +1,818 @@ +/* Copyright (c) 2002-2010 Jean-Marc Valin + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008-2010 Gregory Maxwell + File: celtenc.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#if !defined WIN32 && !defined _WIN32 +#include +#endif + +#ifdef HAVE_GETOPT_H +#include +#endif + +#ifndef HAVE_GETOPT_LONG +#include "getopt_win.h" +#endif + +#include +#include +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +#include "celt.h" +#include "celt_header.h" +#include +#include "wav_io.h" + +#if defined WIN32 || defined _WIN32 +/* We need the following two to set stdout to binary */ +#include +#include +#endif + +#include "skeleton.h" + + +void comment_init(char **comments, int* length, char *vendor_string); +void comment_add(char **comments, int* length, char *tag, char *val); + + +/*Write an Ogg page to a file pointer*/ +int oe_write_page(ogg_page *page, FILE *fp) +{ + int written; + written = fwrite(page->header,1,page->header_len, fp); + written += fwrite(page->body,1,page->body_len, fp); + + return written; +} + +#define MAX_FRAME_SIZE 2048 +#define MAX_FRAME_BYTES 1275 +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ + +/* Convert input audio bits, endians and channels */ +static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, celt_int32 *size) +{ + short s[MAX_FRAME_SIZE]; + unsigned char *in = (unsigned char*)s; + int i; + int nb_read; + + if (size && *size<=0) + { + return 0; + } + /*Read input audio*/ + if (size) + *size -= bits/8*channels*frame_size; + if (buff) + { + for (i=0;i<12;i++) + in[i]=buff[i]; + nb_read = fread(in+12,1,bits/8*channels*frame_size-12, fin) + 12; + if (size) + *size += 12; + } else { + nb_read = fread(in,1,bits/8*channels* frame_size, fin); + } + nb_read /= bits/8*channels; + + /*fprintf (stderr, "%d\n", nb_read);*/ + if (nb_read==0) + return 0; + + if(bits==8) + { + /* Convert 8->16 bits */ + for(i=frame_size*channels-1;i>=0;i--) + { + s[i]=(in[i]<<8)^0x8000; + } + } else + { + /* convert to our endian format */ + for(i=0;iextra_headers; + fp.granule_rate_n = header->sample_rate; + fp.granule_rate_d = 1; + fp.start_granule = 0; + fp.preroll = 3; + fp.granule_shift = 0; + + add_message_header_field(&fp, "Content-Type", "audio/x-celt"); + + add_fisbone_to_stream(os, &fp); +} + +void version(void) +{ + printf ("celtenc (CELT %s encoder)\n",CELT_VERSION); + printf ("Copyright (C) 2008-2010 Xiph.Org Foundation (written by Jean-Marc Valin)\n"); +} + +void version_short(void) +{ + printf ("celtenc (CELT %s encoder)\n",CELT_VERSION); + printf ("Copyright (C) 2008-2010 Xiph.Org Foundation (written by Jean-Marc Valin)\n"); +} + +void usage(void) +{ + printf ("Usage: celtenc [options] input_file output_file.oga\n"); + printf ("\n"); + printf ("Encodes input_file using CELT. It can read the WAV or raw files.\n"); + printf ("\n"); + printf ("input_file can be:\n"); + printf (" filename.wav wav file\n"); + printf (" filename.* Raw PCM file (any extension other than .wav)\n"); + printf (" - stdin\n"); + printf ("\n"); + printf ("output_file can be:\n"); + printf (" filename.oga compressed file\n"); + printf (" - stdout\n"); + printf ("\n"); + printf ("Options:\n"); + printf (" --bitrate n Encoding bit-rate in kbit/sec\n"); + printf (" --cbr Use constant bitrate encoding\n"); + printf (" --comp n Encoding complexity (0-10)\n"); + printf (" --framesize n Frame size (Default: 960)\n"); + printf (" --nopf Do not use the prefilter/postfilter\n"); + printf (" --independent Encode frames independently (implies nopf)\n"); + printf (" --skeleton Outputs ogg skeleton metadata (may cause incompatibilities)\n"); + printf (" --comment Add the given string as an extra comment. This may be\n"); + printf (" used multiple times\n"); + printf (" --author Author of this track\n"); + printf (" --title Title for this track\n"); + printf (" -h, --help This help\n"); + printf (" -v, --version Version information\n"); + printf (" -V Verbose mode (show bit-rate)\n"); + printf ("Raw input options:\n"); + printf (" --rate n Sampling rate for raw input\n"); + printf (" --mono Consider raw input as mono\n"); + printf (" --stereo Consider raw input as stereo\n"); + printf (" --le Raw input is little-endian\n"); + printf (" --be Raw input is big-endian\n"); + printf (" --8bit Raw input is 8-bit unsigned\n"); + printf (" --16bit Raw input is 16-bit signed\n"); + printf ("Default raw PCM input is 48kHz, 16-bit, little-endian, stereo\n"); +} + + +int main(int argc, char **argv) +{ + int nb_samples, total_samples=0, nb_encoded; + int c; + int option_index = 0; + char *inFile, *outFile; + FILE *fin, *fout; + short input[MAX_FRAME_SIZE]; + celt_int32 frame_size = 960; + int quiet=0; + int nbBytes; + CELTMode *mode; + void *st; + unsigned char bits[MAX_FRAME_BYTES]; + int with_cbr = 0; + int with_cvbr = 0; + int with_skeleton = 0; + int total_bytes = 0; + int peak_bytes = 0; + struct option long_options[] = + { + {"bitrate", required_argument, NULL, 0}, + {"cbr",no_argument,NULL, 0}, + {"cvbr",no_argument,NULL, 0}, + {"comp", required_argument, NULL, 0}, + {"nopf", no_argument, NULL, 0}, + {"independent", no_argument, NULL, 0}, + {"framesize", required_argument, NULL, 0}, + {"skeleton",no_argument,NULL, 0}, + {"help", no_argument, NULL, 0}, + {"quiet", no_argument, NULL, 0}, + {"le", no_argument, NULL, 0}, + {"be", no_argument, NULL, 0}, + {"8bit", no_argument, NULL, 0}, + {"16bit", no_argument, NULL, 0}, + {"mono", no_argument, NULL, 0}, + {"stereo", no_argument, NULL, 0}, + {"rate", required_argument, NULL, 0}, + {"version", no_argument, NULL, 0}, + {"version-short", no_argument, NULL, 0}, + {"comment", required_argument, NULL, 0}, + {"author", required_argument, NULL, 0}, + {"title", required_argument, NULL, 0}, + {0, 0, 0, 0} + }; + int print_bitrate=0; + celt_int32 rate=48000; + celt_int32 size; + int chan=1; + int fmt=16; + int lsb=1; + ogg_stream_state os; + ogg_stream_state so; /* ogg stream for skeleton bitstream */ + ogg_page og; + ogg_packet op; + int bytes_written=0, ret, result; + int id=-1; + CELTHeader header; + char vendor_string[64]; + char *comments; + int comments_length; + int close_in=0, close_out=0; + int eos=0; + float bitrate=-1; + char first_bytes[12]; + int wave_input=0; + celt_int32 lookahead = 0; + int bytes_per_packet=-1; + int complexity=-127; + int prediction=2; + + + /*Process command-line options*/ + while(1) + { + c = getopt_long (argc, argv, "hvV", + long_options, &option_index); + if (c==-1) + break; + + switch(c) + { + case 0: + if (strcmp(long_options[option_index].name,"bitrate")==0) + { + bitrate = atof (optarg); + } else if (strcmp(long_options[option_index].name,"cbr")==0) + { + with_cbr=1; + } else if (strcmp(long_options[option_index].name,"cvbr")==0) + { + with_cvbr=1; + } else if (strcmp(long_options[option_index].name,"skeleton")==0) + { + with_skeleton=1; + } else if (strcmp(long_options[option_index].name,"help")==0) + { + usage(); + exit(0); + } else if (strcmp(long_options[option_index].name,"quiet")==0) + { + quiet = 1; + } else if (strcmp(long_options[option_index].name,"version")==0) + { + version(); + exit(0); + } else if (strcmp(long_options[option_index].name,"version-short")==0) + { + version_short(); + exit(0); + } else if (strcmp(long_options[option_index].name,"le")==0) + { + lsb=1; + } else if (strcmp(long_options[option_index].name,"be")==0) + { + lsb=0; + } else if (strcmp(long_options[option_index].name,"8bit")==0) + { + fmt=8; + } else if (strcmp(long_options[option_index].name,"16bit")==0) + { + fmt=16; + } else if (strcmp(long_options[option_index].name,"stereo")==0) + { + chan=2; + } else if (strcmp(long_options[option_index].name,"mono")==0) + { + chan=1; + } else if (strcmp(long_options[option_index].name,"rate")==0) + { + rate=atoi (optarg); + } else if (strcmp(long_options[option_index].name,"comp")==0) + { + complexity=atoi (optarg); + } else if (strcmp(long_options[option_index].name,"framesize")==0) + { + frame_size=atoi (optarg); + } else if (strcmp(long_options[option_index].name,"nopf")==0) + { + if (prediction>1) + prediction=1; + } else if (strcmp(long_options[option_index].name,"independent")==0) + { + prediction=0; + } else if (strcmp(long_options[option_index].name,"comment")==0) + { + if (!strchr(optarg, '=')) + { + fprintf (stderr, "Invalid comment: %s\n", optarg); + fprintf (stderr, "Comments must be of the form name=value\n"); + exit(1); + } + comment_add(&comments, &comments_length, NULL, optarg); + } else if (strcmp(long_options[option_index].name,"author")==0) + { + comment_add(&comments, &comments_length, "author=", optarg); + } else if (strcmp(long_options[option_index].name,"title")==0) + { + comment_add(&comments, &comments_length, "title=", optarg); + } + + break; + case 'h': + usage(); + exit(0); + break; + case 'v': + version(); + exit(0); + break; + case 'V': + print_bitrate=1; + break; + case '?': + usage(); + exit(1); + break; + } + } + if (argc-optind!=2) + { + usage(); + exit(1); + } + inFile=argv[optind]; + outFile=argv[optind+1]; + + /*Initialize Ogg stream struct*/ + srand(time(NULL)); + if (ogg_stream_init(&os, rand())==-1) + { + fprintf(stderr,"Error: stream init failed\n"); + exit(1); + } + if (with_skeleton && ogg_stream_init(&so, rand())==-1) + { + fprintf(stderr,"Error: stream init failed\n"); + exit(1); + } + + if (strcmp(inFile, "-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdin), _O_BINARY); +#elif defined OS2 + _fsetmode(stdin,"b"); +#endif + fin=stdin; + } + else + { + fin = fopen(inFile, "rb"); + if (!fin) + { + perror(inFile); + exit(1); + } + close_in=1; + } + + { + fread(first_bytes, 1, 12, fin); + if (strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0) + { + if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1) + exit(1); + wave_input=1; + lsb=1; /* CHECK: exists big-endian .wav ?? */ + } + } + + if (bitrate<=0.005) + if (chan==1) + bitrate=64.0; + else + bitrate=128.0; + + bytes_per_packet = MAX_FRAME_BYTES; + + mode = celt_mode_create(rate, frame_size, NULL); + if (!mode) + return 1; + + snprintf(vendor_string, sizeof(vendor_string), "Encoded with CELT %s\n",CELT_VERSION); + comment_init(&comments, &comments_length, vendor_string); + + /*celt_mode_info(mode, CELT_GET_FRAME_SIZE, &frame_size);*/ + + celt_header_init(&header, mode, frame_size, chan); + header.nb_channels = chan; + + { + char *st_string="mono"; + if (chan==2) + st_string="stereo"; + if (!quiet) + if (with_cbr) + fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet, CBR)\n", + header.sample_rate/1000., st_string, frame_size/(float)header.sample_rate*1000., bitrate, bytes_per_packet); + else + fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet maximum)\n", + header.sample_rate/1000., st_string, frame_size/(float)header.sample_rate*1000., bitrate, bytes_per_packet); + } + + /*Initialize CELT encoder*/ + st = celt_encoder_create_custom(mode, chan, NULL); + + { + int tmp = (bitrate*1000); + if (celt_encoder_ctl(st, CELT_SET_BITRATE(tmp)) != CELT_OK) + { + fprintf (stderr, "bitrate request failed\n"); + return 1; + } + } + if (!with_cbr) + { + if (celt_encoder_ctl(st, CELT_SET_VBR(1)) != CELT_OK) + { + fprintf (stderr, "VBR request failed\n"); + return 1; + } + if (!with_cvbr) + { + if (celt_encoder_ctl(st, CELT_SET_VBR_CONSTRAINT(0)) != CELT_OK) + { + fprintf (stderr, "VBR constraint failed\n"); + return 1; + } + } + } + + if (celt_encoder_ctl(st, CELT_SET_PREDICTION(prediction)) != CELT_OK) + { + fprintf (stderr, "Prediction request failed\n"); + return 1; + } + + if (complexity!=-127) { + if (celt_encoder_ctl(st, CELT_SET_COMPLEXITY(complexity)) != CELT_OK) + { + fprintf (stderr, "Only complexity 0 through 10 is supported\n"); + return 1; + } + } + + if (strcmp(outFile,"-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdout), _O_BINARY); +#endif + fout=stdout; + } + else + { + fout = fopen(outFile, "wb"); + if (!fout) + { + perror(outFile); + exit(1); + } + close_out=1; + } + + if (with_skeleton) { + fprintf (stderr, "Warning: Enabling skeleton output may cause some decoders to fail.\n"); + } + + /* first packet should be the skeleton header. */ + if (with_skeleton) { + add_fishead_packet(&so); + if ((ret = flush_ogg_stream_to_file(&so, fout))) { + fprintf (stderr,"Error: failed skeleton (fishead) header to output stream\n"); + exit(1); + } else + bytes_written += ret; + } + + /*Write header*/ + { + unsigned char header_data[100]; + int packet_size = celt_header_to_packet(&header, header_data, 100); + op.packet = header_data; + op.bytes = packet_size; + op.b_o_s = 1; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = 0; + ogg_stream_packetin(&os, &op); + + while((result = ogg_stream_flush(&os, &og))) + { + if(!result) break; + ret = oe_write_page(&og, fout); + if(ret != og.header_len + og.body_len) + { + fprintf (stderr,"Error: failed writing header to output stream\n"); + exit(1); + } + else + bytes_written += ret; + } + + op.packet = (unsigned char *)comments; + op.bytes = comments_length; + op.b_o_s = 0; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = 1; + ogg_stream_packetin(&os, &op); + } + + /* fisbone packet should be write after all bos pages */ + if (with_skeleton) { + add_fisbone_packet(&so, os.serialno, &header); + if ((ret = flush_ogg_stream_to_file(&so, fout))) { + fprintf (stderr,"Error: failed writing skeleton (fisbone )header to output stream\n"); + exit(1); + } else + bytes_written += ret; + } + + /* writing the rest of the celt header packets */ + while((result = ogg_stream_flush(&os, &og))) + { + if(!result) break; + ret = oe_write_page(&og, fout); + if(ret != og.header_len + og.body_len) + { + fprintf (stderr,"Error: failed writing header to output stream\n"); + exit(1); + } + else + bytes_written += ret; + } + + free(comments); + + /* write the skeleton eos packet */ + if (with_skeleton) { + add_eos_packet_to_stream(&so); + if ((ret = flush_ogg_stream_to_file(&so, fout))) { + fprintf (stderr,"Error: failed writing skeleton header to output stream\n"); + exit(1); + } else + bytes_written += ret; + } + + + if (!wave_input) + { + nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL); + } else { + nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size); + } + if (nb_samples==0) + eos=1; + total_samples += nb_samples; + nb_encoded = -lookahead; + /*Main encoding loop (one frame per iteration)*/ + while (!eos || total_samples>nb_encoded) + { + id++; + /*Encode current frame*/ + + nbBytes = celt_encode(st, input, frame_size, bits, bytes_per_packet); + if (nbBytes<0) + { + fprintf(stderr, "Got error %d while encoding. Aborting.\n", nbBytes); + break; + } + nb_encoded += frame_size; + total_bytes += nbBytes; + peak_bytes=IMAX(nbBytes,peak_bytes); + + if (wave_input) + { + nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size); + } else { + nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL); + } + if (nb_samples==0) + { + eos=1; + } + if (eos && total_samples<=nb_encoded) + op.e_o_s = 1; + else + op.e_o_s = 0; + total_samples += nb_samples; + + op.packet = (unsigned char *)bits; + op.bytes = nbBytes; + op.b_o_s = 0; + /*Is this redundent?*/ + if (eos && total_samples<=nb_encoded) + op.e_o_s = 1; + else + op.e_o_s = 0; + op.granulepos = (id+1)*frame_size-lookahead; + if (op.granulepos>total_samples) + op.granulepos = total_samples; + /*printf ("granulepos: %d %d %d %d %d %d\n", (int)op.granulepos, id, nframes, lookahead, 5, 6);*/ + op.packetno = 2+id; + ogg_stream_packetin(&os, &op); + + /*Write all new pages (most likely 0 or 1)*/ + while (ogg_stream_pageout(&os,&og)) + { + ret = oe_write_page(&og, fout); + if(ret != og.header_len + og.body_len) + { + fprintf (stderr,"Error: failed writing header to output stream\n"); + exit(1); + } + else + bytes_written += ret; + } + } + /*Flush all pages left to be written*/ + while (ogg_stream_flush(&os, &og)) + { + ret = oe_write_page(&og, fout); + if(ret != og.header_len + og.body_len) + { + fprintf (stderr,"Error: failed writing header to output stream\n"); + exit(1); + } + else + bytes_written += ret; + } + + if (!with_cbr && !quiet) + fprintf (stderr, "Average rate %0.3fkbit/sec, %d peak bytes per packet\n", (total_bytes*8.0/((float)nb_encoded/header.sample_rate))/1000.0, peak_bytes); + + celt_encoder_destroy(st); + celt_mode_destroy(mode); + ogg_stream_clear(&os); + + if (close_in) + fclose(fin); + if (close_out) + fclose(fout); + return 0; +} + +/* + Comments will be stored in the Vorbis style. + It is describled in the "Structure" section of + http://www.xiph.org/ogg/vorbis/doc/v-comment.html + +The comment header is decoded as follows: + 1) [vendor_length] = read an unsigned integer of 32 bits + 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets + 3) [user_comment_list_length] = read an unsigned integer of 32 bits + 4) iterate [user_comment_list_length] times { + 5) [length] = read an unsigned integer of 32 bits + 6) this iteration's user comment = read a UTF-8 vector as [length] octets + } + 7) [framing_bit] = read a single bit as boolean + 8) if ( [framing_bit] unset or end of packet ) then ERROR + 9) done. + + If you have troubles, please write to ymnk@jcraft.com. + */ + +#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ + ((buf[base+2]<<16)&0xff0000)| \ + ((buf[base+1]<<8)&0xff00)| \ + (buf[base]&0xff)) +#define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \ + buf[base+2]=((val)>>16)&0xff; \ + buf[base+1]=((val)>>8)&0xff; \ + buf[base]=(val)&0xff; \ + }while(0) + +void comment_init(char **comments, int* length, char *vendor_string) +{ + int vendor_length=strlen(vendor_string); + int user_comment_list_length=0; + int len=4+vendor_length+4; + char *p=(char*)malloc(len); + if(p==NULL){ + fprintf (stderr, "malloc failed in comment_init()\n"); + exit(1); + } + writeint(p, 0, vendor_length); + memcpy(p+4, vendor_string, vendor_length); + writeint(p, 4+vendor_length, user_comment_list_length); + *length=len; + *comments=p; +} +void comment_add(char **comments, int* length, char *tag, char *val) +{ + char* p=*comments; + int vendor_length=readint(p, 0); + int user_comment_list_length=readint(p, 4+vendor_length); + int tag_len=(tag?strlen(tag):0); + int val_len=strlen(val); + int len=(*length)+4+tag_len+val_len; + + p=(char*)realloc(p, len); + if(p==NULL){ + fprintf (stderr, "realloc failed in comment_add()\n"); + exit(1); + } + + writeint(p, *length, tag_len+val_len); /* length of comment */ + if(tag) memcpy(p+*length+4, tag, tag_len); /* comment */ + memcpy(p+*length+4+tag_len, val, val_len); /* comment */ + writeint(p, 4+vendor_length, user_comment_list_length+1); + + *comments=p; + *length=len; +} +#undef readint +#undef writeint diff --git a/native/codec/libraries/celt/tools/getopt.c b/native/codec/libraries/celt/tools/getopt.c new file mode 100644 index 0000000..dad25b6 --- /dev/null +++ b/native/codec/libraries/celt/tools/getopt.c @@ -0,0 +1,1047 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 + Free Software Foundation, Inc. + + The GNU C 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. + + The GNU C 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 the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt_win.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +#include + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/native/codec/libraries/celt/tools/getopt1.c b/native/codec/libraries/celt/tools/getopt1.c new file mode 100644 index 0000000..dee6325 --- /dev/null +++ b/native/codec/libraries/celt/tools/getopt1.c @@ -0,0 +1,188 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C 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. + + The GNU C 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 the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt_win.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/native/codec/libraries/celt/tools/getopt_win.h b/native/codec/libraries/celt/tools/getopt_win.h new file mode 100644 index 0000000..b0147e9 --- /dev/null +++ b/native/codec/libraries/celt/tools/getopt_win.h @@ -0,0 +1,169 @@ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C 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. + + The GNU C 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 the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +# if defined __STDC__ && __STDC__ + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#if defined __STDC__ && __STDC__ +# ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int __argc, char *const *__argv, const char *__shortopts); +# else /* not __GNU_LIBRARY__ */ +extern int getopt (); +# endif /* __GNU_LIBRARY__ */ + +# ifndef __need_getopt +extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); +# endif +#else /* not __STDC__ */ +extern int getopt (); +# ifndef __need_getopt +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +# endif +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/native/codec/libraries/celt/tools/opus_compare.m b/native/codec/libraries/celt/tools/opus_compare.m new file mode 100644 index 0000000..fc0f383 --- /dev/null +++ b/native/codec/libraries/celt/tools/opus_compare.m @@ -0,0 +1,79 @@ +%% Tests bit-stream compliance for the Opus codec +%% x: Signal from the Opus reference implementation (float or fixed) +%% y: Signal from the decoder under test +%% stereo: 0 for mono, 1 for stereo +function [err, NMR] = opus_compare(x, y, stereo) + +% Bands on which we compute the pseudo-NMR (Bark-derived CELT bands) +b = 2*[0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100]; +d = diff(b); + +% Per-band SNR threshold +T = 50-.7*[1:21]; + +% Noise floor +N = 10 .^ ((10-0.6*[1:21])/10); + +% Error signal +e=x-y; + +%Add a +/- 1 dead zone on the error +e = e - min(1, max(-1, e)); + +% Compute spectrum of original and error +if (stereo) + X=(abs(specgram(x(1:2:end),480))+abs(specgram(x(2:2:end),480)))/2; + E=(abs(specgram(e(1:2:end),480))+abs(specgram(e(2:2:end),480)))/2; +else + X=abs(specgram(x,480)); + E=abs(specgram(e,480)); +endif + +% Group energy per band +for k=1:21 + Xb(k,:) = sum(X(b(k)+1:b(k+1),:).^2)/d(k)+1; + Eb(k,:) = sum(E(b(k)+1:b(k+1),:).^2)/d(k)+1; +end + +% Frequency masking (low to high) with 10 dB/Bark slope +Xb = filter(1, [1, -.1], Xb); +% Frequency masking (high to low) with 15 dB/Bark slope +Xb(end:-1:1,:) = filter(1, [1, -.03], Xb(end:-1:1,:)); + +% Temporal masking with 5 dB/5 ms slope +Xb = filter(1, [1, -.3], Xb')'; + +% NMR threshold +T0 = ones(length(Eb), 1)*(10.^((T)/10)); + +% Time-frequency SNR +NMR = (Xb./Eb)'; + +%Picking only errors in the 90th percentile +tmp = Eb(:); +thresh = sort(tmp)(round(.90*length(tmp))); +weight = Eb'>thresh; + +printf("Average pseudo-NMR: %3.2f dB\n", mean(mean(10*log10(NMR)))); + +if (sum(sum(weight))<1) + printf("Mismatch level: below noise floor\n"); + err = -100; +else + M = (T0./NMR) .* weight; + + err = 10*log10(sum(sum(M)) / sum(sum(weight))); + + printf("Weighted mismatch: %3.2f dB\n", err); +endif + +printf("\n"); + +if (err < 0) + printf("**Decoder PASSES test (mismatch < 0 dB)\n"); +else + printf("**Decoder FAILS test (mismatch >= 0 dB)\n"); +endif + + + diff --git a/native/codec/libraries/celt/tools/skeleton.c b/native/codec/libraries/celt/tools/skeleton.c new file mode 100644 index 0000000..c5e6b5b --- /dev/null +++ b/native/codec/libraries/celt/tools/skeleton.c @@ -0,0 +1,218 @@ +/* + * skeleton.c + * author: Tahseen Mohammad + */ + +/* This file depends on WORDS_BIGENDIAN being defined to 1 if the host + * processor stores words with the most significant byte first (like Motorola + * and SPARC, unlike Intel and VAX). + * On little endian systems, WORDS_BIGENDIAN should be undefined. + * + * When using GNU Autotools, the correct value will be written into config.h + * if the autoconf macro AC_C_BIGENDIAN is called in configure.ac. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include + +#include "skeleton.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +static unsigned short +_le_16 (unsigned short s) +{ + unsigned short ret=s; +#ifdef WORDS_BIGENDIAN + ret = (s>>8) & 0x00ffU; + ret += (s<<8) & 0xff00U; +#endif + return ret; +} + +static ogg_uint32_t +_le_32 (ogg_uint32_t i) +{ + ogg_uint32_t ret=i; +#ifdef WORDS_BIGENDIAN + ret = (i>>24); + ret += (i>>8) & 0x0000ff00; + ret += (i<<8) & 0x00ff0000; + ret += (i<<24); +#endif + return ret; +} + +static ogg_int64_t +_le_64 (ogg_int64_t l) +{ + ogg_int64_t ret=l; + unsigned char *ucptr = (unsigned char *)&ret; +#ifdef WORDS_BIGENDIAN + unsigned char temp; + + temp = ucptr [0] ; + ucptr [0] = ucptr [7] ; + ucptr [7] = temp ; + + temp = ucptr [1] ; + ucptr [1] = ucptr [6] ; + ucptr [6] = temp ; + + temp = ucptr [2] ; + ucptr [2] = ucptr [5] ; + ucptr [5] = temp ; + + temp = ucptr [3] ; + ucptr [3] = ucptr [4] ; + ucptr [4] = temp ; + +#endif + return (*(ogg_int64_t *)ucptr); +} + +/* write an ogg_page to a file pointer */ +int write_ogg_page_to_file(ogg_page *og, FILE *out) { + int written; + + written = fwrite(og->header,1, og->header_len, out); + written += fwrite(og->body,1, og->body_len, out); + + return written; +} + +int add_message_header_field(fisbone_packet *fp, + char *header_key, + char *header_value) { + + /* size of both key and value + ': ' + CRLF */ + int this_message_size = strlen(header_key) + strlen(header_value) + 4; + if (fp->message_header_fields == NULL) { + fp->message_header_fields = _ogg_calloc(this_message_size+1, sizeof(char)); + } else { + int new_size = (fp->current_header_size + this_message_size+1) * sizeof(char); + fp->message_header_fields = _ogg_realloc(fp->message_header_fields, new_size); + } + snprintf(fp->message_header_fields + fp->current_header_size, + this_message_size+1, + "%s: %s\r\n", + header_key, + header_value); + fp->current_header_size += this_message_size; + + return 0; +} + +/* create a ogg_packet from a fishead_packet structure */ +ogg_packet ogg_from_fishead(fishead_packet *fp) { + + ogg_packet op; + + memset(&op, 0, sizeof(op)); + op.packet = _ogg_calloc(FISHEAD_SIZE, sizeof(unsigned char)); + memset(op.packet, 0, FISHEAD_SIZE); + + memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */ + *((ogg_uint16_t*)(op.packet+8)) = _le_16 (SKELETON_VERSION_MAJOR); /* version major */ + *((ogg_uint16_t*)(op.packet+10)) = _le_16 (SKELETON_VERSION_MINOR); /* version minor */ + *((ogg_int64_t*)(op.packet+12)) = _le_64 (fp->ptime_n); /* presentationtime numerator */ + *((ogg_int64_t*)(op.packet+20)) = _le_64 (fp->ptime_d); /* presentationtime denominator */ + *((ogg_int64_t*)(op.packet+28)) = _le_64 (fp->btime_n); /* basetime numerator */ + *((ogg_int64_t*)(op.packet+36)) = _le_64 (fp->btime_d); /* basetime denominator */ + /* TODO: UTC time, set to zero for now */ + + op.b_o_s = 1; /* its the first packet of the stream */ + op.e_o_s = 0; /* its not the last packet of the stream */ + op.bytes = FISHEAD_SIZE; /* length of the packet in bytes */ + + return op; +} + +/* create a ogg_packet from a fisbone_packet structure. + * call this method after the fisbone_packet is filled and all message header fields are added + * by calling add_message_header_field method. + */ +ogg_packet ogg_from_fisbone(fisbone_packet *fp) { + + ogg_packet op; + int packet_size = FISBONE_SIZE + fp->current_header_size; + + memset (&op, 0, sizeof (op)); + op.packet = _ogg_calloc (packet_size, sizeof(unsigned char)); + memset (op.packet, 0, packet_size); + memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */ + *((ogg_uint32_t*)(op.packet+8)) = _le_32 (FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */ + *((ogg_uint32_t*)(op.packet+12)) = _le_32 (fp->serial_no); /* serialno of the respective stream */ + *((ogg_uint32_t*)(op.packet+16)) = _le_32 (fp->nr_header_packet); /* number of header packets */ + *((ogg_int64_t*)(op.packet+20)) = _le_64 (fp->granule_rate_n); /* granulrate numerator */ + *((ogg_int64_t*)(op.packet+28)) = _le_64 (fp->granule_rate_d); /* granulrate denominator */ + *((ogg_int64_t*)(op.packet+36)) = _le_64 (fp->start_granule); /* start granule */ + *((ogg_uint32_t*)(op.packet+44)) = _le_32 (fp->preroll); /* preroll, for theora its 0 */ + *(op.packet+48) = fp->granule_shift; /* granule shift */ + memcpy((op.packet+FISBONE_SIZE), fp->message_header_fields, fp->current_header_size); + + op.b_o_s = 0; + op.e_o_s = 0; + op.bytes = packet_size; /* size of the packet in bytes */ + + return op; +} + + + +int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) { + + ogg_packet op; + + op = ogg_from_fishead(fp); + ogg_stream_packetin(os, &op); + _ogg_free(op.packet); + + return 0; +} + +int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) { + + ogg_packet op; + + op = ogg_from_fisbone(fp); + ogg_stream_packetin(os, &op); + _ogg_free(op.packet); + + return 0; +} + +int add_eos_packet_to_stream(ogg_stream_state *os) { + + ogg_packet op; + + memset (&op, 0, sizeof(op)); + op.e_o_s = 1; + ogg_stream_packetin(os, &op); + + return 0; +} + +int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) { + + ogg_page og; + int result; + + while((result = ogg_stream_flush(os, &og))) + { + if(!result) break; + result = write_ogg_page_to_file(&og, out); + if(result != og.header_len + og.body_len) + return 1; + } + + return 0; +} diff --git a/native/codec/libraries/celt/tools/skeleton.h b/native/codec/libraries/celt/tools/skeleton.h new file mode 100644 index 0000000..f07d7a3 --- /dev/null +++ b/native/codec/libraries/celt/tools/skeleton.h @@ -0,0 +1,78 @@ +/* + * skeleton.h + * author: Tahseen Mohammad + */ + +#ifndef _SKELETON_H +#define _SKELETON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +#include + +#define SKELETON_VERSION_MAJOR 3 +#define SKELETON_VERSION_MINOR 0 +#define FISHEAD_IDENTIFIER "fishead\0" +#define FISBONE_IDENTIFIER "fisbone\0" +#define FISHEAD_SIZE 64 +#define FISBONE_SIZE 52 +#define FISBONE_MESSAGE_HEADER_OFFSET 44 + +/* fishead_packet holds a fishead header packet. */ +typedef struct { + ogg_uint16_t version_major; /* skeleton version major */ + ogg_uint16_t version_minor; /* skeleton version minor */ + /* Start time of the presentation + * For a new stream presentationtime & basetime is same. */ + ogg_int64_t ptime_n; /* presentation time numerator */ + ogg_int64_t ptime_d; /* presentation time denominator */ + ogg_int64_t btime_n; /* basetime numerator */ + ogg_int64_t btime_d; /* basetime denominator */ + /* will holds the time of origin of the stream, a 20 bit field. */ + unsigned char UTC[20]; +} fishead_packet; + +/* fisbone_packet holds a fisbone header packet. */ +typedef struct { + ogg_uint32_t serial_no; /* serial no of the corresponding stream */ + ogg_uint32_t nr_header_packet; /* number of header packets */ + /* granule rate is the temporal resolution of the logical bitstream */ + ogg_int64_t granule_rate_n; /* granule rate numerator */ + ogg_int64_t granule_rate_d; /* granule rate denominator */ + ogg_int64_t start_granule; /* start granule value */ + ogg_uint32_t preroll; /* preroll */ + unsigned char granule_shift; /* 1 byte value holding the granule shift */ + char *message_header_fields; /* holds all the message header fields */ + /* current total size of the message header fields, for realloc purpose, initially zero */ + ogg_uint32_t current_header_size; +} fisbone_packet; + +extern int write_ogg_page_to_file(ogg_page *og, FILE *out); +extern int add_message_header_field(fisbone_packet *fp, char *header_key, char *header_value); +/* remember to deallocate the returned ogg_packet properly */ +extern ogg_packet ogg_from_fishead(fishead_packet *fp); +extern ogg_packet ogg_from_fisbone(fisbone_packet *fp); +extern fishead_packet fishead_from_ogg(ogg_packet *op); +extern fisbone_packet fisbone_from_ogg(ogg_packet *op); +extern int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp); +extern int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp); +extern int add_eos_packet_to_stream(ogg_stream_state *os); +extern int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out); + +#ifdef __cplusplus +} +#endif + +#endif /* _SKELETON_H */ + + + + + + diff --git a/native/codec/libraries/celt/tools/wav_io.c b/native/codec/libraries/celt/tools/wav_io.c new file mode 100644 index 0000000..d231d5e --- /dev/null +++ b/native/codec/libraries/celt/tools/wav_io.c @@ -0,0 +1,223 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: wav_io.c + Routines to handle wav (RIFF) headers + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include "celt_types.h" +#include "wav_io.h" + + +int read_wav_header(FILE *file, int *rate, int *channels, int *format, celt_int32 *size) +{ + char ch[5]; + celt_int32 itmp; + celt_int16 stmp; + celt_int32 bpersec; + celt_int16 balign; + int skip_bytes; + int i; + + ch[4]=0; +#if 0 + fread(ch, 1, 4, file); + if (strcmp(ch, "RIFF")!=0) + { + fseek(file, 0, SEEK_SET); + return 0; + } + + fread(&itmp, 4, 1, file); + *size = le_int(itmp-36); + + fread(ch, 1, 4, file); + if (strcmp(ch, "WAVE")!=0) + { + fprintf (stderr, "RIFF file is not a WAVE file\n"); + return -1; + } +#endif + fread(ch, 1, 4, file); + while (strcmp(ch, "fmt ")!=0) + { + fread(&itmp, 4, 1, file); + itmp = le_int(itmp); + /*fprintf (stderr, "skip=%d\n", itmp);*/ + /*strange way of seeking, but it works even for pipes*/ + for (i=0;i2) + { + fprintf (stderr, "Only mono and (intensity) stereo supported\n"); + return -1; + } + + fread(&itmp, 4, 1, file); + itmp = le_int(itmp); + *rate = itmp; + + fread(&itmp, 4, 1, file); + bpersec = le_int(itmp); + + fread(&stmp, 2, 1, file); + balign = le_short(stmp); + + fread(&stmp, 2, 1, file); + stmp = le_short(stmp); + if (stmp!=16 && stmp!=8) + { + fprintf (stderr, "Only 8/16-bit linear supported\n"); + return -1; + } + *format=stmp; + + if (bpersec!=*rate**channels*stmp/8) + { + fprintf (stderr, "Corrupted header: ByteRate mismatch\n"); + return -1; + } + + if (balign!=*channels*stmp/8) + { + fprintf (stderr, "Corrupted header: BlockAlign mismatch\n"); + return -1; + } + + + /*strange way of seeking, but it works even for pipes*/ + if (skip_bytes>0) + for (i=0;i +#include "celt_types.h" + +#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) +#define le_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8)) +#define be_short(s) ((short) (s)) +#else +#define le_short(s) ((short) (s)) +#define be_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8)) +#endif + +/** Convert little endian */ +static inline celt_int32 le_int(celt_int32 i) +{ +#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) + celt_uint32 ui, ret; + ui = i; + ret = ui>>24; + ret |= (ui>>8)&0x0000ff00; + ret |= (ui<<8)&0x00ff0000; + ret |= (ui<<24); + return ret; +#else + return i; +#endif +} + +int read_wav_header(FILE *file, int *rate, int *channels, int *format, celt_int32 *size); + +void write_wav_header(FILE *file, int rate, int channels, int format, int size); + +#endif diff --git a/native/codec/libraries/celt/tools/wave_out.c b/native/codec/libraries/celt/tools/wave_out.c new file mode 100644 index 0000000..57b5703 --- /dev/null +++ b/native/codec/libraries/celt/tools/wave_out.c @@ -0,0 +1,220 @@ +/* Copyright (c) 2002, John Edwards + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Set TABS = 4 */ +/******************************************************************** + + function: To provide playback of 16 bit PCM wave data in Win32 + environments from decoded compressed files. + + ********************************************************************/ + +#if defined WIN32 || defined _WIN32 + +#include +#include +#include "wave_out.h" + +#define MAXWAVESIZE 4294967040LU +#define MAX_WAVEBLOCKS 32 + +// This is modified for USE_WIN_AUDIO - ONLY 2002-02-27 + + +static CRITICAL_SECTION cs; +static HWAVEOUT dev = NULL; +static int ScheduledBlocks = 0; +static int PlayedWaveHeadersCount = 0; // free index +static WAVEHDR* PlayedWaveHeaders [MAX_WAVEBLOCKS]; + +static int +Box ( const char* msg ) +{ + MessageBox ( NULL, msg, " "VERSION_STRING": Error Message . . .", MB_OK | MB_ICONEXCLAMATION ); + return -1; +} + + +/* + * This function registers already played WAVE chunks. Freeing is done by free_memory(), + */ + +static void CALLBACK +wave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) +{ + if ( uMsg == WOM_DONE ) { + EnterCriticalSection ( &cs ); + PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1; + LeaveCriticalSection ( &cs ); + } +} + + +static void +free_memory ( void ) +{ + WAVEHDR* wh; + HGLOBAL hg; + + EnterCriticalSection ( &cs ); + wh = PlayedWaveHeaders [--PlayedWaveHeadersCount]; + ScheduledBlocks--; // decrease the number of USED blocks + LeaveCriticalSection ( &cs ); + + waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) ); + + hg = GlobalHandle ( wh -> lpData ); // Deallocate the buffer memory + GlobalUnlock (hg); + GlobalFree (hg); + + hg = GlobalHandle ( wh ); // Deallocate the header memory + GlobalUnlock (hg); + GlobalFree (hg); +} + + +Int +Set_WIN_Params ( FILE_T dummyFile , + Ldouble SampleFreq, + Uint BitsPerSample, + Uint Channels ) +{ + WAVEFORMATEX outFormat; + UINT deviceID = WAVE_MAPPER; + + (void) dummyFile; + + if ( waveOutGetNumDevs () == 0 ) + return Box ( "No audio device present." ); + + outFormat.wFormatTag = WAVE_FORMAT_PCM; + outFormat.wBitsPerSample = BitsPerSample; + outFormat.nChannels = Channels; + outFormat.nSamplesPerSec = (unsigned long)(SampleFreq + 0.5); + outFormat.nBlockAlign = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels; + outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign; + + switch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD)wave_callback, 0, CALLBACK_FUNCTION ) ) + { + case MMSYSERR_ALLOCATED: return Box ( "Device is already open." ); + case MMSYSERR_BADDEVICEID: return Box ( "The specified device is out of range." ); + case MMSYSERR_NODRIVER: return Box ( "There is no audio driver in this system." ); + case MMSYSERR_NOMEM: return Box ( "Unable to allocate sound memory." ); + case WAVERR_BADFORMAT: return Box ( "This audio format is not supported." ); + case WAVERR_SYNC: return Box ( "The device is synchronous." ); + default: return Box ( "Unknown media error." ); + case MMSYSERR_NOERROR: break; + } + + waveOutReset ( dev ); + InitializeCriticalSection ( &cs ); + SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS ); + return 0; +} + + +int +WIN_Play_Samples ( const void* data, size_t len ) +{ + HGLOBAL hg; + HGLOBAL hg2; + LPWAVEHDR wh; + void* allocptr; + + do { + while ( PlayedWaveHeadersCount > 0 ) // free used blocks ... + free_memory (); + + if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ... + break; + Sleep (26); + } while (1); + + if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL ) // allocate some memory for a copy of the buffer + return Box ( "GlobalAlloc failed." ); + + allocptr = GlobalLock (hg2); + CopyMemory ( allocptr, data, len ); // Here we can call any modification output functions we want.... + + if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT! + return -1; + + wh = GlobalLock (hg); + wh -> dwBufferLength = len; + wh -> lpData = allocptr; + + if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) { + GlobalUnlock (hg); + GlobalFree (hg); + return -1; + } + + if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) { + GlobalUnlock (hg); + GlobalFree (hg); + return -1; + } + + EnterCriticalSection ( &cs ); + ScheduledBlocks++; + LeaveCriticalSection ( &cs ); + + return len; +} + + +int +WIN_Audio_close ( void ) +{ + if ( dev != NULL ) { + + while ( ScheduledBlocks > 0 ) { + Sleep (ScheduledBlocks); + while ( PlayedWaveHeadersCount > 0 ) // free used blocks ... + free_memory (); + } + + waveOutReset (dev); // reset the device + waveOutClose (dev); // close the device + dev = NULL; + } + + DeleteCriticalSection ( &cs ); + ScheduledBlocks = 0; + return 0; +} + +#endif + +/* end of wave_out.c */ diff --git a/native/codec/libraries/celt/tools/wave_out.h b/native/codec/libraries/celt/tools/wave_out.h new file mode 100644 index 0000000..2b8bc05 --- /dev/null +++ b/native/codec/libraries/celt/tools/wave_out.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2002, John Edwards + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// WAVE_OUT.H - Necessary stuff for WIN_AUDIO + +#ifndef WAVE_OUT_H +#define WAVE_OUT_H + +#include +#include +#ifdef __MINGW32__ +#include +#endif + +#define VERSION_STRING "\n 0.11.4\n" + +#define Cdecl __cdecl +#define __attribute__(x) +#define sleep(__sec) Sleep ((__sec) * 1000) +#define inline __inline +#define restrict + +//// constants ///////////////////////////////////////////////////// + +#define CD_SAMPLE_FREQ 44.1e3 +#define SAMPLE_SIZE 16 +#define SAMPLE_SIZE_STRING "" +#define WINAUDIO_FD ((FILE_T)-128) +#define FILE_T FILE* +#define INVALID_FILEDESC NULL + +//// Simple types ////////////////////////////////////////////////// + +typedef signed int Int; // at least -32767...+32767, fast type +typedef unsigned int Uint; // at least 0...65535, fast type +typedef long double Ldouble; // most exact floating point format + +//// procedures/functions ////////////////////////////////////////// +// wave_out.c +Int Set_WIN_Params ( FILE_T dummyFile , Ldouble SampleFreq, Uint BitsPerSample, Uint Channels); +int WIN_Play_Samples ( const void* buff, size_t len ); +int WIN_Audio_close ( void ); + +#endif /* WAVE_OUT_H */ diff --git a/native/codec/libraries/cmake/opus/CMakeLists.txt b/native/codec/libraries/cmake/opus/CMakeLists.txt new file mode 100644 index 0000000..23b5880 --- /dev/null +++ b/native/codec/libraries/cmake/opus/CMakeLists.txt @@ -0,0 +1,356 @@ +cmake_minimum_required(VERSION 3.1) +project(opus) + + +option(USE_ALLOCA "USE_ALLOCA" ON) +option(FIXED_POINT "FIXED_POINT" OFF) +option(DISABLE_FLOAT_API "DISABLE_FLOAT_API" OFF) + +#HAVE_SSE +#HAVE_SSE2 +#HAVE_SSE4_1 + +#CPU_ARM +# HAVE_ARM_NEON_INTR +# HAVE_ARM_NE10 + +set(SILK_SOURCES + silk/CNG.c + silk/code_signs.c + silk/init_decoder.c + silk/decode_core.c + silk/decode_frame.c + silk/decode_parameters.c + silk/decode_indices.c + silk/decode_pulses.c + silk/decoder_set_fs.c + silk/dec_API.c + silk/enc_API.c + silk/encode_indices.c + silk/encode_pulses.c + silk/gain_quant.c + silk/interpolate.c + silk/LP_variable_cutoff.c + silk/NLSF_decode.c + silk/NSQ.c + silk/NSQ_del_dec.c + silk/PLC.c + silk/shell_coder.c + silk/tables_gain.c + silk/tables_LTP.c + silk/tables_NLSF_CB_NB_MB.c + silk/tables_NLSF_CB_WB.c + silk/tables_other.c + silk/tables_pitch_lag.c + silk/tables_pulses_per_block.c + silk/VAD.c + silk/control_audio_bandwidth.c + silk/quant_LTP_gains.c + silk/VQ_WMat_EC.c + silk/HP_variable_cutoff.c + silk/NLSF_encode.c + silk/NLSF_VQ.c + silk/NLSF_unpack.c + silk/NLSF_del_dec_quant.c + silk/process_NLSFs.c + silk/stereo_LR_to_MS.c + silk/stereo_MS_to_LR.c + silk/check_control_input.c + silk/control_SNR.c + silk/init_encoder.c + silk/control_codec.c + silk/A2NLSF.c + silk/ana_filt_bank_1.c + silk/biquad_alt.c + silk/bwexpander_32.c + silk/bwexpander.c + silk/debug.c + silk/decode_pitch.c + silk/inner_prod_aligned.c + silk/lin2log.c + silk/log2lin.c + silk/LPC_analysis_filter.c + silk/LPC_inv_pred_gain.c + silk/table_LSF_cos.c + silk/NLSF2A.c + silk/NLSF_stabilize.c + silk/NLSF_VQ_weights_laroia.c + silk/pitch_est_tables.c + silk/resampler.c + silk/resampler_down2_3.c + silk/resampler_down2.c + silk/resampler_private_AR2.c + silk/resampler_private_down_FIR.c + silk/resampler_private_IIR_FIR.c + silk/resampler_private_up2_HQ.c + silk/resampler_rom.c + silk/sigm_Q15.c + silk/sort.c + silk/sum_sqr_shift.c + silk/stereo_decode_pred.c + silk/stereo_encode_pred.c + silk/stereo_find_predictor.c + silk/stereo_quant_pred.c + silk/LPC_fit.c +) + +set(SILK_SOURCES_SSE4_1 + silk/x86/NSQ_sse.c + silk/x86/NSQ_del_dec_sse.c + silk/x86/x86_silk_map.c + silk/x86/VAD_sse.c + silk/x86/VQ_WMat_EC_sse.c +) + +set(SILK_SOURCES_ARM_NEON_INTR + silk/arm/arm_silk_map.c + silk/arm/NSQ_del_dec_neon_intr.c + silk/arm/NSQ_neon.c +) + +set(SILK_SOURCES_FIXED + silk/fixed/LTP_analysis_filter_FIX.c + silk/fixed/LTP_scale_ctrl_FIX.c + silk/fixed/corrMatrix_FIX.c + silk/fixed/encode_frame_FIX.c + silk/fixed/find_LPC_FIX.c + silk/fixed/find_LTP_FIX.c + silk/fixed/find_pitch_lags_FIX.c + silk/fixed/find_pred_coefs_FIX.c + silk/fixed/noise_shape_analysis_FIX.c + silk/fixed/process_gains_FIX.c + silk/fixed/regularize_correlations_FIX.c + silk/fixed/residual_energy16_FIX.c + silk/fixed/residual_energy_FIX.c + silk/fixed/warped_autocorrelation_FIX.c + silk/fixed/apply_sine_window_FIX.c + silk/fixed/autocorr_FIX.c + silk/fixed/burg_modified_FIX.c + silk/fixed/k2a_FIX.c + silk/fixed/k2a_Q16_FIX.c + silk/fixed/pitch_analysis_core_FIX.c + silk/fixed/vector_ops_FIX.c + silk/fixed/schur64_FIX.c + silk/fixed/schur_FIX.c +) + +set(SILK_SOURCES_FIXED_SSE4_1 + silk/fixed/x86/vector_ops_FIX_sse.c + silk/fixed/x86/burg_modified_FIX_sse.c +) + +set(SILK_SOURCES_FLOAT + silk/float/apply_sine_window_FLP.c + silk/float/corrMatrix_FLP.c + silk/float/encode_frame_FLP.c + silk/float/find_LPC_FLP.c + silk/float/find_LTP_FLP.c + silk/float/find_pitch_lags_FLP.c + silk/float/find_pred_coefs_FLP.c + silk/float/LPC_analysis_filter_FLP.c + silk/float/LTP_analysis_filter_FLP.c + silk/float/LTP_scale_ctrl_FLP.c + silk/float/noise_shape_analysis_FLP.c + silk/float/process_gains_FLP.c + silk/float/regularize_correlations_FLP.c + silk/float/residual_energy_FLP.c + silk/float/warped_autocorrelation_FLP.c + silk/float/wrappers_FLP.c + silk/float/autocorrelation_FLP.c + silk/float/burg_modified_FLP.c + silk/float/bwexpander_FLP.c + silk/float/energy_FLP.c + silk/float/inner_product_FLP.c + silk/float/k2a_FLP.c + silk/float/LPC_inv_pred_gain_FLP.c + silk/float/pitch_analysis_core_FLP.c + silk/float/scale_copy_vector_FLP.c + silk/float/scale_vector_FLP.c + silk/float/schur_FLP.c + silk/float/sort_FLP.c +) + +set(CELT_SOURCES + celt/bands.c + celt/celt.c + celt/celt_encoder.c + celt/celt_decoder.c + celt/cwrs.c + celt/entcode.c + celt/entdec.c + celt/entenc.c + celt/kiss_fft.c + celt/laplace.c + celt/mathops.c + celt/mdct.c + celt/modes.c + celt/pitch.c + celt/celt_lpc.c + celt/quant_bands.c + celt/rate.c + celt/vq.c +) + +set(CELT_SOURCES_SSE + celt/x86/x86cpu.c + celt/x86/x86_celt_map.c + celt/x86/pitch_sse.c +) + +set(CELT_SOURCES_SSE2 + celt/x86/pitch_sse2.c celt/x86/vq_sse2.c +) + +set(CELT_SOURCES_SSE4_1 + celt/x86/celt_lpc_sse.c + celt/x86/pitch_sse4_1.c +) + +set(CELT_SOURCES_ARM + celt/arm/armcpu.c + celt/arm/arm_celt_map.c +) + + +set(CELT_SOURCES_ARM_ASM + celt/arm/celt_pitch_xcorr_arm.s +) + +set(CELT_AM_SOURCES_ARM_ASM + celt/arm/armopts.s.in +) + +set(CELT_SOURCES_ARM_NEON_INTR + celt/arm/celt_neon_intr.c +) + +set(CELT_SOURCES_ARM_NE10 + celt/arm/celt_ne10_fft.c + celt/arm/celt_ne10_mdct.c +) + + + +set(OPUS_SOURCES + src/opus.c + src/opus_decoder.c + src/opus_encoder.c + src/opus_multistream.c + src/opus_multistream_encoder.c + src/opus_multistream_decoder.c + src/repacketizer.c +) + +set(OPUS_SOURCES_FLOAT + src/analysis.c + src/mlp.c + src/mlp_data.c +) + +if(FIXED_POINT) + list(APPEND SILK_SOURCES ${SILK_SOURCES_FIXED}) + if(HAVE_SSE4_1) + list(APPEND SILK_SOURCES ${SILK_SOURCES_SSE4_1} ${SILK_SOURCES_FIXED_SSE4_1}) + endif(HAVE_SSE4_1) +else(FIXED_POINT) + list(APPEND SILK_SOURCES ${SILK_SOURCES_FLOAT}) + if (HAVE_SSE4_1) + list(APPEND SILK_SOURCES ${SILK_SOURCES_SSE4_1}) + endif(HAVE_SSE4_1) +endif(FIXED_POINT) + +if (DISABLE_FLOAT_API) +else(DISABLE_FLOAT_API) + list(APPEND OPUS_SOURCES ${OPUS_SOURCES_FLOAT}) +endif(DISABLE_FLOAT_API) + +if(HAVE_SSE) + list(APPEND CELT_SOURCES ${CELT_SOURCES_SSE}) +endif(HAVE_SSE) + +if(HAVE_SSE2) + list(APPEND CELT_SOURCES ${CELT_SOURCES_SSE2}) +endif(HAVE_SSE2) + +if(HAVE_SSE4_1) + list(APPEND CELT_SOURCES ${CELT_SOURCES_SSE4_1}) +endif(HAVE_SSE4_1) + +if(CPU_ARM) + list(APPEND CELT_SOURCES ${CELT_SOURCES_ARM}) + list(APPEND SILK_SOURCES ${SILK_SOURCES_ARM}) + + if(HAVE_ARM_NEON_INTR) + list(APPEND CELT_SOURCES ${CELT_SOURCES_ARM_NEON_INTR}) + list(APPEND SILK_SOURCES ${SILK_SOURCES_ARM_NEON_INTR}) + endif(HAVE_ARM_NEON_INTR) + + if(HAVE_ARM_NE10) + list(APPEND CELT_SOURCES ${CELT_SOURCES_ARM_NE10}) + endif(HAVE_ARM_NE10) + + #if(OPUS_ARM_EXTERNAL_ASM) + # noinst_LTLIBRARIES = libarmasm.la + # libarmasm_la_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) + # BUILT_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \ + # $(CELT_AM_SOURCES_ARM_ASM:.s.in=.s) \ + # $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S) + #endif(OPUS_ARM_EXTERNAL_ASM) +endif(CPU_ARM) + +#add_definitions(-DOPUS_VERSION="\\"1.0.1\\"") + +# It is strongly recommended to uncomment one of these +# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation +# USE_ALLOCA: Use alloca() for stack allocation +# If none is defined, then the fallback is a non-threadsafe global array +if (USE_ALLOCA) + add_definitions(-DUSE_ALLOCA) +else (USE_ALLOCA) + add_definitions(-DVAR_ARRAYS) +endif (USE_ALLOCA) + +# These options affect performance +# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion +add_definitions(-DHAVE_LRINTF) + +if(UNIX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wstrict-prototypes -Wextra -Wcast-align") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wnested-externs -Wshadow") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") + add_definitions(-D__OPTIMIZE__) +endif(UNIX) + +add_definitions(-DOPUS_BUILD) + +if (FIXED_POINT) + add_definitions(-DFIXED_POINT=1 -DDISABLE_FLOAT_API) +endif (FIXED_POINT) + +set(OPUS_SOURCE_DIRECTORY ".") +include_directories( + ${OPUS_SOURCE_DIRECTORY}/include + ${OPUS_SOURCE_DIRECTORY}/silk + ${OPUS_SOURCE_DIRECTORY}/silk/float + ${OPUS_SOURCE_DIRECTORY}/silk/fixed + ${OPUS_SOURCE_DIRECTORY}/celt + ${OPUS_SOURCE_DIRECTORY}/src + ${OPUS_SOURCE_DIRECTORY}/include) + + +# add opus prefix +set(ALL_SOURCES) +foreach(src_file ${CELT_SOURCES} ${SILK_SOURCES} ${OPUS_SOURCES}) + list(APPEND ALL_SOURCES ${OPUS_SOURCE_DIRECTORY}/${src_file}) +endforeach(src_file) + + +add_library(opus STATIC ${ALL_SOURCES}) +install( + TARGETS opus + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) + + +install(DIRECTORY ${OPUS_SOURCE_DIRECTORY}/include/ DESTINATION include/opus) \ No newline at end of file diff --git a/native/codec/libraries/opus/.appveyor.yml b/native/codec/libraries/opus/.appveyor.yml new file mode 100644 index 0000000..a0f4a77 --- /dev/null +++ b/native/codec/libraries/opus/.appveyor.yml @@ -0,0 +1,37 @@ +image: Visual Studio 2015 +configuration: +- Debug +- DebugDLL +- DebugDLL_fixed +- Release +- ReleaseDLL +- ReleaseDLL_fixed + +platform: +- Win32 +- x64 + +environment: + api_key: + secure: kR3Ac0NjGwFnTmXdFrR8d6VXjdk5F7L4F/BilC4nvaM= + +build: + project: win32\VS2015\opus.sln + parallel: true + verbosity: minimal + +after_build: +- cd %APPVEYOR_BUILD_FOLDER% +- 7z a opus.zip win32\VS2015\%PLATFORM%\%CONFIGURATION%\opus.??? include\*.h + +test_script: +- cd %APPVEYOR_BUILD_FOLDER%\win32\VS2015\%PLATFORM%\%CONFIGURATION% +- test_opus_api.exe +- test_opus_decode.exe +- test_opus_encode.exe + +artifacts: +- path: opus.zip + +on_success: +- ps: if ($env:api_key -and "$env:configuration/$env:platform" -eq "ReleaseDLL_fixed/x64") { Start-AppveyorBuild -ApiKey $env:api_key -ProjectSlug 'opus-tools' } diff --git a/native/codec/libraries/opus/.gitattributes b/native/codec/libraries/opus/.gitattributes new file mode 100644 index 0000000..649c810 --- /dev/null +++ b/native/codec/libraries/opus/.gitattributes @@ -0,0 +1,10 @@ +.gitignore export-ignore +.gitattributes export-ignore + +update_version export-ignore + +*.bat eol=crlf +*.sln eol=crlf +*.vcxproj eol=crlf +*.vcxproj.filters eol=crlf +common.props eol=crlf diff --git a/native/codec/libraries/opus/.gitignore b/native/codec/libraries/opus/.gitignore new file mode 100644 index 0000000..31e2901 --- /dev/null +++ b/native/codec/libraries/opus/.gitignore @@ -0,0 +1,89 @@ +Doxyfile +Makefile +Makefile.in +TAGS +aclocal.m4 +autom4te.cache +*.kdevelop.pcs +*.kdevses +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +INSTALL +install-sh +.deps +.libs +.dirstamp +*.a +*.exe +*.la +*-gnu.S +testcelt +libtool +ltmain.sh +missing +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +opus_compare +opus_demo +repacketizer_demo +stamp-h1 +test-driver +*.sw* +*.o +*.lo +*.pc +*.tar.gz +*~ +tests/*test +tests/test_opus_api +tests/test_opus_decode +tests/test_opus_encode +tests/test_opus_padding +tests/test_opus_projection +celt/arm/armopts.s +celt/dump_modes/dump_modes +celt/tests/test_unit_cwrs32 +celt/tests/test_unit_dft +celt/tests/test_unit_entropy +celt/tests/test_unit_laplace +celt/tests/test_unit_mathops +celt/tests/test_unit_mdct +celt/tests/test_unit_rotation +celt/tests/test_unit_types +doc/doxygen_sqlite3.db +doc/doxygen-build.stamp +doc/html +doc/latex +doc/man +package_version +version.h +celt/Debug +celt/Release +celt/x64 +silk/Debug +silk/Release +silk/x64 +silk/fixed/Debug +silk/fixed/Release +silk/fixed/x64 +silk/float/Debug +silk/float/Release +silk/float/x64 +silk/tests/test_unit_LPC_inv_pred_gain +src/Debug +src/Release +src/x64 +/*[Bb]uild*/ +.vs/ +.vscode/ +CMakeSettings.json diff --git a/native/codec/libraries/opus/.travis.yml b/native/codec/libraries/opus/.travis.yml new file mode 100644 index 0000000..821c813 --- /dev/null +++ b/native/codec/libraries/opus/.travis.yml @@ -0,0 +1,21 @@ +language: c + +compiler: + - gcc + - clang + +os: + - linux + - osx + +env: + - CONFIG="" + - CONFIG="--enable-assertions" + - CONFIG="--enable-fixed-point" + - CONFIG="--enable-fixed-point --disable-float-api" + - CONFIG="--enable-fixed-point --enable-assertions" + +script: + - ./autogen.sh + - ./configure $CONFIG + - make distcheck diff --git a/native/codec/libraries/opus/AUTHORS b/native/codec/libraries/opus/AUTHORS new file mode 100644 index 0000000..b3d22a2 --- /dev/null +++ b/native/codec/libraries/opus/AUTHORS @@ -0,0 +1,6 @@ +Jean-Marc Valin (jmvalin@jmvalin.ca) +Koen Vos (koenvos74@gmail.com) +Timothy Terriberry (tterribe@xiph.org) +Karsten Vandborg Sorensen (karsten.vandborg.sorensen@skype.net) +Soren Skak Jensen (ssjensen@gn.com) +Gregory Maxwell (greg@xiph.org) diff --git a/native/codec/libraries/opus/CMakeLists.txt b/native/codec/libraries/opus/CMakeLists.txt new file mode 100644 index 0000000..17ee3fc --- /dev/null +++ b/native/codec/libraries/opus/CMakeLists.txt @@ -0,0 +1,411 @@ +cmake_minimum_required(VERSION 3.1) + +include(opus_functions.cmake) + +get_library_version(OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR) +message(STATUS "Opus library version: ${OPUS_LIBRARY_VERSION}") + +get_package_version(PACKAGE_VERSION) +message(STATUS "Opus package version: ${PACKAGE_VERSION}") + +string(REGEX + REPLACE "^([0-9]+.[0-9]+\\.?([0-9]+)?).*" + "\\1" + PROJECT_VERSION + ${PACKAGE_VERSION}) +message(STATUS "Opus project version: ${PROJECT_VERSION}") + +project(Opus LANGUAGES C VERSION ${PROJECT_VERSION}) +include(opus_buildtype.cmake) + +option(OPUS_STACK_PROTECTOR "Use stack protection" ON) +option(OPUS_USE_ALLOCA "Use alloca for stack arrays (on non-C99 compilers)" OFF) +option(OPUS_CUSTOM_MODES "Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames" + OFF) +option(OPUS_BUILD_PROGRAMS "Build programs" OFF) +option(OPUS_FIXED_POINT + "Compile as fixed-point (for machines without a fast enough FPU)" OFF) +option(OPUS_ENABLE_FLOAT_API + "Compile with the floating point API (for machines with float library" + ON) +option(OPUS_INSTALL_PKG_CONFIG_MODULE "Install PkgConfig module" ON) +option(OPUS_INSTALL_CMAKE_CONFIG_MODULE "Install CMake package config module" + ON) + +include(opus_config.cmake) +include(opus_sources.cmake) +include(GNUInstallDirs) +include(CMakeDependentOption) +include(FeatureSummary) + +if(OPUS_STACK_PROTECTOR) + if(NOT MSVC) # GC on by default on MSVC + check_and_set_flag(STACK_PROTECTION_STRONG -fstack-protector-strong) + endif() +else() + if(MSVC) + check_and_set_flag(BUFFER_SECURITY_CHECK /GS-) + endif() +endif() + +if(OPUS_CPU_X86 OR OPUS_CPU_X64) + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE + "Does runtime check for SSE1 support" + ON + "SSE1_SUPPORTED" + OFF) + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE2 + "Does runtime check for SSE2 support" + ON + "SSE2_SUPPORTED" + OFF) + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE4_1 + "Does runtime check for SSE4.1 support" + ON + "SSE4_1_SUPPORTED" + OFF) + cmake_dependent_option(OPUS_X86_MAY_HAVE_AVX + "Does runtime check for AVX support" + ON + "AVX_SUPPORTED" + OFF) + + if(OPUS_CPU_X64) # Assume 64 bit has SSE2 support + cmake_dependent_option(OPUS_X86_PRESUME_SSE + "Assume target CPU has SSE1 support" + ON + "OPUS_X86_MAY_HAVE_SSE" + OFF) + cmake_dependent_option(OPUS_X86_PRESUME_SSE2 + "Assume target CPU has SSE2 support" + ON + "OPUS_X86_MAY_HAVE_SSE2" + OFF) + else() + cmake_dependent_option(OPUS_X86_PRESUME_SSE + "Assume target CPU has SSE1 support" + OFF + "OPUS_X86_MAY_HAVE_SSE" + OFF) + cmake_dependent_option(OPUS_X86_PRESUME_SSE2 + "Assume target CPU has SSE2 support" + OFF + "OPUS_X86_MAY_HAVE_SSE2" + OFF) + endif() + cmake_dependent_option(OPUS_X86_PRESUME_SSE4_1 + "Assume target CPU has SSE4.1 support" + OFF + "OPUS_X86_MAY_HAVE_SSE4_1" + OFF) + cmake_dependent_option(OPUS_X86_PRESUME_AVX + "Assume target CPU has AVX support" + OFF + "OPUS_X86_MAY_HAVE_AVX" + OFF) +endif() + +set_package_properties(Git + PROPERTIES + TYPE + REQUIRED + DESCRIPTION + "fast, scalable, distributed revision control system" + URL + "https://git-scm.com/" + PURPOSE + "required to set up package version") + +add_feature_info(STACK_PROTECTOR OPUS_STACK_PROTECTOR "Use stack protection") +add_feature_info(USE_ALLOCA OPUS_USE_ALLOCA + "Use alloca for stack arrays (on non-C99 compilers)") +add_feature_info(CUSTOM_MODES OPUS_CUSTOM_MODES + "Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames") +add_feature_info(BUILD_PROGRAMS OPUS_BUILD_PROGRAMS "Build programs") +add_feature_info( + FIXED_POINT OPUS_FIXED_POINT + "compile as fixed-point (for machines without a fast enough FPU)") +add_feature_info( + FLOAT_API OPUS_ENABLE_FLOAT_API + "compile with the floating point API (for machines with float library)") + +add_feature_info(INSTALL_PKG_CONFIG_MODULE OPUS_INSTALL_PKG_CONFIG_MODULE + "install PkgConfig module") +add_feature_info(INSTALL_CMAKE_CONFIG_MODULE OPUS_INSTALL_CMAKE_CONFIG_MODULE + "install CMake package config module") + +if(OPUS_CPU_X86 OR OPUS_CPU_X64) + add_feature_info(X86_MAY_HAVE_SSE OPUS_X86_MAY_HAVE_SSE + "does runtime check for SSE1 support") + add_feature_info(X86_MAY_HAVE_SSE2 OPUS_X86_MAY_HAVE_SSE2 + "does runtime check for SSE2 support") + add_feature_info(X86_MAY_HAVE_SSE4_1 OPUS_X86_MAY_HAVE_SSE4_1 + "does runtime check for SSE4_1 support") + add_feature_info(X86_MAY_HAVE_AVX OPUS_X86_MAY_HAVE_AVX + "does runtime check for AVX support") + add_feature_info(X86_PRESUME_SSE OPUS_X86_PRESUME_SSE + "assume target CPU has SSE1 support") + add_feature_info(X86_PRESUME_SSE2 OPUS_X86_PRESUME_SSE2 + "assume target CPU has SSE2 support") + add_feature_info(X86_PRESUME_SSE4_1 OPUS_X86_PRESUME_SSE4_1 + "assume target CPU has SSE4_1 support") + add_feature_info(X86_PRESUME_AVX OPUS_X86_PRESUME_AVX + "assume target CPU has AVX support") +endif() + +feature_summary(WHAT ALL) + +add_library(opus ${opus_sources} ${opus_sources_float}) + +set(Opus_PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_custom.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_defines.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_multistream.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_projection.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_types.h) + +set_target_properties(opus + PROPERTIES SOVERSION + ${OPUS_LIBRARY_VERSION_MAJOR} + VERSION + ${OPUS_LIBRARY_VERSION} + PUBLIC_HEADER + "${Opus_PUBLIC_HEADER}") + +target_include_directories( + opus + PUBLIC $ + $ + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + celt + silk) + +target_link_libraries(opus PRIVATE ${OPUS_REQUIRED_LIBRARIES}) +target_compile_definitions(opus PRIVATE OPUS_BUILD ENABLE_HARDENING) + +if(NOT MSVC) + target_compile_definitions(opus PRIVATE FORTIFY_SOURCE=2) +endif() + +# It is strongly recommended to uncomment one of these VAR_ARRAYS: Use C99 +# variable-length arrays for stack allocation USE_ALLOCA: Use alloca() for stack +# allocation If none is defined, then the fallback is a non-threadsafe global +# array +if(OPUS_USE_ALLOCA OR MSVC) + target_compile_definitions(opus PRIVATE USE_ALLOCA) +else() + target_compile_definitions(opus PRIVATE VAR_ARRAYS) +endif() + +if(OPUS_CUSTOM_MODES) + target_compile_definitions(opus PRIVATE CUSTOM_MODES) +endif() + +if(BUILD_SHARED_LIBS) + if(WIN32) + target_compile_definitions(opus PRIVATE DLL_EXPORT) + else() + include(CheckCCompilerFlag) + check_c_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) + if(COMPILER_HAS_HIDDEN_VISIBILITY) + set_target_properties(opus PROPERTIES C_VISIBILITY_PRESET hidden) + endif() + endif() +endif() + +add_sources_group(opus silk ${silk_sources}) +add_sources_group(opus celt ${celt_sources}) + +if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed}) + target_include_directories(opus PRIVATE silk/fixed) + target_compile_definitions(opus PRIVATE FIXED_POINT=1) +else() + add_sources_group(opus silk ${silk_sources_float}) + target_include_directories(opus PRIVATE silk/float) +endif() + +if(NOT OPUS_ENABLE_FLOAT_API) + target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API) +endif() + +if(OPUS_X86_MAY_HAVE_SSE + OR OPUS_X86_MAY_HAVE_SSE2 + OR OPUS_X86_MAY_HAVE_SSE4_1 + OR OPUS_X86_MAY_HAVE_AVX) + target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD) +endif() + +if(OPUS_X86_MAY_HAVE_SSE) + add_sources_group(opus celt ${celt_sources_sse}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE) +endif() +if(OPUS_X86_PRESUME_SSE) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE) +endif() + +if(OPUS_X86_MAY_HAVE_SSE2) + add_sources_group(opus celt ${celt_sources_sse2}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE2) +endif() +if(OPUS_X86_PRESUME_SSE2) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE2) +endif() + +if(OPUS_X86_MAY_HAVE_SSE) + add_sources_group(opus celt ${celt_sources_sse4_1}) + add_sources_group(opus silk ${silk_sources_sse4_1}) + if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed_sse4_1}) + endif() + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE4_1) +endif() +if(OPUS_X86_PRESUME_SSE4_1) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE4_1) +endif() + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(armv7-a)") + add_sources_group(opus celt ${celt_sources_arm}) +endif() + +if(COMPILER_SUPPORT_NEON AND OPUS_USE_NEON) + + if(OPUS_MAY_HAVE_NEON) + if(RUNTIME_CPU_CAPABILITY_DETECTION) + message(STATUS "OPUS_MAY_HAVE_NEON enabling runtime detection") + target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD) + else() + message(ERROR "Runtime cpu capability detection needed for MAY_HAVE_NEON") + endif() + # Do runtime check for NEON + target_compile_definitions(opus + PRIVATE + OPUS_ARM_MAY_HAVE_NEON + OPUS_ARM_MAY_HAVE_NEON_INTR) + endif() + + add_sources_group(opus celt ${celt_sources_arm_neon_intr}) + add_sources_group(opus silk ${silk_sources_arm_neon_intr}) + + # silk arm neon depends on main_Fix.h + target_include_directories(opus PRIVATE silk/fixed) + + if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed_arm_neon_intr}) + endif() + + if(OPUS_PRESUME_NEON) + target_compile_definitions(opus + PRIVATE + OPUS_ARM_PRESUME_NEON + OPUS_ARM_PRESUME_NEON_INTR) + endif() +endif() + +install(TARGETS opus + EXPORT OpusTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus) + +if(OPUS_INSTALL_PKG_CONFIG_MODULE) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix ${CMAKE_INSTALL_PREFIX}) + set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) + set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) + set(VERSION ${OPUS_LIBRARY_VERSION}) + set(VERSION ${OPUS_LIBRARY_VERSION}) + if(HAVE_LIBM) + set(LIBM "-lm") + endif() + configure_file(opus.pc.in opus.pc) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() + +if(OPUS_INSTALL_CMAKE_CONFIG_MODULE) + set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + install(EXPORT OpusTargets + NAMESPACE Opus:: + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) + + include(CMakePackageConfigHelpers) + + set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) + configure_package_config_file(OpusConfig.cmake.in + OpusConfig.cmake + INSTALL_DESTINATION + ${CMAKE_INSTALL_PACKAGEDIR} + PATH_VARS + INCLUDE_INSTALL_DIR + INSTALL_PREFIX + ${CMAKE_INSTALL_PREFIX}) + write_basic_package_version_file(OpusConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) +endif() + +if(OPUS_BUILD_PROGRAMS) + # demo + if(OPUS_CUSTOM_MODES) + add_executable(opus_custom_demo ${opus_custom_demo_sources}) + target_include_directories(opus_custom_demo + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(opus_custom_demo PRIVATE opus) + endif() + + add_executable(opus_demo ${opus_demo_sources}) + target_include_directories(opus_demo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_include_directories(opus_demo PRIVATE silk) # debug.h + target_include_directories(opus_demo PRIVATE celt) # arch.h + target_link_libraries(opus_demo PRIVATE opus) + + # compare + add_executable(opus_compare ${opus_compare_sources}) + target_include_directories(opus_compare PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(opus_compare PRIVATE opus) +endif() + +if(BUILD_TESTING) + enable_testing() + + # tests + add_executable(test_opus_decode ${test_opus_decode_sources}) + target_include_directories(test_opus_decode + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(test_opus_decode PRIVATE opus) + if(OPUS_FIXED_POINT) + target_compile_definitions(test_opus_decode PRIVATE DISABLE_FLOAT_API) + endif() + add_test(test_opus_decode test_opus_decode) + + add_executable(test_opus_padding ${test_opus_padding_sources}) + target_include_directories(test_opus_padding + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(test_opus_padding PRIVATE opus) + add_test(test_opus_padding test_opus_padding) + + if(NOT BUILD_SHARED_LIBS) + # disable tests that depends on private API when building shared lib + add_executable(test_opus_api ${test_opus_api_sources}) + target_include_directories(test_opus_api + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt) + target_link_libraries(test_opus_api PRIVATE opus) + if(OPUS_FIXED_POINT) + target_compile_definitions(test_opus_api PRIVATE DISABLE_FLOAT_API) + endif() + add_test(test_opus_api test_opus_api) + + add_executable(test_opus_encode ${test_opus_encode_sources}) + target_include_directories(test_opus_encode + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt) + target_link_libraries(test_opus_encode PRIVATE opus) + add_test(test_opus_encode test_opus_encode) + endif() +endif() diff --git a/native/codec/libraries/opus/COPYING b/native/codec/libraries/opus/COPYING new file mode 100644 index 0000000..9c739c3 --- /dev/null +++ b/native/codec/libraries/opus/COPYING @@ -0,0 +1,44 @@ +Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic, + Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, Gregory Maxwell, Mark Borgerding, + Erik de Castro Lopo + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Opus is subject to the royalty-free patent licenses which are +specified at: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/native/codec/libraries/opus/ChangeLog b/native/codec/libraries/opus/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/native/codec/libraries/opus/LICENSE_PLEASE_READ.txt b/native/codec/libraries/opus/LICENSE_PLEASE_READ.txt new file mode 100644 index 0000000..bc88efa --- /dev/null +++ b/native/codec/libraries/opus/LICENSE_PLEASE_READ.txt @@ -0,0 +1,22 @@ +Contributions to the collaboration shall not be considered confidential. + +Each contributor represents and warrants that it has the right and +authority to license copyright in its contributions to the collaboration. + +Each contributor agrees to license the copyright in the contributions +under the Modified (2-clause or 3-clause) BSD License or the Clear BSD License. + +Please see the IPR statements submitted to the IETF for the complete +patent licensing details: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Skype Limited: +https://datatracker.ietf.org/ipr/1602/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/native/codec/libraries/opus/Makefile.am b/native/codec/libraries/opus/Makefile.am new file mode 100644 index 0000000..4e3f183 --- /dev/null +++ b/native/codec/libraries/opus/Makefile.am @@ -0,0 +1,351 @@ +# Provide the full test output for failed tests when using the parallel +# test suite (which is enabled by default with automake 1.13+). +export VERBOSE = yes + +AUTOMAKE_OPTIONS = subdir-objects +ACLOCAL_AMFLAGS = -I m4 + +lib_LTLIBRARIES = libopus.la + +DIST_SUBDIRS = doc + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/celt -I$(top_srcdir)/silk \ + -I$(top_srcdir)/silk/float -I$(top_srcdir)/silk/fixed $(NE10_CFLAGS) + +include celt_sources.mk +include silk_sources.mk +include opus_sources.mk + +if FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +if HAVE_SSE4_1 +SILK_SOURCES += $(SILK_SOURCES_SSE4_1) $(SILK_SOURCES_FIXED_SSE4_1) +endif +if HAVE_ARM_NEON_INTR +SILK_SOURCES += $(SILK_SOURCES_FIXED_ARM_NEON_INTR) +endif +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +if HAVE_SSE4_1 +SILK_SOURCES += $(SILK_SOURCES_SSE4_1) +endif +endif + +if DISABLE_FLOAT_API +else +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +if HAVE_SSE +CELT_SOURCES += $(CELT_SOURCES_SSE) +endif +if HAVE_SSE2 +CELT_SOURCES += $(CELT_SOURCES_SSE2) +endif +if HAVE_SSE4_1 +CELT_SOURCES += $(CELT_SOURCES_SSE4_1) +endif + +if CPU_ARM +CELT_SOURCES += $(CELT_SOURCES_ARM) +SILK_SOURCES += $(SILK_SOURCES_ARM) + +if HAVE_ARM_NEON_INTR +CELT_SOURCES += $(CELT_SOURCES_ARM_NEON_INTR) +SILK_SOURCES += $(SILK_SOURCES_ARM_NEON_INTR) +endif + +if HAVE_ARM_NE10 +CELT_SOURCES += $(CELT_SOURCES_ARM_NE10) +endif + +if OPUS_ARM_EXTERNAL_ASM +noinst_LTLIBRARIES = libarmasm.la +libarmasm_la_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) +BUILT_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=.s) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S) +endif +endif + +CLEANFILES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S) + +include celt_headers.mk +include silk_headers.mk +include opus_headers.mk + +libopus_la_SOURCES = $(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES) +libopus_la_LDFLAGS = -no-undefined -version-info @OPUS_LT_CURRENT@:@OPUS_LT_REVISION@:@OPUS_LT_AGE@ +libopus_la_LIBADD = $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +libopus_la_LIBADD += libarmasm.la +endif + +pkginclude_HEADERS = include/opus.h include/opus_multistream.h include/opus_types.h include/opus_defines.h include/opus_projection.h + +noinst_HEADERS = $(OPUS_HEAD) $(SILK_HEAD) $(CELT_HEAD) + +if EXTRA_PROGRAMS +noinst_PROGRAMS = celt/tests/test_unit_cwrs32 \ + celt/tests/test_unit_dft \ + celt/tests/test_unit_entropy \ + celt/tests/test_unit_laplace \ + celt/tests/test_unit_mathops \ + celt/tests/test_unit_mdct \ + celt/tests/test_unit_rotation \ + celt/tests/test_unit_types \ + opus_compare \ + opus_demo \ + repacketizer_demo \ + silk/tests/test_unit_LPC_inv_pred_gain \ + tests/test_opus_api \ + tests/test_opus_decode \ + tests/test_opus_encode \ + tests/test_opus_padding \ + tests/test_opus_projection + +TESTS = celt/tests/test_unit_cwrs32 \ + celt/tests/test_unit_dft \ + celt/tests/test_unit_entropy \ + celt/tests/test_unit_laplace \ + celt/tests/test_unit_mathops \ + celt/tests/test_unit_mdct \ + celt/tests/test_unit_rotation \ + celt/tests/test_unit_types \ + silk/tests/test_unit_LPC_inv_pred_gain \ + tests/test_opus_api \ + tests/test_opus_decode \ + tests/test_opus_encode \ + tests/test_opus_padding \ + tests/test_opus_projection + +opus_demo_SOURCES = src/opus_demo.c + +opus_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +repacketizer_demo_SOURCES = src/repacketizer_demo.c + +repacketizer_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +opus_compare_SOURCES = src/opus_compare.c +opus_compare_LDADD = $(LIBM) + +tests_test_opus_api_SOURCES = tests/test_opus_api.c tests/test_opus_common.h +tests_test_opus_api_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_encode_SOURCES = tests/test_opus_encode.c tests/opus_encode_regressions.c tests/test_opus_common.h +tests_test_opus_encode_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_decode_SOURCES = tests/test_opus_decode.c tests/test_opus_common.h +tests_test_opus_decode_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_padding_SOURCES = tests/test_opus_padding.c tests/test_opus_common.h +tests_test_opus_padding_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +CELT_OBJ = $(CELT_SOURCES:.c=.lo) +SILK_OBJ = $(SILK_SOURCES:.c=.lo) +OPUS_OBJ = $(OPUS_SOURCES:.c=.lo) + +tests_test_opus_projection_SOURCES = tests/test_opus_projection.c tests/test_opus_common.h +tests_test_opus_projection_LDADD = $(OPUS_OBJ) $(SILK_OBJ) $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +tests_test_opus_projection_LDADD += libarmasm.la +endif + +silk_tests_test_unit_LPC_inv_pred_gain_SOURCES = silk/tests/test_unit_LPC_inv_pred_gain.c +silk_tests_test_unit_LPC_inv_pred_gain_LDADD = $(SILK_OBJ) $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +silk_tests_test_unit_LPC_inv_pred_gain_LDADD += libarmasm.la +endif + +celt_tests_test_unit_cwrs32_SOURCES = celt/tests/test_unit_cwrs32.c +celt_tests_test_unit_cwrs32_LDADD = $(LIBM) + +celt_tests_test_unit_dft_SOURCES = celt/tests/test_unit_dft.c +celt_tests_test_unit_dft_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_dft_LDADD += libarmasm.la +endif + +celt_tests_test_unit_entropy_SOURCES = celt/tests/test_unit_entropy.c +celt_tests_test_unit_entropy_LDADD = $(LIBM) + +celt_tests_test_unit_laplace_SOURCES = celt/tests/test_unit_laplace.c +celt_tests_test_unit_laplace_LDADD = $(LIBM) + +celt_tests_test_unit_mathops_SOURCES = celt/tests/test_unit_mathops.c +celt_tests_test_unit_mathops_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_mathops_LDADD += libarmasm.la +endif + +celt_tests_test_unit_mdct_SOURCES = celt/tests/test_unit_mdct.c +celt_tests_test_unit_mdct_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_mdct_LDADD += libarmasm.la +endif + +celt_tests_test_unit_rotation_SOURCES = celt/tests/test_unit_rotation.c +celt_tests_test_unit_rotation_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_rotation_LDADD += libarmasm.la +endif + +celt_tests_test_unit_types_SOURCES = celt/tests/test_unit_types.c +celt_tests_test_unit_types_LDADD = $(LIBM) +endif + +if CUSTOM_MODES +pkginclude_HEADERS += include/opus_custom.h +if EXTRA_PROGRAMS +noinst_PROGRAMS += opus_custom_demo +opus_custom_demo_SOURCES = celt/opus_custom_demo.c +opus_custom_demo_LDADD = libopus.la $(LIBM) +endif +endif + +EXTRA_DIST = opus.pc.in \ + opus-uninstalled.pc.in \ + opus.m4 \ + Makefile.mips \ + Makefile.unix \ + CMakeLists.txt \ + config.h.cmake.in \ + opus_config.cmake \ + opus_functions.cmake \ + opus_sources.cmake \ + OpusConfig.cmake.in \ + tests/run_vectors.sh \ + celt/arm/arm2gnu.pl \ + celt/arm/celt_pitch_xcorr_arm.s \ + win32/VS2015/opus.vcxproj \ + win32/VS2015/test_opus_encode.vcxproj.filters \ + win32/VS2015/test_opus_encode.vcxproj \ + win32/VS2015/opus_demo.vcxproj \ + win32/VS2015/test_opus_api.vcxproj.filters \ + win32/VS2015/test_opus_api.vcxproj \ + win32/VS2015/test_opus_decode.vcxproj.filters \ + win32/VS2015/opus_demo.vcxproj.filters \ + win32/VS2015/opus.vcxproj.filters \ + win32/VS2015/test_opus_decode.vcxproj \ + win32/VS2015/opus.sln \ + win32/VS2015/common.props \ + win32/genversion.bat \ + win32/config.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = opus.pc + +m4datadir = $(datadir)/aclocal +m4data_DATA = opus.m4 + +# Targets to build and install just the library without the docs +opus check-opus install-opus: export NO_DOXYGEN = 1 + +opus: all +check-opus: check +install-opus: install + + +# Or just the docs +docs: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) ) + +install-docs: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) install ) + + +# Or everything (by default) +all-local: + @[ -n "$(NO_DOXYGEN)" ] || ( cd doc && $(MAKE) $(AM_MAKEFLAGS) ) + +install-data-local: + @[ -n "$(NO_DOXYGEN)" ] || ( cd doc && $(MAKE) $(AM_MAKEFLAGS) install ) + +clean-local: + -( cd doc && $(MAKE) $(AM_MAKEFLAGS) clean ) + +uninstall-local: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) uninstall ) + + +# We check this every time make is run, with configure.ac being touched to +# trigger an update of the build system files if update_version changes the +# current PACKAGE_VERSION (or if package_version was modified manually by a +# user with either AUTO_UPDATE=no or no update_version script present - the +# latter being the normal case for tarball releases). +# +# We can't just add the package_version file to CONFIGURE_DEPENDENCIES since +# simply running autoconf will not actually regenerate configure for us when +# the content of that file changes (due to autoconf dependency checking not +# knowing about that without us creating yet another file for it to include). +# +# The MAKECMDGOALS check is a gnu-make'ism, but will degrade 'gracefully' for +# makes that don't support it. The only loss of functionality is not forcing +# an update of package_version for `make dist` if AUTO_UPDATE=no, but that is +# unlikely to be a real problem for any real user. +$(top_srcdir)/configure.ac: force + @case "$(MAKECMDGOALS)" in \ + dist-hook) exit 0 ;; \ + dist-* | dist | distcheck | distclean) _arg=release ;; \ + esac; \ + if ! $(top_srcdir)/update_version $$_arg 2> /dev/null; then \ + if [ ! -e $(top_srcdir)/package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > $(top_srcdir)/package_version; \ + fi; \ + . $(top_srcdir)/package_version || exit 1; \ + [ "$(PACKAGE_VERSION)" != "$$PACKAGE_VERSION" ] || exit 0; \ + fi; \ + touch $@ + +force: + +# Create a minimal package_version file when make dist is run. +dist-hook: + echo 'PACKAGE_VERSION="$(PACKAGE_VERSION)"' > $(top_distdir)/package_version + + +.PHONY: opus check-opus install-opus docs install-docs + +# automake doesn't do dependency tracking for asm files, that I can tell +$(CELT_SOURCES_ARM_ASM:%.s=%-gnu.S): celt/arm/armopts-gnu.S +$(CELT_SOURCES_ARM_ASM:%.s=%-gnu.S): $(top_srcdir)/celt/arm/arm2gnu.pl + +# convert ARM asm to GNU as format +%-gnu.S: $(top_srcdir)/%.s + $(top_srcdir)/celt/arm/arm2gnu.pl @ARM2GNU_PARAMS@ < $< > $@ +# For autoconf-modified sources (e.g., armopts.s) +%-gnu.S: %.s + $(top_srcdir)/celt/arm/arm2gnu.pl @ARM2GNU_PARAMS@ < $< > $@ + +OPT_UNIT_TEST_OBJ = $(celt_tests_test_unit_mathops_SOURCES:.c=.o) \ + $(celt_tests_test_unit_rotation_SOURCES:.c=.o) \ + $(celt_tests_test_unit_mdct_SOURCES:.c=.o) \ + $(celt_tests_test_unit_dft_SOURCES:.c=.o) \ + $(silk_tests_test_unit_LPC_inv_pred_gain_SOURCES:.c=.o) + +if HAVE_SSE +SSE_OBJ = $(CELT_SOURCES_SSE:.c=.lo) +$(SSE_OBJ): CFLAGS += $(OPUS_X86_SSE_CFLAGS) +endif + +if HAVE_SSE2 +SSE2_OBJ = $(CELT_SOURCES_SSE2:.c=.lo) +$(SSE2_OBJ): CFLAGS += $(OPUS_X86_SSE2_CFLAGS) +endif + +if HAVE_SSE4_1 +SSE4_1_OBJ = $(CELT_SOURCES_SSE4_1:.c=.lo) \ + $(SILK_SOURCES_SSE4_1:.c=.lo) \ + $(SILK_SOURCES_FIXED_SSE4_1:.c=.lo) +$(SSE4_1_OBJ): CFLAGS += $(OPUS_X86_SSE4_1_CFLAGS) +endif + +if HAVE_ARM_NEON_INTR +ARM_NEON_INTR_OBJ = $(CELT_SOURCES_ARM_NEON_INTR:.c=.lo) \ + $(SILK_SOURCES_ARM_NEON_INTR:.c=.lo) \ + $(SILK_SOURCES_FIXED_ARM_NEON_INTR:.c=.lo) +$(ARM_NEON_INTR_OBJ): CFLAGS += \ + $(OPUS_ARM_NEON_INTR_CFLAGS) $(NE10_CFLAGS) +endif diff --git a/native/codec/libraries/opus/Makefile.mips b/native/codec/libraries/opus/Makefile.mips new file mode 100644 index 0000000..e9bfc22 --- /dev/null +++ b/native/codec/libraries/opus/Makefile.mips @@ -0,0 +1,161 @@ +#################### COMPILE OPTIONS ####################### + +# Uncomment this for fixed-point build +FIXED_POINT=1 + +# It is strongly recommended to uncomment one of these +# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation +# USE_ALLOCA: Use alloca() for stack allocation +# If none is defined, then the fallback is a non-threadsafe global array +CFLAGS := -DUSE_ALLOCA $(CFLAGS) +#CFLAGS := -DVAR_ARRAYS $(CFLAGS) + +# These options affect performance +# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion +CFLAGS := -DHAVE_LRINTF $(CFLAGS) + +###################### END OF OPTIONS ###################### + +-include package_version + +include silk_sources.mk +include celt_sources.mk +include opus_sources.mk + +ifdef FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +EXESUFFIX = +LIBPREFIX = lib +LIBSUFFIX = .a +OBJSUFFIX = .o + +CC = $(TOOLCHAIN_PREFIX)cc$(TOOLCHAIN_SUFFIX) +AR = $(TOOLCHAIN_PREFIX)ar +RANLIB = $(TOOLCHAIN_PREFIX)ranlib +CP = $(TOOLCHAIN_PREFIX)cp + +cppflags-from-defines = $(addprefix -D,$(1)) +cppflags-from-includes = $(addprefix -I,$(1)) +ldflags-from-ldlibdirs = $(addprefix -L,$(1)) +ldlibs-from-libs = $(addprefix -l,$(1)) + +WARNINGS = -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow + +CFLAGS += -mips32r2 -mno-mips16 -std=gnu99 -O2 -g $(WARNINGS) -DENABLE_ASSERTIONS -DMIPSr1_ASM -DOPUS_BUILD -mdspr2 -march=74kc -mtune=74kc -mmt -mgp32 + +CINCLUDES = include silk celt + +ifdef FIXED_POINT +CFLAGS += -DFIXED_POINT=1 -DDISABLE_FLOAT_API +CINCLUDES += silk/fixed +else +CINCLUDES += silk/float +endif + + +LIBS = m + +LDLIBDIRS = ./ + +CFLAGS += $(call cppflags-from-defines,$(CDEFINES)) +CFLAGS += $(call cppflags-from-includes,$(CINCLUDES)) +LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS)) +LDLIBS += $(call ldlibs-from-libs,$(LIBS)) + +COMPILE.c.cmdline = $(CC) -c $(CFLAGS) -o $@ $< +LINK.o = $(CC) $(LDPREFLAGS) $(LDFLAGS) +LINK.o.cmdline = $(LINK.o) $^ $(LDLIBS) -o $@$(EXESUFFIX) + +ARCHIVE.cmdline = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@ + +%$(OBJSUFFIX):%.c + $(COMPILE.c.cmdline) + +%$(OBJSUFFIX):%.cpp + $(COMPILE.cpp.cmdline) + +# Directives + + +# Variable definitions +LIB_NAME = opus +TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX) + +SRCS_C = $(SILK_SOURCES) $(CELT_SOURCES) $(OPUS_SOURCES) + +OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C)) + +OPUSDEMO_SRCS_C = src/opus_demo.c +OPUSDEMO_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSDEMO_SRCS_C)) + +TESTOPUSAPI_SRCS_C = tests/test_opus_api.c +TESTOPUSAPI_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSAPI_SRCS_C)) + +TESTOPUSDECODE_SRCS_C = tests/test_opus_decode.c +TESTOPUSDECODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSDECODE_SRCS_C)) + +TESTOPUSENCODE_SRCS_C = tests/test_opus_encode.c tests/opus_encode_regressions.c +TESTOPUSENCODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSENCODE_SRCS_C)) + +TESTOPUSPADDING_SRCS_C = tests/test_opus_padding.c +TESTOPUSPADDING_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSPADDING_SRCS_C)) + +OPUSCOMPARE_SRCS_C = src/opus_compare.c +OPUSCOMPARE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSCOMPARE_SRCS_C)) + +TESTS := test_opus_api test_opus_decode test_opus_encode test_opus_padding + +# Rules +all: lib opus_demo opus_compare $(TESTS) + +lib: $(TARGET) + +check: all + for test in $(TESTS); do ./$$test; done + +$(TARGET): $(OBJS) + $(ARCHIVE.cmdline) + +opus_demo$(EXESUFFIX): $(OPUSDEMO_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_api$(EXESUFFIX): $(TESTOPUSAPI_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_decode$(EXESUFFIX): $(TESTOPUSDECODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_encode$(EXESUFFIX): $(TESTOPUSENCODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_padding$(EXESUFFIX): $(TESTOPUSPADDING_OBJS) $(TARGET) + $(LINK.o.cmdline) + +opus_compare$(EXESUFFIX): $(OPUSCOMPARE_OBJS) + $(LINK.o.cmdline) + +celt/celt.o: CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' +celt/celt.o: package_version + +package_version: force + @if [ -x ./update_version ]; then \ + ./update_version || true; \ + elif [ ! -e ./package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > ./package_version; \ + fi + +force: + +clean: + rm -f opus_demo$(EXESUFFIX) opus_compare$(EXESUFFIX) $(TARGET) \ + test_opus_api$(EXESUFFIX) test_opus_decode$(EXESUFFIX) \ + test_opus_encode$(EXESUFFIX) test_opus_padding$(EXESUFFIX) \ + $(OBJS) $(OPUSDEMO_OBJS) $(OPUSCOMPARE_OBJS) $(TESTOPUSAPI_OBJS) \ + $(TESTOPUSDECODE_OBJS) $(TESTOPUSENCODE_OBJS) $(TESTOPUSPADDING_OBJS) + +.PHONY: all lib clean force check diff --git a/native/codec/libraries/opus/Makefile.unix b/native/codec/libraries/opus/Makefile.unix new file mode 100644 index 0000000..90a48f0 --- /dev/null +++ b/native/codec/libraries/opus/Makefile.unix @@ -0,0 +1,159 @@ +#################### COMPILE OPTIONS ####################### + +# Uncomment this for fixed-point build +#FIXED_POINT=1 + +# It is strongly recommended to uncomment one of these +# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation +# USE_ALLOCA: Use alloca() for stack allocation +# If none is defined, then the fallback is a non-threadsafe global array +CFLAGS := -DUSE_ALLOCA $(CFLAGS) +#CFLAGS := -DVAR_ARRAYS $(CFLAGS) + +# These options affect performance +# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion +#CFLAGS := -DHAVE_LRINTF $(CFLAGS) + +###################### END OF OPTIONS ###################### + +-include package_version + +include silk_sources.mk +include celt_sources.mk +include opus_sources.mk + +ifdef FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +EXESUFFIX = +LIBPREFIX = lib +LIBSUFFIX = .a +OBJSUFFIX = .o + +CC = $(TOOLCHAIN_PREFIX)cc$(TOOLCHAIN_SUFFIX) +AR = $(TOOLCHAIN_PREFIX)ar +RANLIB = $(TOOLCHAIN_PREFIX)ranlib +CP = $(TOOLCHAIN_PREFIX)cp + +cppflags-from-defines = $(addprefix -D,$(1)) +cppflags-from-includes = $(addprefix -I,$(1)) +ldflags-from-ldlibdirs = $(addprefix -L,$(1)) +ldlibs-from-libs = $(addprefix -l,$(1)) + +WARNINGS = -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow +CFLAGS += -O2 -g $(WARNINGS) -DOPUS_BUILD +CINCLUDES = include silk celt + +ifdef FIXED_POINT +CFLAGS += -DFIXED_POINT=1 -DDISABLE_FLOAT_API +CINCLUDES += silk/fixed +else +CINCLUDES += silk/float +endif + + +LIBS = m + +LDLIBDIRS = ./ + +CFLAGS += $(call cppflags-from-defines,$(CDEFINES)) +CFLAGS += $(call cppflags-from-includes,$(CINCLUDES)) +LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS)) +LDLIBS += $(call ldlibs-from-libs,$(LIBS)) + +COMPILE.c.cmdline = $(CC) -c $(CFLAGS) -o $@ $< +LINK.o = $(CC) $(LDPREFLAGS) $(LDFLAGS) +LINK.o.cmdline = $(LINK.o) $^ $(LDLIBS) -o $@$(EXESUFFIX) + +ARCHIVE.cmdline = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@ + +%$(OBJSUFFIX):%.c + $(COMPILE.c.cmdline) + +%$(OBJSUFFIX):%.cpp + $(COMPILE.cpp.cmdline) + +# Directives + + +# Variable definitions +LIB_NAME = opus +TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX) + +SRCS_C = $(SILK_SOURCES) $(CELT_SOURCES) $(OPUS_SOURCES) + +OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C)) + +OPUSDEMO_SRCS_C = src/opus_demo.c +OPUSDEMO_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSDEMO_SRCS_C)) + +TESTOPUSAPI_SRCS_C = tests/test_opus_api.c +TESTOPUSAPI_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSAPI_SRCS_C)) + +TESTOPUSDECODE_SRCS_C = tests/test_opus_decode.c +TESTOPUSDECODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSDECODE_SRCS_C)) + +TESTOPUSENCODE_SRCS_C = tests/test_opus_encode.c tests/opus_encode_regressions.c +TESTOPUSENCODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSENCODE_SRCS_C)) + +TESTOPUSPADDING_SRCS_C = tests/test_opus_padding.c +TESTOPUSPADDING_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSPADDING_SRCS_C)) + +OPUSCOMPARE_SRCS_C = src/opus_compare.c +OPUSCOMPARE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSCOMPARE_SRCS_C)) + +TESTS := test_opus_api test_opus_decode test_opus_encode test_opus_padding + +# Rules +all: lib opus_demo opus_compare $(TESTS) + +lib: $(TARGET) + +check: all + for test in $(TESTS); do ./$$test; done + +$(TARGET): $(OBJS) + $(ARCHIVE.cmdline) + +opus_demo$(EXESUFFIX): $(OPUSDEMO_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_api$(EXESUFFIX): $(TESTOPUSAPI_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_decode$(EXESUFFIX): $(TESTOPUSDECODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_encode$(EXESUFFIX): $(TESTOPUSENCODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_padding$(EXESUFFIX): $(TESTOPUSPADDING_OBJS) $(TARGET) + $(LINK.o.cmdline) + +opus_compare$(EXESUFFIX): $(OPUSCOMPARE_OBJS) + $(LINK.o.cmdline) + +celt/celt.o: CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' +celt/celt.o: package_version + +package_version: force + @if [ -x ./update_version ]; then \ + ./update_version || true; \ + elif [ ! -e ./package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > ./package_version; \ + fi + +force: + +clean: + rm -f opus_demo$(EXESUFFIX) opus_compare$(EXESUFFIX) $(TARGET) \ + test_opus_api$(EXESUFFIX) test_opus_decode$(EXESUFFIX) \ + test_opus_encode$(EXESUFFIX) test_opus_padding$(EXESUFFIX) \ + $(OBJS) $(OPUSDEMO_OBJS) $(OPUSCOMPARE_OBJS) $(TESTOPUSAPI_OBJS) \ + $(TESTOPUSDECODE_OBJS) $(TESTOPUSENCODE_OBJS) $(TESTOPUSPADDING_OBJS) + +.PHONY: all lib clean force check diff --git a/native/codec/libraries/opus/NEWS b/native/codec/libraries/opus/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/native/codec/libraries/opus/OpusConfig.cmake.in b/native/codec/libraries/opus/OpusConfig.cmake.in new file mode 100644 index 0000000..1577174 --- /dev/null +++ b/native/codec/libraries/opus/OpusConfig.cmake.in @@ -0,0 +1,19 @@ +set(OPUS_VERSION @PROJECT_VERSION@) +set(OPUS_VERSION_STRING @PROJECT_VERSION@) +set(OPUS_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) +set(OPUS_VERSION_MINOR @PROJECT_VERSION_MINOR@) +set(OPUS_VERSION_PATCH @PROJECT_VERSION_PATCH@) + +@PACKAGE_INIT@ + +set_and_check(OPUS_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set_and_check(OPUS_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") + +include(${CMAKE_CURRENT_LIST_DIR}/OpusTargets.cmake) + +set(OPUS_LIBRARY Opus::opus) +set(OPUS_LIBRARIES Opus::opus) + +check_required_components(Opus) + +set(OPUS_FOUND 1) diff --git a/native/codec/libraries/opus/README b/native/codec/libraries/opus/README new file mode 100644 index 0000000..27fddf9 --- /dev/null +++ b/native/codec/libraries/opus/README @@ -0,0 +1,161 @@ +== Opus audio codec == + +Opus is a codec for interactive speech and audio transmission over the Internet. + + Opus can handle a wide range of interactive audio applications, including +Voice over IP, videoconferencing, in-game chat, and even remote live music +performances. It can scale from low bit-rate narrowband speech to very high +quality stereo music. + + Opus, when coupled with an appropriate container format, is also suitable +for non-realtime stored-file applications such as music distribution, game +soundtracks, portable music players, jukeboxes, and other applications that +have historically used high latency formats such as MP3, AAC, or Vorbis. + + Opus is specified by IETF RFC 6716: + https://tools.ietf.org/html/rfc6716 + + The Opus format and this implementation of it are subject to the royalty- +free patent and copyright licenses specified in the file COPYING. + +This package implements a shared library for encoding and decoding raw Opus +bitstreams. Raw Opus bitstreams should be used over RTP according to + https://tools.ietf.org/html/rfc7587 + +The package also includes a number of test tools used for testing the +correct operation of the library. The bitstreams read/written by these +tools should not be used for Opus file distribution: They include +additional debugging data and cannot support seeking. + +Opus stored in files should use the Ogg encapsulation for Opus which is +described at: + https://tools.ietf.org/html/rfc7845 + +An opus-tools package is available which provides encoding and decoding of +Ogg encapsulated Opus files and includes a number of useful features. + +Opus-tools can be found at: + https://git.xiph.org/?p=opus-tools.git +or on the main Opus website: + https://opus-codec.org/ + +== Compiling libopus == + +To build from a distribution tarball, you only need to do the following: + + % ./configure + % make + +To build from the git repository, the following steps are necessary: + +0) Set up a development environment: + +On an Ubuntu or Debian family Linux distribution: + + % sudo apt-get install git autoconf automake libtool gcc make + +On a Fedora/Redhat based Linux: + + % sudo dnf install git autoconf automake libtool gcc make + +Or for older Redhat/Centos Linux releases: + + % sudo yum install git autoconf automake libtool gcc make + +On Apple macOS, install Xcode and brew.sh, then in the Terminal enter: + + % brew install autoconf automake libtool + +1) Clone the repository: + + % git clone https://git.xiph.org/opus.git + % cd opus + +2) Compiling the source + + % ./autogen.sh + % ./configure + % make + +3) Install the codec libraries (optional) + + % sudo make install + +Once you have compiled the codec, there will be a opus_demo executable +in the top directory. + +Usage: opus_demo [-e] + [options] + opus_demo -d [options] + + +mode: voip | audio | restricted-lowdelay +options: + -e : only runs the encoder (output the bit-stream) + -d : only runs the decoder (reads the bit-stream as input) + -cbr : enable constant bitrate; default: variable bitrate + -cvbr : enable constrained variable bitrate; default: + unconstrained + -bandwidth + : audio bandwidth (from narrowband to fullband); + default: sampling rate + -framesize <2.5|5|10|20|40|60> + : frame size in ms; default: 20 + -max_payload + : maximum payload size in bytes, default: 1024 + -complexity + : complexity, 0 (lowest) ... 10 (highest); default: 10 + -inbandfec : enable SILK inband FEC + -forcemono : force mono encoding, even for stereo input + -dtx : enable SILK DTX + -loss : simulate packet loss, in percent (0-100); default: 0 + +input and output are little-endian signed 16-bit PCM files or opus +bitstreams with simple opus_demo proprietary framing. + +== Testing == + +This package includes a collection of automated unit and system tests +which SHOULD be run after compiling the package especially the first +time it is run on a new platform. + +To run the integrated tests: + + % make check + +There is also collection of standard test vectors which are not +included in this package for size reasons but can be obtained from: +https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz + +To run compare the code to these test vectors: + + % curl -OL https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz + % tar -zxf opus_testvectors-rfc8251.tar.gz + % ./tests/run_vectors.sh ./ opus_newvectors 48000 + +== Portability notes == + +This implementation uses floating-point by default but can be compiled to +use only fixed-point arithmetic by setting --enable-fixed-point (if using +autoconf) or by defining the FIXED_POINT macro (if building manually). +The fixed point implementation has somewhat lower audio quality and is +slower on platforms with fast FPUs, it is normally only used in embedded +environments. + +The implementation can be compiled with either a C89 or a C99 compiler. +While it does not rely on any _undefined behavior_ as defined by C89 or +C99, it relies on common _implementation-defined behavior_ for two's +complement architectures: + +o Right shifts of negative values are consistent with two's + complement arithmetic, so that a>>b is equivalent to + floor(a/(2^b)), + +o For conversion to a signed integer of N bits, the value is reduced + modulo 2^N to be within range of the type, + +o The result of integer division of a negative value is truncated + towards zero, and + +o The compiler provides a 64-bit integer type (a C99 requirement + which is supported by most C89 compilers). diff --git a/native/codec/libraries/opus/README.draft b/native/codec/libraries/opus/README.draft new file mode 100644 index 0000000..8d8e24d --- /dev/null +++ b/native/codec/libraries/opus/README.draft @@ -0,0 +1,54 @@ +To build this source code, simply type: + +% make + +If this does not work, or if you want to change the default configuration +(e.g., to compile for a fixed-point architecture), simply edit the options +in the Makefile. + +An up-to-date implementation conforming to this standard is available in a +Git repository at https://git.xiph.org/opus.git or on a website at: +https://opus-codec.org/ +However, although that implementation is expected to remain conformant +with the standard, it is the code in this RFC that shall remain normative. +To build from the git repository instead of using this RFC, follow these +steps: + +1) Clone the repository (latest implementation of this standard at the time +of publication) + +% git clone https://git.xiph.org/opus.git +% cd opus + +2) Compile + +% ./autogen.sh +% ./configure +% make + +Once you have compiled the codec, there will be a opus_demo executable in +the top directory. + +Usage: opus_demo [-e] + [options] + opus_demo -d [options] + + +mode: voip | audio | restricted-lowdelay +options: +-e : only runs the encoder (output the bit-stream) +-d : only runs the decoder (reads the bit-stream as input) +-cbr : enable constant bitrate; default: variable bitrate +-cvbr : enable constrained variable bitrate; default: unconstrained +-bandwidth : audio bandwidth (from narrowband to fullband); + default: sampling rate +-framesize <2.5|5|10|20|40|60> : frame size in ms; default: 20 +-max_payload : maximum payload size in bytes, default: 1024 +-complexity : complexity, 0 (lowest) ... 10 (highest); default: 10 +-inbandfec : enable SILK inband FEC +-forcemono : force mono encoding, even for stereo input +-dtx : enable SILK DTX +-loss : simulate packet loss, in percent (0-100); default: 0 + +input and output are little endian signed 16-bit PCM files or opus bitstreams +with simple opus_demo proprietary framing. diff --git a/native/codec/libraries/opus/autogen.sh b/native/codec/libraries/opus/autogen.sh new file mode 100755 index 0000000..380d1f3 --- /dev/null +++ b/native/codec/libraries/opus/autogen.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Copyright (c) 2010-2015 Xiph.Org Foundation and contributors. +# Use of this source code is governed by a BSD-style license that can be +# found in the COPYING file. + +# Run this to set up the build system: configure, makefiles, etc. +set -e + +srcdir=`dirname $0` +test -n "$srcdir" && cd "$srcdir" + +echo "Updating build configuration files, please wait...." + +autoreconf -isf diff --git a/native/codec/libraries/opus/celt/_kiss_fft_guts.h b/native/codec/libraries/opus/celt/_kiss_fft_guts.h new file mode 100644 index 0000000..17392b3 --- /dev/null +++ b/native/codec/libraries/opus/celt/_kiss_fft_guts.h @@ -0,0 +1,182 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +#ifndef KISS_FFT_GUTS_H +#define KISS_FFT_GUTS_H + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" + + +#define SAMP_MAX 2147483647 +#define TWID_MAX 32767 +#define TRIG_UPSCALE 1 + +#define SAMP_MIN -SAMP_MAX + + +# define S_MUL(a,b) MULT16_32_Q15(b, a) + +# define C_MUL(m,a,b) \ + do{ (m).r = SUB32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = ADD32_ovflw(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0) + +# define C_MULC(m,a,b) \ + do{ (m).r = ADD32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = SUB32_ovflw(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = S_MUL( (c).r , s ) ;\ + (c).i = S_MUL( (c).i , s ) ; }while(0) + +# define DIVSCALAR(x,k) \ + (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +#define C_ADD( res, a,b)\ + do {(res).r=ADD32_ovflw((a).r,(b).r); (res).i=ADD32_ovflw((a).i,(b).i); \ + }while(0) +#define C_SUB( res, a,b)\ + do {(res).r=SUB32_ovflw((a).r,(b).r); (res).i=SUB32_ovflw((a).i,(b).i); \ + }while(0) +#define C_ADDTO( res , a)\ + do {(res).r = ADD32_ovflw((res).r, (a).r); (res).i = ADD32_ovflw((res).i,(a).i);\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {(res).r = ADD32_ovflw((res).r,(a).r); (res).i = SUB32_ovflw((res).i,(a).i); \ + }while(0) + +#if defined(OPUS_ARM_INLINE_ASM) +#include "arm/kiss_fft_armv4.h" +#endif + +#if defined(OPUS_ARM_INLINE_EDSP) +#include "arm/kiss_fft_armv5e.h" +#endif +#if defined(MIPSr1_ASM) +#include "mips/kiss_fft_mipsr1.h" +#endif + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +#define C_MULC(m,a,b) \ + do{ (m).r = (a).r*(b).r + (a).i*(b).i;\ + (m).i = (a).i*(b).r - (a).r*(b).i; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#ifndef C_ADD +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) +#endif /* C_ADD defined */ + +#ifdef FIXED_POINT +/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/ +# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5f)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5f) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\ + (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\ +}while(0) + +#endif /* KISS_FFT_GUTS_H */ diff --git a/native/codec/libraries/opus/celt/arch.h b/native/codec/libraries/opus/celt/arch.h new file mode 100644 index 0000000..08b07db --- /dev/null +++ b/native/codec/libraries/opus/celt/arch.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2003-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions for CELT +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#include "opus_types.h" +#include "opus_defines.h" + +# if !defined(__GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define __GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define __GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if OPUS_GNUC_PREREQ(3, 0) +#define opus_likely(x) (__builtin_expect(!!(x), 1)) +#define opus_unlikely(x) (__builtin_expect(!!(x), 0)) +#else +#define opus_likely(x) (!!(x)) +#define opus_unlikely(x) (!!(x)) +#endif + +#define CELT_SIG_SCALE 32768.f + +#define CELT_FATAL(str) celt_fatal(str, __FILE__, __LINE__); + +#if defined(ENABLE_ASSERTIONS) || defined(ENABLE_HARDENING) +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void celt_fatal(const char *str, const char *file, int line); + +#if defined(CELT_C) && !defined(OVERRIDE_celt_fatal) +#include +#include +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void celt_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +#endif + +#define celt_assert(cond) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond);}} +#define celt_assert2(cond, message) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond "\n" message);}} +#define MUST_SUCCEED(call) celt_assert((call) == OPUS_OK) +#else +#define celt_assert(cond) +#define celt_assert2(cond, message) +#define MUST_SUCCEED(call) do {if((call) != OPUS_OK) {RESTORE_STACK; return OPUS_INTERNAL_ERROR;} } while (0) +#endif + +#if defined(ENABLE_ASSERTIONS) +#define celt_sig_assert(cond) {if (!(cond)) {CELT_FATAL("signal assertion failed: " #cond);}} +#else +#define celt_sig_assert(cond) +#endif + +#define IMUL32(a,b) ((a)*(b)) + +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ +#define UADD32(a,b) ((a)+(b)) +#define USUB32(a,b) ((a)-(b)) + +/* Set this if opus_int64 is a native type of the CPU. */ +/* Assume that all LP64 architectures have fast 64-bit types; also x86_64 + (which can be ILP32 for x32) and Win64 (which is LLP64). */ +#if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64) +#define OPUS_FAST_INT64 1 +#else +#define OPUS_FAST_INT64 0 +#endif + +#define PRINT_MIPS(file) + +#ifdef FIXED_POINT + +typedef opus_int16 opus_val16; +typedef opus_int32 opus_val32; +typedef opus_int64 opus_val64; + +typedef opus_val32 celt_sig; +typedef opus_val16 celt_norm; +typedef opus_val32 celt_ener; + +#define celt_isnan(x) 0 + +#define Q15ONE 32767 + +#define SIG_SHIFT 12 +/* Safe saturation value for 32-bit signals. Should be less than + 2^31*(1-0.85) to avoid blowing up on DC at deemphasis.*/ +#define SIG_SAT (300000000) + +#define NORM_SCALING 16384 + +#define DB_SHIFT 10 + +#define EPSILON 1 +#define VERY_SMALL 0 +#define VERY_LARGE16 ((opus_val16)32767) +#define Q15_ONE ((opus_val16)32767) + +#define SCALEIN(a) (a) +#define SCALEOUT(a) (a) + +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) + +static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { + return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; +} + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR +#include "arm/fixed_arm64.h" +#elif defined (OPUS_ARM_INLINE_EDSP) +#include "arm/fixed_armv5e.h" +#elif defined (OPUS_ARM_INLINE_ASM) +#include "arm/fixed_armv4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#elif defined (TI_C5X_ASM) +#include "fixed_c5x.h" +#elif defined (TI_C6X_ASM) +#include "fixed_c6x.h" +#endif + +#endif + +#else /* FIXED_POINT */ + +typedef float opus_val16; +typedef float opus_val32; +typedef float opus_val64; + +typedef float celt_sig; +typedef float celt_norm; +typedef float celt_ener; + +#ifdef FLOAT_APPROX +/* This code should reliably detect NaN/inf even when -ffast-math is used. + Assumes IEEE 754 format. */ +static OPUS_INLINE int celt_isnan(float x) +{ + union {float f; opus_uint32 i;} in; + in.f = x; + return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0; +} +#else +#ifdef __FAST_MATH__ +#error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input +#endif +#define celt_isnan(x) ((x)!=(x)) +#endif + +#define Q15ONE 1.0f + +#define NORM_SCALING 1.f + +#define EPSILON 1e-15f +#define VERY_SMALL 1e-30f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((opus_val16)1.f) + +/* This appears to be the same speed as C99's fabsf() but it's more portable. */ +#define ABS16(x) ((float)fabs(x)) +#define ABS32(x) ((float)fabs(x)) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define NEG32_ovflw(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) +#define SATURATE16(x) (x) + +#define ROUND16(a,shift) (a) +#define SROUND16(a,shift) (a) +#define HALF16(x) (.5f*(x)) +#define HALF32(x) (.5f*(x)) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define ADD32_ovflw(a,b) ((a)+(b)) +#define SUB32_ovflw(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b)) +#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b)) + +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_Q16(a,b) ((a)*(b)) + +#define MULT32_32_Q31(a,b) ((a)*(b)) + +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q16(c,a,b) ((c)+(a)*(b)) + +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q11(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) +#define MULT16_32_P16(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b)) +#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b)) + +#define SCALEIN(a) ((a)*CELT_SIG_SCALE) +#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) + +#define SIG2WORD16(x) (x) + +#endif /* !FIXED_POINT */ + +#ifndef GLOBAL_STACK_SIZE +#ifdef FIXED_POINT +#define GLOBAL_STACK_SIZE 120000 +#else +#define GLOBAL_STACK_SIZE 120000 +#endif +#endif + +#endif /* ARCH_H */ diff --git a/native/codec/libraries/opus/celt/arm/arm2gnu.pl b/native/codec/libraries/opus/celt/arm/arm2gnu.pl new file mode 100755 index 0000000..a2895f7 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/arm2gnu.pl @@ -0,0 +1,353 @@ +#!/usr/bin/perl +# Copyright (C) 2002-2013 Xiph.org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +my $bigend; # little/big endian +my $nxstack; +my $apple = 0; +my $symprefix = ""; + +$nxstack = 0; + +eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}' + if $running_under_some_shell; + +while ($ARGV[0] =~ /^-/) { + $_ = shift; + last if /^--$/; + if (/^-n$/) { + $nflag++; + next; + } + if (/^--apple$/) { + $apple = 1; + $symprefix = "_"; + next; + } + die "I don't recognize this switch: $_\\n"; +} +$printit++ unless $nflag; + +$\ = "\n"; # automatically add newline on print +$n=0; + +$thumb = 0; # ARM mode by default, not Thumb. +@proc_stack = (); + +printf (" .syntax unified\n"); + +LINE: +while (<>) { + + # For ADRLs we need to add a new line after the substituted one. + $addPadding = 0; + + # First, we do not dare to touch *anything* inside double quotes, do we? + # Second, if you want a dollar character in the string, + # insert two of them -- that's how ARM C and assembler treat strings. + s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1: .ascii \"/ && do { s/\$\$/\$/g; next }; + s/\bDCB\b[ \t]*\"/.ascii \"/ && do { s/\$\$/\$/g; next }; + s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/ && do { s/\$\$/\$/g; next }; + # If there's nothing on a line but a comment, don't try to apply any further + # substitutions (this is a cheap hack to avoid mucking up the license header) + s/^([ \t]*);/$1@/ && do { s/\$\$/\$/g; next }; + # If substituted -- leave immediately ! + + s/@/,:/; + s/;/@/; + while ( /@.*'/ ) { + s/(@.*)'/$1/g; + } + s/\{FALSE\}/0/g; + s/\{TRUE\}/1/g; + s/\{(\w\w\w\w+)\}/$1/g; + s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/; + s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/; + s/\bIMPORT\b/.extern/; + s/\bEXPORT\b\s*/.global $symprefix/; + s/^(\s+)\[/$1IF/; + s/^(\s+)\|/$1ELSE/; + s/^(\s+)\]/$1ENDIF/; + s/IF *:DEF:/ .ifdef/; + s/IF *:LNOT: *:DEF:/ .ifndef/; + s/ELSE/ .else/; + s/ENDIF/ .endif/; + + if( /\bIF\b/ ) { + s/\bIF\b/ .if/; + s/=/==/; + } + if ( $n == 2) { + s/\$/\\/g; + } + if ($n == 1) { + s/\$//g; + s/label//g; + $n = 2; + } + if ( /MACRO/ ) { + s/MACRO *\n/.macro/; + $n=1; + } + if ( /\bMEND\b/ ) { + s/\bMEND\b/.endm/; + $n=0; + } + + # ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there. + # + if ( /\bAREA\b/ ) { + my $align; + $align = "2"; + if ( /ALIGN=(\d+)/ ) { + $align = $1; + } + if ( /CODE/ ) { + $nxstack = 1; + } + s/^(.+)CODE(.+)READONLY(.*)/ .text/; + s/^(.+)DATA(.+)READONLY(.*)/ .section .rdata/; + s/^(.+)\|\|\.data\|\|(.+)/ .data/; + s/^(.+)\|\|\.bss\|\|(.+)/ .bss/; + s/$/; .p2align $align/; + # Enable NEON instructions but don't produce a binary that requires + # ARMv7. RVCT does not have equivalent directives, so we just do this + # for all CODE areas. + if ( /.text/ ) { + # Separating .arch, .fpu, etc., by semicolons does not work (gas + # thinks the semicolon is part of the arch name, even when there's + # whitespace separating them). Sadly this means our line numbers + # won't match the original source file (we could use the .line + # directive, which is documented to be obsolete, but then gdb will + # show the wrong line in the translated source file). + s/$/; .arch armv7-a\n .fpu neon\n .object_arch armv4t/ unless ($apple); + } + } + + s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/; # ||.constdata$3|| + s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/; # ||.bss$2|| + s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/; # ||.data$2|| + s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/; + s/^(\s+)\%(\s)/ .space $1/; + + s/\|(.+)\.(\d+)\|/\.$1_$2/; # |L80.123| -> .L80_123 + s/\bCODE32\b/.code 32/ && do {$thumb = 0}; + s/\bCODE16\b/.code 16/ && do {$thumb = 1}; + if (/\bPROC\b/) + { + my $prefix; + my $proc; + /^([A-Za-z_\.]\w+)\b/; + $proc = $1; + $prefix = ""; + if ($proc) + { + $prefix = $prefix.sprintf("\t.type\t%s, %%function", $proc) unless ($apple); + # Make sure we $prefix isn't empty here (for the $apple case). + # We handle mangling the label here, make sure it doesn't match + # the label handling below (if $prefix would be empty). + $prefix = $prefix."; "; + push(@proc_stack, $proc); + s/^[A-Za-z_\.]\w+/$symprefix$&:/; + } + $prefix = $prefix."\t.thumb_func; " if ($thumb); + s/\bPROC\b/@ $&/; + $_ = $prefix.$_; + } + s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/; + s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/; + if (/\bENDP\b/) + { + my $proc; + s/\bENDP\b/@ $&/; + $proc = pop(@proc_stack); + $_ = "\t.size $proc, .-$proc".$_ if ($proc && !$apple); + } + s/\bSUBT\b/@ $&/; + s/\bDATA\b/@ $&/; # DATA directive is deprecated -- Asm guide, p.7-25 + s/\bKEEP\b/@ $&/; + s/\bEXPORTAS\b/@ $&/; + s/\|\|(.)+\bEQU\b/@ $&/; + s/\|\|([\w\$]+)\|\|/$1/; + s/\bENTRY\b/@ $&/; + s/\bASSERT\b/@ $&/; + s/\bGBLL\b/@ $&/; + s/\bGBLA\b/@ $&/; + s/^\W+OPT\b/@ $&/; + s/:OR:/|/g; + s/:SHL:/<>/g; + s/:AND:/&/g; + s/:LAND:/&&/g; + s/CPSR/cpsr/; + s/SPSR/spsr/; + s/ALIGN$/.balign 4/; + s/ALIGN\s+([0-9x]+)$/.balign $1/; + s/psr_cxsf/psr_all/; + s/LTORG/.ltorg/; + s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/; + + # {PC} + 0xdeadfeed --> . + 0xdeadfeed + s/\{PC\} \+/ \. +/; + + # Single hex constant on the line ! + # + # >>> NOTE <<< + # Double-precision floats in gcc are always mixed-endian, which means + # bytes in two words are little-endian, but words are big-endian. + # So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address + # and 0xfeed0000 at high address. + # + s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/; + # Only decimal constants on the line, no hex ! + s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/; + + # Single hex constant on the line ! +# s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/; + # Only decimal constants on the line, no hex ! +# s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/; + s/\bDCFS[ \t]+0x/.word 0x/; + s/\bDCFS\b/.float/; + + s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/; + s/\bDCD\b/.word/; + s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/; + s/\bDCW\b/.short/; + s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/; + s/\bDCB\b/.byte/; + s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/; + s/^[A-Za-z_\.]\w+/$&:/; + s/^(\d+)/$1:/; + s/\%(\d+)/$1b_or_f/; + s/\%[Bb](\d+)/$1b/; + s/\%[Ff](\d+)/$1f/; + s/\%[Ff][Tt](\d+)/$1f/; + s/&([\dA-Fa-f]+)/0x$1/; + if ( /\b2_[01]+\b/ ) { + s/\b2_([01]+)\b/conv$1&&&&/g; + while ( /[01][01][01][01]&&&&/ ) { + s/0000&&&&/&&&&0/g; + s/0001&&&&/&&&&1/g; + s/0010&&&&/&&&&2/g; + s/0011&&&&/&&&&3/g; + s/0100&&&&/&&&&4/g; + s/0101&&&&/&&&&5/g; + s/0110&&&&/&&&&6/g; + s/0111&&&&/&&&&7/g; + s/1000&&&&/&&&&8/g; + s/1001&&&&/&&&&9/g; + s/1010&&&&/&&&&A/g; + s/1011&&&&/&&&&B/g; + s/1100&&&&/&&&&C/g; + s/1101&&&&/&&&&D/g; + s/1110&&&&/&&&&E/g; + s/1111&&&&/&&&&F/g; + } + s/000&&&&/&&&&0/g; + s/001&&&&/&&&&1/g; + s/010&&&&/&&&&2/g; + s/011&&&&/&&&&3/g; + s/100&&&&/&&&&4/g; + s/101&&&&/&&&&5/g; + s/110&&&&/&&&&6/g; + s/111&&&&/&&&&7/g; + s/00&&&&/&&&&0/g; + s/01&&&&/&&&&1/g; + s/10&&&&/&&&&2/g; + s/11&&&&/&&&&3/g; + s/0&&&&/&&&&0/g; + s/1&&&&/&&&&1/g; + s/conv&&&&/0x/g; + } + + if ( /commandline/) + { + if( /-bigend/) + { + $bigend=1; + } + } + + if ( /\bDCDU\b/ ) + { + my $cmd=$_; + my $value; + my $prefix; + my $w1; + my $w2; + my $w3; + my $w4; + + s/\s+DCDU\b/@ $&/; + + $cmd =~ /\bDCDU\b\s+0x(\d+)/; + $value = $1; + $value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/; + $w1 = $1; + $w2 = $2; + $w3 = $3; + $w4 = $4; + + if( $bigend ne "") + { + # big endian + $prefix = "\t.byte\t0x".$w1.";". + "\t.byte\t0x".$w2.";". + "\t.byte\t0x".$w3.";". + "\t.byte\t0x".$w4."; "; + } + else + { + # little endian + $prefix = "\t.byte\t0x".$w4.";". + "\t.byte\t0x".$w3.";". + "\t.byte\t0x".$w2.";". + "\t.byte\t0x".$w1."; "; + } + $_=$prefix.$_; + } + + if ( /\badrl\b/i ) + { + s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i; + $addPadding = 1; + } + s/\bEND\b/@ END/; +} continue { + printf ("%s", $_) if $printit; + if ($addPadding != 0) + { + printf (" mov r0,r0\n"); + $addPadding = 0; + } +} +#If we had a code section, mark that this object doesn't need an executable +# stack. +if ($nxstack && !$apple) { + printf (" .section\t.note.GNU-stack,\"\",\%\%progbits\n"); +} diff --git a/native/codec/libraries/opus/celt/arm/arm_celt_map.c b/native/codec/libraries/opus/celt/arm/arm_celt_map.c new file mode 100644 index 0000000..ca988b6 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/arm_celt_map.c @@ -0,0 +1,160 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pitch.h" +#include "kiss_fft.h" +#include "mdct.h" + +#if defined(OPUS_HAVE_RTCD) + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) +opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y, int N) = { + celt_inner_prod_c, /* ARMv4 */ + celt_inner_prod_c, /* EDSP */ + celt_inner_prod_c, /* Media */ + celt_inner_prod_neon /* NEON */ +}; + +void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) = { + dual_inner_prod_c, /* ARMv4 */ + dual_inner_prod_c, /* EDSP */ + dual_inner_prod_c, /* Media */ + dual_inner_prod_neon /* NEON */ +}; +# endif + +# if defined(FIXED_POINT) +# if ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \ + (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \ + (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP))) +opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int) = { + celt_pitch_xcorr_c, /* ARMv4 */ + MAY_HAVE_EDSP(celt_pitch_xcorr), /* EDSP */ + MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */ + MAY_HAVE_NEON(celt_pitch_xcorr) /* NEON */ +}; + +# endif +# else /* !FIXED_POINT */ +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) +void (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int) = { + celt_pitch_xcorr_c, /* ARMv4 */ + celt_pitch_xcorr_c, /* EDSP */ + celt_pitch_xcorr_c, /* Media */ + celt_pitch_xcorr_float_neon /* Neon */ +}; +# endif +# endif /* FIXED_POINT */ + +#if defined(FIXED_POINT) && defined(OPUS_HAVE_RTCD) && \ + defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) + +void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len +) = { + xcorr_kernel_c, /* ARMv4 */ + xcorr_kernel_c, /* EDSP */ + xcorr_kernel_c, /* Media */ + xcorr_kernel_neon_fixed, /* Neon */ +}; + +#endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# if defined(HAVE_ARM_NE10) +# if defined(CUSTOM_MODES) +int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = { + opus_fft_alloc_arch_c, /* ARMv4 */ + opus_fft_alloc_arch_c, /* EDSP */ + opus_fft_alloc_arch_c, /* Media */ + opus_fft_alloc_arm_neon /* Neon with NE10 library support */ +}; + +void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = { + opus_fft_free_arch_c, /* ARMv4 */ + opus_fft_free_arch_c, /* EDSP */ + opus_fft_free_arch_c, /* Media */ + opus_fft_free_arm_neon /* Neon with NE10 */ +}; +# endif /* CUSTOM_MODES */ + +void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) = { + opus_fft_c, /* ARMv4 */ + opus_fft_c, /* EDSP */ + opus_fft_c, /* Media */ + opus_fft_neon /* Neon with NE10 */ +}; + +void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) = { + opus_ifft_c, /* ARMv4 */ + opus_ifft_c, /* EDSP */ + opus_ifft_c, /* Media */ + opus_ifft_neon /* Neon with NE10 */ +}; + +void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, + int stride, int arch) = { + clt_mdct_forward_c, /* ARMv4 */ + clt_mdct_forward_c, /* EDSP */ + clt_mdct_forward_c, /* Media */ + clt_mdct_forward_neon /* Neon with NE10 */ +}; + +void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, + int stride, int arch) = { + clt_mdct_backward_c, /* ARMv4 */ + clt_mdct_backward_c, /* EDSP */ + clt_mdct_backward_c, /* Media */ + clt_mdct_backward_neon /* Neon with NE10 */ +}; + +# endif /* HAVE_ARM_NE10 */ +# endif /* OPUS_ARM_MAY_HAVE_NEON_INTR */ + +#endif /* OPUS_HAVE_RTCD */ diff --git a/native/codec/libraries/opus/celt/arm/armcpu.c b/native/codec/libraries/opus/celt/arm/armcpu.c new file mode 100644 index 0000000..694a63b --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/armcpu.c @@ -0,0 +1,185 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Original code from libtheora modified to suit to Opus */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef OPUS_HAVE_RTCD + +#include "armcpu.h" +#include "cpu_support.h" +#include "os_support.h" +#include "opus_types.h" +#include "arch.h" + +#define OPUS_CPU_ARM_V4_FLAG (1< + +static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){ + opus_uint32 flags; + flags=0; + /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit + * instructions via their assembled hex code. + * All of these instructions should be essentially nops. */ +# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*PLD [r13]*/ + __emit(0xF5DDF000); + flags|=OPUS_CPU_ARM_EDSP_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*SHADD8 r3,r3,r3*/ + __emit(0xE6333F93); + flags|=OPUS_CPU_ARM_MEDIA_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*VORR q0,q0,q0*/ + __emit(0xF2200150); + flags|=OPUS_CPU_ARM_NEON_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# endif +# endif +# endif + return flags; +} + +#elif defined(__linux__) +/* Linux based */ +opus_uint32 opus_cpu_capabilities(void) +{ + opus_uint32 flags = 0; + FILE *cpuinfo; + + /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on + * Android */ + cpuinfo = fopen("/proc/cpuinfo", "r"); + + if(cpuinfo != NULL) + { + /* 512 should be enough for anybody (it's even enough for all the flags that + * x86 has accumulated... so far). */ + char buf[512]; + + while(fgets(buf, 512, cpuinfo) != NULL) + { +# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + /* Search for edsp and neon flag */ + if(memcmp(buf, "Features", 8) == 0) + { + char *p; + p = strstr(buf, " edsp"); + if(p != NULL && (p[5] == ' ' || p[5] == '\n')) + flags |= OPUS_CPU_ARM_EDSP_FLAG; + +# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + p = strstr(buf, " neon"); + if(p != NULL && (p[5] == ' ' || p[5] == '\n')) + flags |= OPUS_CPU_ARM_NEON_FLAG; +# endif + } +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + /* Search for media capabilities (>= ARMv6) */ + if(memcmp(buf, "CPU architecture:", 17) == 0) + { + int version; + version = atoi(buf+17); + + if(version >= 6) + flags |= OPUS_CPU_ARM_MEDIA_FLAG; + } +# endif + } + + fclose(cpuinfo); + } + return flags; +} +#else +/* The feature registers which can tell us what the processor supports are + * accessible in priveleged modes only, so we can't have a general user-space + * detection method like on x86.*/ +# error "Configured to use ARM asm but no CPU detection method available for " \ + "your platform. Reconfigure with --disable-rtcd (or send patches)." +#endif + +int opus_select_arch(void) +{ + opus_uint32 flags = opus_cpu_capabilities(); + int arch = 0; + + if(!(flags & OPUS_CPU_ARM_EDSP_FLAG)) { + /* Asserts ensure arch values are sequential */ + celt_assert(arch == OPUS_ARCH_ARM_V4); + return arch; + } + arch++; + + if(!(flags & OPUS_CPU_ARM_MEDIA_FLAG)) { + celt_assert(arch == OPUS_ARCH_ARM_EDSP); + return arch; + } + arch++; + + if(!(flags & OPUS_CPU_ARM_NEON_FLAG)) { + celt_assert(arch == OPUS_ARCH_ARM_MEDIA); + return arch; + } + arch++; + + celt_assert(arch == OPUS_ARCH_ARM_NEON); + return arch; +} + +#endif diff --git a/native/codec/libraries/opus/celt/arm/armcpu.h b/native/codec/libraries/opus/celt/arm/armcpu.h new file mode 100644 index 0000000..820262f --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/armcpu.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(ARMCPU_H) +# define ARMCPU_H + +# if defined(OPUS_ARM_MAY_HAVE_EDSP) +# define MAY_HAVE_EDSP(name) name ## _edsp +# else +# define MAY_HAVE_EDSP(name) name ## _c +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) +# define MAY_HAVE_MEDIA(name) name ## _media +# else +# define MAY_HAVE_MEDIA(name) MAY_HAVE_EDSP(name) +# endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON) +# define MAY_HAVE_NEON(name) name ## _neon +# else +# define MAY_HAVE_NEON(name) MAY_HAVE_MEDIA(name) +# endif + +# if defined(OPUS_ARM_PRESUME_EDSP) +# define PRESUME_EDSP(name) name ## _edsp +# else +# define PRESUME_EDSP(name) name ## _c +# endif + +# if defined(OPUS_ARM_PRESUME_MEDIA) +# define PRESUME_MEDIA(name) name ## _media +# else +# define PRESUME_MEDIA(name) PRESUME_EDSP(name) +# endif + +# if defined(OPUS_ARM_PRESUME_NEON) +# define PRESUME_NEON(name) name ## _neon +# else +# define PRESUME_NEON(name) PRESUME_MEDIA(name) +# endif + +# if defined(OPUS_HAVE_RTCD) +int opus_select_arch(void); + +#define OPUS_ARCH_ARM_V4 (0) +#define OPUS_ARCH_ARM_EDSP (1) +#define OPUS_ARCH_ARM_MEDIA (2) +#define OPUS_ARCH_ARM_NEON (3) + +# endif + +#endif diff --git a/native/codec/libraries/opus/celt/arm/armopts.s.in b/native/codec/libraries/opus/celt/arm/armopts.s.in new file mode 100644 index 0000000..3d8aaf2 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/armopts.s.in @@ -0,0 +1,37 @@ +/* Copyright (C) 2013 Mozilla Corporation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +; Set the following to 1 if we have EDSP instructions +; (LDRD/STRD, etc., ARMv5E and later). +OPUS_ARM_MAY_HAVE_EDSP * @OPUS_ARM_MAY_HAVE_EDSP@ + +; Set the following to 1 if we have ARMv6 media instructions. +OPUS_ARM_MAY_HAVE_MEDIA * @OPUS_ARM_MAY_HAVE_MEDIA@ + +; Set the following to 1 if we have NEON (some ARMv7) +OPUS_ARM_MAY_HAVE_NEON * @OPUS_ARM_MAY_HAVE_NEON@ + +END diff --git a/native/codec/libraries/opus/celt/arm/celt_fft_ne10.c b/native/codec/libraries/opus/celt/arm/celt_fft_ne10.c new file mode 100644 index 0000000..ea5fd78 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/celt_fft_ne10.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_fft_ne10.c + @brief ARM Neon optimizations for fft using NE10 library + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include +#include "os_support.h" +#include "kiss_fft.h" +#include "stack_alloc.h" + +#if !defined(FIXED_POINT) +# define NE10_FFT_ALLOC_C2C_TYPE_NEON ne10_fft_alloc_c2c_float32_neon +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_float32_t +# define NE10_FFT_STATE_TYPE_T ne10_fft_state_float32_t +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_float32 +# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_float32_t +# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_float32_neon +#else +# define NE10_FFT_ALLOC_C2C_TYPE_NEON(nfft) ne10_fft_alloc_c2c_int32_neon(nfft) +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_int32_t +# define NE10_FFT_STATE_TYPE_T ne10_fft_state_int32_t +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32 +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32 +# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_int32_t +# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_int32_neon +#endif + +#if defined(CUSTOM_MODES) + +/* nfft lengths in NE10 that support scaled fft */ +# define NE10_FFTSCALED_SUPPORT_MAX 4 +static const int ne10_fft_scaled_support[NE10_FFTSCALED_SUPPORT_MAX] = { + 480, 240, 120, 60 +}; + +int opus_fft_alloc_arm_neon(kiss_fft_state *st) +{ + int i; + size_t memneeded = sizeof(struct arch_fft_state); + + st->arch_fft = (arch_fft_state *)opus_alloc(memneeded); + if (!st->arch_fft) + return -1; + + for (i = 0; i < NE10_FFTSCALED_SUPPORT_MAX; i++) { + if(st->nfft == ne10_fft_scaled_support[i]) + break; + } + if (i == NE10_FFTSCALED_SUPPORT_MAX) { + /* This nfft length (scaled fft) is not supported in NE10 */ + st->arch_fft->is_supported = 0; + st->arch_fft->priv = NULL; + } + else { + st->arch_fft->is_supported = 1; + st->arch_fft->priv = (void *)NE10_FFT_ALLOC_C2C_TYPE_NEON(st->nfft); + if (st->arch_fft->priv == NULL) { + return -1; + } + } + return 0; +} + +void opus_fft_free_arm_neon(kiss_fft_state *st) +{ + NE10_FFT_CFG_TYPE_T cfg; + + if (!st->arch_fft) + return; + + cfg = (NE10_FFT_CFG_TYPE_T)st->arch_fft->priv; + if (cfg) + NE10_FFT_DESTROY_C2C_TYPE(cfg); + opus_free(st->arch_fft); +} +#endif + +void opus_fft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) +{ + NE10_FFT_STATE_TYPE_T state; + NE10_FFT_CFG_TYPE_T cfg = &state; + VARDECL(NE10_FFT_CPX_TYPE_T, buffer); + SAVE_STACK; + ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T); + + if (!st->arch_fft->is_supported) { + /* This nfft length (scaled fft) not supported in NE10 */ + opus_fft_c(st, fin, fout); + } + else { + memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T)); + state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0]; +#if !defined(FIXED_POINT) + state.is_forward_scaled = 1; + + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 0); +#else + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 0, 1); +#endif + } + RESTORE_STACK; +} + +void opus_ifft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) +{ + NE10_FFT_STATE_TYPE_T state; + NE10_FFT_CFG_TYPE_T cfg = &state; + VARDECL(NE10_FFT_CPX_TYPE_T, buffer); + SAVE_STACK; + ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T); + + if (!st->arch_fft->is_supported) { + /* This nfft length (scaled fft) not supported in NE10 */ + opus_ifft_c(st, fin, fout); + } + else { + memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T)); + state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0]; +#if !defined(FIXED_POINT) + state.is_backward_scaled = 0; + + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 1); +#else + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 1, 0); +#endif + } + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/celt/arm/celt_mdct_ne10.c b/native/codec/libraries/opus/celt/arm/celt_mdct_ne10.c new file mode 100644 index 0000000..3531d02 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/celt_mdct_ne10.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_mdct_ne10.c + @brief ARM Neon optimizations for mdct using NE10 library + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include "mdct.h" +#include "stack_alloc.h" + +void clt_mdct_forward_neon(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + + SAVE_STACK; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ii,t[N4+i]) - S_MUL(fp->r,t[i]); + yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} + +void clt_mdct_backward_neon(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, + int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + const kiss_twiddle_scalar *trig; + const kiss_fft_state *st = l->kfft[shift]; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + for(i=0;i>1)), arch); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * yp0 = out+(overlap>>1); + kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + re = yp0[0]; + im = yp0[1]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL(re,t0) + S_MUL(im,t1); + yi = S_MUL(re,t1) - S_MUL(im,t0); + re = yp1[0]; + im = yp1[1]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL(re,t0) + S_MUL(im,t1); + yi = S_MUL(re,t1) - S_MUL(im,t0); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1); + *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/celt/arm/celt_neon_intr.c b/native/codec/libraries/opus/celt/arm/celt_neon_intr.c new file mode 100644 index 0000000..effda76 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/celt_neon_intr.c @@ -0,0 +1,211 @@ +/* Copyright (c) 2014-2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_neon_intr.c + @brief ARM Neon Intrinsic optimizations for celt + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "../pitch.h" + +#if defined(FIXED_POINT) +void xcorr_kernel_neon_fixed(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len) +{ + int j; + int32x4_t a = vld1q_s32(sum); + /* Load y[0...3] */ + /* This requires len>0 to always be valid (which we assert in the C code). */ + int16x4_t y0 = vld1_s16(y); + y += 4; + + for (j = 0; j + 8 <= len; j += 8) + { + /* Load x[0...7] */ + int16x8_t xx = vld1q_s16(x); + int16x4_t x0 = vget_low_s16(xx); + int16x4_t x4 = vget_high_s16(xx); + /* Load y[4...11] */ + int16x8_t yy = vld1q_s16(y); + int16x4_t y4 = vget_low_s16(yy); + int16x4_t y8 = vget_high_s16(yy); + int32x4_t a0 = vmlal_lane_s16(a, y0, x0, 0); + int32x4_t a1 = vmlal_lane_s16(a0, y4, x4, 0); + + int16x4_t y1 = vext_s16(y0, y4, 1); + int16x4_t y5 = vext_s16(y4, y8, 1); + int32x4_t a2 = vmlal_lane_s16(a1, y1, x0, 1); + int32x4_t a3 = vmlal_lane_s16(a2, y5, x4, 1); + + int16x4_t y2 = vext_s16(y0, y4, 2); + int16x4_t y6 = vext_s16(y4, y8, 2); + int32x4_t a4 = vmlal_lane_s16(a3, y2, x0, 2); + int32x4_t a5 = vmlal_lane_s16(a4, y6, x4, 2); + + int16x4_t y3 = vext_s16(y0, y4, 3); + int16x4_t y7 = vext_s16(y4, y8, 3); + int32x4_t a6 = vmlal_lane_s16(a5, y3, x0, 3); + int32x4_t a7 = vmlal_lane_s16(a6, y7, x4, 3); + + y0 = y8; + a = a7; + x += 8; + y += 8; + } + + for (; j < len; j++) + { + int16x4_t x0 = vld1_dup_s16(x); /* load next x */ + int32x4_t a0 = vmlal_s16(a, y0, x0); + + int16x4_t y4 = vld1_dup_s16(y); /* load next y */ + y0 = vext_s16(y0, y4, 1); + a = a0; + x++; + y++; + } + + vst1q_s32(sum, a); +} + +#else +/* + * Function: xcorr_kernel_neon_float + * --------------------------------- + * Computes 4 correlation values and stores them in sum[4] + */ +static void xcorr_kernel_neon_float(const float32_t *x, const float32_t *y, + float32_t sum[4], int len) { + float32x4_t YY[3]; + float32x4_t YEXT[3]; + float32x4_t XX[2]; + float32x2_t XX_2; + float32x4_t SUMM; + const float32_t *xi = x; + const float32_t *yi = y; + + celt_assert(len>0); + + YY[0] = vld1q_f32(yi); + SUMM = vdupq_n_f32(0); + + /* Consume 8 elements in x vector and 12 elements in y + * vector. However, the 12'th element never really gets + * touched in this loop. So, if len == 8, then we only + * must access y[0] to y[10]. y[11] must not be accessed + * hence make sure len > 8 and not len >= 8 + */ + while (len > 8) { + yi += 4; + YY[1] = vld1q_f32(yi); + yi += 4; + YY[2] = vld1q_f32(yi); + + XX[0] = vld1q_f32(xi); + xi += 4; + XX[1] = vld1q_f32(xi); + xi += 4; + + SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0); + YEXT[0] = vextq_f32(YY[0], YY[1], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1); + YEXT[1] = vextq_f32(YY[0], YY[1], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0); + YEXT[2] = vextq_f32(YY[0], YY[1], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1); + + SUMM = vmlaq_lane_f32(SUMM, YY[1], vget_low_f32(XX[1]), 0); + YEXT[0] = vextq_f32(YY[1], YY[2], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[1]), 1); + YEXT[1] = vextq_f32(YY[1], YY[2], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[1]), 0); + YEXT[2] = vextq_f32(YY[1], YY[2], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[1]), 1); + + YY[0] = YY[2]; + len -= 8; + } + + /* Consume 4 elements in x vector and 8 elements in y + * vector. However, the 8'th element in y never really gets + * touched in this loop. So, if len == 4, then we only + * must access y[0] to y[6]. y[7] must not be accessed + * hence make sure len>4 and not len>=4 + */ + if (len > 4) { + yi += 4; + YY[1] = vld1q_f32(yi); + + XX[0] = vld1q_f32(xi); + xi += 4; + + SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0); + YEXT[0] = vextq_f32(YY[0], YY[1], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1); + YEXT[1] = vextq_f32(YY[0], YY[1], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0); + YEXT[2] = vextq_f32(YY[0], YY[1], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1); + + YY[0] = YY[1]; + len -= 4; + } + + while (--len > 0) { + XX_2 = vld1_dup_f32(xi++); + SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0); + YY[0]= vld1q_f32(++yi); + } + + XX_2 = vld1_dup_f32(xi); + SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0); + + vst1q_f32(sum, SUMM); +} + +void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch) { + int i; + (void)arch; + celt_assert(max_pitch > 0); + celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + + for (i = 0; i < (max_pitch-3); i += 4) { + xcorr_kernel_neon_float((const float32_t *)_x, (const float32_t *)_y+i, + (float32_t *)xcorr+i, len); + } + + /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */ + for (; i < max_pitch; i++) { + xcorr[i] = celt_inner_prod_neon(_x, _y+i, len); + } +} +#endif diff --git a/native/codec/libraries/opus/celt/arm/celt_pitch_xcorr_arm.s b/native/codec/libraries/opus/celt/arm/celt_pitch_xcorr_arm.s new file mode 100644 index 0000000..6e873af --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/celt_pitch_xcorr_arm.s @@ -0,0 +1,551 @@ +; Copyright (c) 2007-2008 CSIRO +; Copyright (c) 2007-2009 Xiph.Org Foundation +; Copyright (c) 2013 Parrot +; Written by Aurélien Zanelli +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; - Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; +; - Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +; OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + AREA |.text|, CODE, READONLY + + GET celt/arm/armopts.s + +IF OPUS_ARM_MAY_HAVE_EDSP + EXPORT celt_pitch_xcorr_edsp +ENDIF + +IF OPUS_ARM_MAY_HAVE_NEON + EXPORT celt_pitch_xcorr_neon +ENDIF + +IF OPUS_ARM_MAY_HAVE_NEON + +; Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3 +xcorr_kernel_neon PROC +xcorr_kernel_neon_start + ; input: + ; r3 = int len + ; r4 = opus_val16 *x + ; r5 = opus_val16 *y + ; q0 = opus_val32 sum[4] + ; output: + ; q0 = opus_val32 sum[4] + ; preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15 + ; internal usage: + ; r12 = int j + ; d3 = y_3|y_2|y_1|y_0 + ; q2 = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4 + ; q3 = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0 + ; q8 = scratch + ; + ; Load y[0...3] + ; This requires len>0 to always be valid (which we assert in the C code). + VLD1.16 {d5}, [r5]! + SUBS r12, r3, #8 + BLE xcorr_kernel_neon_process4 +; Process 8 samples at a time. +; This loop loads one y value more than we actually need. Therefore we have to +; stop as soon as there are 8 or fewer samples left (instead of 7), to avoid +; reading past the end of the array. +xcorr_kernel_neon_process8 + ; This loop has 19 total instructions (10 cycles to issue, minimum), with + ; - 2 cycles of ARM insrtuctions, + ; - 10 cycles of load/store/byte permute instructions, and + ; - 9 cycles of data processing instructions. + ; On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the + ; latter two categories, meaning the whole loop should run in 10 cycles per + ; iteration, barring cache misses. + ; + ; Load x[0...7] + VLD1.16 {d6, d7}, [r4]! + ; Unlike VMOV, VAND is a data processsing instruction (and doesn't get + ; assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1. + VAND d3, d5, d5 + SUBS r12, r12, #8 + ; Load y[4...11] + VLD1.16 {d4, d5}, [r5]! + VMLAL.S16 q0, d3, d6[0] + VEXT.16 d16, d3, d4, #1 + VMLAL.S16 q0, d4, d7[0] + VEXT.16 d17, d4, d5, #1 + VMLAL.S16 q0, d16, d6[1] + VEXT.16 d16, d3, d4, #2 + VMLAL.S16 q0, d17, d7[1] + VEXT.16 d17, d4, d5, #2 + VMLAL.S16 q0, d16, d6[2] + VEXT.16 d16, d3, d4, #3 + VMLAL.S16 q0, d17, d7[2] + VEXT.16 d17, d4, d5, #3 + VMLAL.S16 q0, d16, d6[3] + VMLAL.S16 q0, d17, d7[3] + BGT xcorr_kernel_neon_process8 +; Process 4 samples here if we have > 4 left (still reading one extra y value). +xcorr_kernel_neon_process4 + ADDS r12, r12, #4 + BLE xcorr_kernel_neon_process2 + ; Load x[0...3] + VLD1.16 d6, [r4]! + ; Use VAND since it's a data processing instruction again. + VAND d4, d5, d5 + SUB r12, r12, #4 + ; Load y[4...7] + VLD1.16 d5, [r5]! + VMLAL.S16 q0, d4, d6[0] + VEXT.16 d16, d4, d5, #1 + VMLAL.S16 q0, d16, d6[1] + VEXT.16 d16, d4, d5, #2 + VMLAL.S16 q0, d16, d6[2] + VEXT.16 d16, d4, d5, #3 + VMLAL.S16 q0, d16, d6[3] +; Process 2 samples here if we have > 2 left (still reading one extra y value). +xcorr_kernel_neon_process2 + ADDS r12, r12, #2 + BLE xcorr_kernel_neon_process1 + ; Load x[0...1] + VLD2.16 {d6[],d7[]}, [r4]! + ; Use VAND since it's a data processing instruction again. + VAND d4, d5, d5 + SUB r12, r12, #2 + ; Load y[4...5] + VLD1.32 {d5[]}, [r5]! + VMLAL.S16 q0, d4, d6 + VEXT.16 d16, d4, d5, #1 + ; Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI + ; instead of VEXT, since it's a data-processing instruction. + VSRI.64 d5, d4, #32 + VMLAL.S16 q0, d16, d7 +; Process 1 sample using the extra y value we loaded above. +xcorr_kernel_neon_process1 + ; Load next *x + VLD1.16 {d6[]}, [r4]! + ADDS r12, r12, #1 + ; y[0...3] are left in d5 from prior iteration(s) (if any) + VMLAL.S16 q0, d5, d6 + MOVLE pc, lr +; Now process 1 last sample, not reading ahead. + ; Load last *y + VLD1.16 {d4[]}, [r5]! + VSRI.64 d4, d5, #16 + ; Load last *x + VLD1.16 {d6[]}, [r4]! + VMLAL.S16 q0, d4, d6 + MOV pc, lr + ENDP + +; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y, +; opus_val32 *xcorr, int len, int max_pitch, int arch) +celt_pitch_xcorr_neon PROC + ; input: + ; r0 = opus_val16 *_x + ; r1 = opus_val16 *_y + ; r2 = opus_val32 *xcorr + ; r3 = int len + ; output: + ; r0 = int maxcorr + ; internal usage: + ; r4 = opus_val16 *x (for xcorr_kernel_neon()) + ; r5 = opus_val16 *y (for xcorr_kernel_neon()) + ; r6 = int max_pitch + ; r12 = int j + ; q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon()) + ; ignored: + ; int arch + STMFD sp!, {r4-r6, lr} + LDR r6, [sp, #16] + VMOV.S32 q15, #1 + ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done + SUBS r6, r6, #4 + BLT celt_pitch_xcorr_neon_process4_done +celt_pitch_xcorr_neon_process4 + ; xcorr_kernel_neon parameters: + ; r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0} + MOV r4, r0 + MOV r5, r1 + VEOR q0, q0, q0 + ; xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3. + ; So we don't save/restore any other registers. + BL xcorr_kernel_neon_start + SUBS r6, r6, #4 + VST1.32 {q0}, [r2]! + ; _y += 4 + ADD r1, r1, #8 + VMAX.S32 q15, q15, q0 + ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done + BGE celt_pitch_xcorr_neon_process4 +; We have less than 4 sums left to compute. +celt_pitch_xcorr_neon_process4_done + ADDS r6, r6, #4 + ; Reduce maxcorr to a single value + VMAX.S32 d30, d30, d31 + VPMAX.S32 d30, d30, d30 + ; if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done + BLE celt_pitch_xcorr_neon_done +; Now compute each remaining sum one at a time. +celt_pitch_xcorr_neon_process_remaining + MOV r4, r0 + MOV r5, r1 + VMOV.I32 q0, #0 + SUBS r12, r3, #8 + BLT celt_pitch_xcorr_neon_process_remaining4 +; Sum terms 8 at a time. +celt_pitch_xcorr_neon_process_remaining_loop8 + ; Load x[0...7] + VLD1.16 {q1}, [r4]! + ; Load y[0...7] + VLD1.16 {q2}, [r5]! + SUBS r12, r12, #8 + VMLAL.S16 q0, d4, d2 + VMLAL.S16 q0, d5, d3 + BGE celt_pitch_xcorr_neon_process_remaining_loop8 +; Sum terms 4 at a time. +celt_pitch_xcorr_neon_process_remaining4 + ADDS r12, r12, #4 + BLT celt_pitch_xcorr_neon_process_remaining4_done + ; Load x[0...3] + VLD1.16 {d2}, [r4]! + ; Load y[0...3] + VLD1.16 {d3}, [r5]! + SUB r12, r12, #4 + VMLAL.S16 q0, d3, d2 +celt_pitch_xcorr_neon_process_remaining4_done + ; Reduce the sum to a single value. + VADD.S32 d0, d0, d1 + VPADDL.S32 d0, d0 + ADDS r12, r12, #4 + BLE celt_pitch_xcorr_neon_process_remaining_loop_done +; Sum terms 1 at a time. +celt_pitch_xcorr_neon_process_remaining_loop1 + VLD1.16 {d2[]}, [r4]! + VLD1.16 {d3[]}, [r5]! + SUBS r12, r12, #1 + VMLAL.S16 q0, d2, d3 + BGT celt_pitch_xcorr_neon_process_remaining_loop1 +celt_pitch_xcorr_neon_process_remaining_loop_done + VST1.32 {d0[0]}, [r2]! + VMAX.S32 d30, d30, d0 + SUBS r6, r6, #1 + ; _y++ + ADD r1, r1, #2 + ; if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining + BGT celt_pitch_xcorr_neon_process_remaining +celt_pitch_xcorr_neon_done + VMOV.32 r0, d30[0] + LDMFD sp!, {r4-r6, pc} + ENDP + +ENDIF + +IF OPUS_ARM_MAY_HAVE_EDSP + +; This will get used on ARMv7 devices without NEON, so it has been optimized +; to take advantage of dual-issuing where possible. +xcorr_kernel_edsp PROC +xcorr_kernel_edsp_start + ; input: + ; r3 = int len + ; r4 = opus_val16 *_x (must be 32-bit aligned) + ; r5 = opus_val16 *_y (must be 32-bit aligned) + ; r6...r9 = opus_val32 sum[4] + ; output: + ; r6...r9 = opus_val32 sum[4] + ; preserved: r0-r5 + ; internal usage + ; r2 = int j + ; r12,r14 = opus_val16 x[4] + ; r10,r11 = opus_val16 y[4] + STMFD sp!, {r2,r4,r5,lr} + LDR r10, [r5], #4 ; Load y[0...1] + SUBS r2, r3, #4 ; j = len-4 + LDR r11, [r5], #4 ; Load y[2...3] + BLE xcorr_kernel_edsp_process4_done + LDR r12, [r4], #4 ; Load x[0...1] + ; Stall +xcorr_kernel_edsp_process4 + ; The multiplies must issue from pipeline 0, and can't dual-issue with each + ; other. Every other instruction here dual-issues with a multiply, and is + ; thus "free". There should be no stalls in the body of the loop. + SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_0,y_0) + LDR r14, [r4], #4 ; Load x[2...3] + SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x_0,y_1) + SUBS r2, r2, #4 ; j-=4 + SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_0,y_2) + SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x_0,y_3) + SMLATT r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_1,y_1) + LDR r10, [r5], #4 ; Load y[4...5] + SMLATB r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],x_1,y_2) + SMLATT r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_1,y_3) + SMLATB r9, r12, r10, r9 ; sum[3] = MAC16_16(sum[3],x_1,y_4) + LDRGT r12, [r4], #4 ; Load x[0...1] + SMLABB r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_2,y_2) + SMLABT r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x_2,y_3) + SMLABB r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_2,y_4) + SMLABT r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x_2,y_5) + SMLATT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_3,y_3) + LDR r11, [r5], #4 ; Load y[6...7] + SMLATB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],x_3,y_4) + SMLATT r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_3,y_5) + SMLATB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],x_3,y_6) + BGT xcorr_kernel_edsp_process4 +xcorr_kernel_edsp_process4_done + ADDS r2, r2, #4 + BLE xcorr_kernel_edsp_done + LDRH r12, [r4], #2 ; r12 = *x++ + SUBS r2, r2, #1 ; j-- + ; Stall + SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_0) + LDRHGT r14, [r4], #2 ; r14 = *x++ + SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x,y_1) + SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_2) + SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x,y_3) + BLE xcorr_kernel_edsp_done + SMLABT r6, r14, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_1) + SUBS r2, r2, #1 ; j-- + SMLABB r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x,y_2) + LDRH r10, [r5], #2 ; r10 = y_4 = *y++ + SMLABT r8, r14, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_3) + LDRHGT r12, [r4], #2 ; r12 = *x++ + SMLABB r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x,y_4) + BLE xcorr_kernel_edsp_done + SMLABB r6, r12, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_2) + CMP r2, #1 ; j-- + SMLABT r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_3) + LDRH r2, [r5], #2 ; r2 = y_5 = *y++ + SMLABB r8, r12, r10, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_4) + LDRHGT r14, [r4] ; r14 = *x + SMLABB r9, r12, r2, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_5) + BLE xcorr_kernel_edsp_done + SMLABT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_3) + LDRH r11, [r5] ; r11 = y_6 = *y + SMLABB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_4) + SMLABB r8, r14, r2, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_5) + SMLABB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_6) +xcorr_kernel_edsp_done + LDMFD sp!, {r2,r4,r5,pc} + ENDP + +celt_pitch_xcorr_edsp PROC + ; input: + ; r0 = opus_val16 *_x (must be 32-bit aligned) + ; r1 = opus_val16 *_y (only needs to be 16-bit aligned) + ; r2 = opus_val32 *xcorr + ; r3 = int len + ; output: + ; r0 = maxcorr + ; internal usage + ; r4 = opus_val16 *x + ; r5 = opus_val16 *y + ; r6 = opus_val32 sum0 + ; r7 = opus_val32 sum1 + ; r8 = opus_val32 sum2 + ; r9 = opus_val32 sum3 + ; r1 = int max_pitch + ; r12 = int j + ; ignored: + ; int arch + STMFD sp!, {r4-r11, lr} + MOV r5, r1 + LDR r1, [sp, #36] + MOV r4, r0 + TST r5, #3 + ; maxcorr = 1 + MOV r0, #1 + BEQ celt_pitch_xcorr_edsp_process1u_done +; Compute one sum at the start to make y 32-bit aligned. + SUBS r12, r3, #4 + ; r14 = sum = 0 + MOV r14, #0 + LDRH r8, [r5], #2 + BLE celt_pitch_xcorr_edsp_process1u_loop4_done + LDR r6, [r4], #4 + MOV r8, r8, LSL #16 +celt_pitch_xcorr_edsp_process1u_loop4 + LDR r9, [r5], #4 + SMLABT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + LDR r7, [r4], #4 + SMLATB r14, r6, r9, r14 ; sum = MAC16_16(sum, x_1, y_1) + LDR r8, [r5], #4 + SMLABT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2) + SUBS r12, r12, #4 ; j-=4 + SMLATB r14, r7, r8, r14 ; sum = MAC16_16(sum, x_3, y_3) + LDRGT r6, [r4], #4 + BGT celt_pitch_xcorr_edsp_process1u_loop4 + MOV r8, r8, LSR #16 +celt_pitch_xcorr_edsp_process1u_loop4_done + ADDS r12, r12, #4 +celt_pitch_xcorr_edsp_process1u_loop1 + LDRHGE r6, [r4], #2 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y) + SUBSGE r12, r12, #1 + LDRHGT r8, [r5], #2 + BGT celt_pitch_xcorr_edsp_process1u_loop1 + ; Restore _x + SUB r4, r4, r3, LSL #1 + ; Restore and advance _y + SUB r5, r5, r3, LSL #1 + ; maxcorr = max(maxcorr, sum) + CMP r0, r14 + ADD r5, r5, #2 + MOVLT r0, r14 + SUBS r1, r1, #1 + ; xcorr[i] = sum + STR r14, [r2], #4 + BLE celt_pitch_xcorr_edsp_done +celt_pitch_xcorr_edsp_process1u_done + ; if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2 + SUBS r1, r1, #4 + BLT celt_pitch_xcorr_edsp_process2 +celt_pitch_xcorr_edsp_process4 + ; xcorr_kernel_edsp parameters: + ; r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0} + MOV r6, #0 + MOV r7, #0 + MOV r8, #0 + MOV r9, #0 + BL xcorr_kernel_edsp_start ; xcorr_kernel_edsp(_x, _y+i, xcorr+i, len) + ; maxcorr = max(maxcorr, sum0, sum1, sum2, sum3) + CMP r0, r6 + ; _y+=4 + ADD r5, r5, #8 + MOVLT r0, r6 + CMP r0, r7 + MOVLT r0, r7 + CMP r0, r8 + MOVLT r0, r8 + CMP r0, r9 + MOVLT r0, r9 + STMIA r2!, {r6-r9} + SUBS r1, r1, #4 + BGE celt_pitch_xcorr_edsp_process4 +celt_pitch_xcorr_edsp_process2 + ADDS r1, r1, #2 + BLT celt_pitch_xcorr_edsp_process1a + SUBS r12, r3, #4 + ; {r10, r11} = {sum0, sum1} = {0, 0} + MOV r10, #0 + MOV r11, #0 + LDR r8, [r5], #4 + BLE celt_pitch_xcorr_edsp_process2_loop_done + LDR r6, [r4], #4 + LDR r9, [r5], #4 +celt_pitch_xcorr_edsp_process2_loop4 + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDR r7, [r4], #4 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + SUBS r12, r12, #4 ; j-=4 + SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1) + LDR r8, [r5], #4 + SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2) + LDRGT r6, [r4], #4 + SMLABB r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_2, y_2) + SMLABT r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_2, y_3) + SMLATT r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_3, y_3) + LDRGT r9, [r5], #4 + SMLATB r11, r7, r8, r11 ; sum1 = MAC16_16(sum1, x_3, y_4) + BGT celt_pitch_xcorr_edsp_process2_loop4 +celt_pitch_xcorr_edsp_process2_loop_done + ADDS r12, r12, #2 + BLE celt_pitch_xcorr_edsp_process2_1 + LDR r6, [r4], #4 + ; Stall + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDR r9, [r5], #4 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + SUB r12, r12, #2 + SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1) + MOV r8, r9 + SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2) +celt_pitch_xcorr_edsp_process2_1 + LDRH r6, [r4], #2 + ADDS r12, r12, #1 + ; Stall + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDRHGT r7, [r4], #2 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + BLE celt_pitch_xcorr_edsp_process2_done + LDRH r9, [r5], #2 + SMLABT r10, r7, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_1) + SMLABB r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_0, y_2) +celt_pitch_xcorr_edsp_process2_done + ; Restore _x + SUB r4, r4, r3, LSL #1 + ; Restore and advance _y + SUB r5, r5, r3, LSL #1 + ; maxcorr = max(maxcorr, sum0) + CMP r0, r10 + ADD r5, r5, #2 + MOVLT r0, r10 + SUB r1, r1, #2 + ; maxcorr = max(maxcorr, sum1) + CMP r0, r11 + ; xcorr[i] = sum + STR r10, [r2], #4 + MOVLT r0, r11 + STR r11, [r2], #4 +celt_pitch_xcorr_edsp_process1a + ADDS r1, r1, #1 + BLT celt_pitch_xcorr_edsp_done + SUBS r12, r3, #4 + ; r14 = sum = 0 + MOV r14, #0 + BLT celt_pitch_xcorr_edsp_process1a_loop_done + LDR r6, [r4], #4 + LDR r8, [r5], #4 + LDR r7, [r4], #4 + LDR r9, [r5], #4 +celt_pitch_xcorr_edsp_process1a_loop4 + SMLABB r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + SUBS r12, r12, #4 ; j-=4 + SMLATT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1) + LDRGE r6, [r4], #4 + SMLABB r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2) + LDRGE r8, [r5], #4 + SMLATT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_3, y_3) + LDRGE r7, [r4], #4 + LDRGE r9, [r5], #4 + BGE celt_pitch_xcorr_edsp_process1a_loop4 +celt_pitch_xcorr_edsp_process1a_loop_done + ADDS r12, r12, #2 + LDRGE r6, [r4], #4 + LDRGE r8, [r5], #4 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + SUBGE r12, r12, #2 + SMLATTGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1) + ADDS r12, r12, #1 + LDRHGE r6, [r4], #2 + LDRHGE r8, [r5], #2 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y) + ; maxcorr = max(maxcorr, sum) + CMP r0, r14 + ; xcorr[i] = sum + STR r14, [r2], #4 + MOVLT r0, r14 +celt_pitch_xcorr_edsp_done + LDMFD sp!, {r4-r11, pc} + ENDP + +ENDIF + +END diff --git a/native/codec/libraries/opus/celt/arm/fft_arm.h b/native/codec/libraries/opus/celt/arm/fft_arm.h new file mode 100644 index 0000000..0b78175 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/fft_arm.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file fft_arm.h + @brief ARM Neon Intrinsic optimizations for fft using NE10 library + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#if !defined(FFT_ARM_H) +#define FFT_ARM_H + +#include "kiss_fft.h" + +#if defined(HAVE_ARM_NE10) + +int opus_fft_alloc_arm_neon(kiss_fft_state *st); +void opus_fft_free_arm_neon(kiss_fft_state *st); + +void opus_fft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout); + +void opus_ifft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_OPUS_FFT (1) + +#define opus_fft_alloc_arch(_st, arch) \ + ((void)(arch), opus_fft_alloc_arm_neon(_st)) + +#define opus_fft_free_arch(_st, arch) \ + ((void)(arch), opus_fft_free_arm_neon(_st)) + +#define opus_fft(_st, _fin, _fout, arch) \ + ((void)(arch), opus_fft_neon(_st, _fin, _fout)) + +#define opus_ifft(_st, _fin, _fout, arch) \ + ((void)(arch), opus_ifft_neon(_st, _fin, _fout)) + +#endif /* OPUS_HAVE_RTCD */ + +#endif /* HAVE_ARM_NE10 */ + +#endif diff --git a/native/codec/libraries/opus/celt/arm/fixed_arm64.h b/native/codec/libraries/opus/celt/arm/fixed_arm64.h new file mode 100644 index 0000000..c6fbd3d --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/fixed_arm64.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2015 Vidyo */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_ARM64_H +#define FIXED_ARM64_H + +#include + +#undef SIG2WORD16 +#define SIG2WORD16(x) (vqmovns_s32(PSHR32((x), SIG_SHIFT))) + +#endif diff --git a/native/codec/libraries/opus/celt/arm/fixed_armv4.h b/native/codec/libraries/opus/celt/arm/fixed_armv4.h new file mode 100644 index 0000000..d84888a --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/fixed_armv4.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2013 Xiph.Org Foundation and contributors */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_ARMv4_H +#define FIXED_ARMv4_H + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q16 +static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#MULT16_32_Q16\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b),"r"(SHL32(a,16)) + ); + return rd_hi; +} +#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv4(a, b)) + + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q15 +static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#MULT16_32_Q15\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b), "r"(SHL32(a,16)) + ); + /*We intentionally don't OR in the high bit of rd_lo for speed.*/ + return SHL32(rd_hi,1); +} +#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b)) + + +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#undef MAC16_32_Q15 +#define MAC16_32_Q15(c, a, b) ADD32(c, MULT16_32_Q15(a, b)) + +/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add. + Result fits in 32 bits. */ +#undef MAC16_32_Q16 +#define MAC16_32_Q16(c, a, b) ADD32(c, MULT16_32_Q16(a, b)) + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#undef MULT32_32_Q31 +#define MULT32_32_Q31(a,b) (opus_val32)((((opus_int64)(a)) * ((opus_int64)(b)))>>31) + +#endif diff --git a/native/codec/libraries/opus/celt/arm/fixed_armv5e.h b/native/codec/libraries/opus/celt/arm/fixed_armv5e.h new file mode 100644 index 0000000..6bf73cb --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/fixed_armv5e.h @@ -0,0 +1,151 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO + Copyright (C) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_ARMv5E_H +#define FIXED_ARMv5E_H + +#include "fixed_armv4.h" + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q16 +static OPUS_INLINE opus_val32 MULT16_32_Q16_armv5e(opus_val16 a, opus_val32 b) +{ + int res; + __asm__( + "#MULT16_32_Q16\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(b),"r"(a) + ); + return res; +} +#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv5e(a, b)) + + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q15 +static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b) +{ + int res; + __asm__( + "#MULT16_32_Q15\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(b), "r"(a) + ); + return SHL32(res,1); +} +#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b)) + + +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#undef MAC16_32_Q15 +static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a, + opus_val32 b) +{ + int res; + __asm__( + "#MAC16_32_Q15\n\t" + "smlawb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(SHL32(b,1)), "r"(a), "r"(c) + ); + return res; +} +#define MAC16_32_Q15(c, a, b) (MAC16_32_Q15_armv5e(c, a, b)) + +/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add. + Result fits in 32 bits. */ +#undef MAC16_32_Q16 +static OPUS_INLINE opus_val32 MAC16_32_Q16_armv5e(opus_val32 c, opus_val16 a, + opus_val32 b) +{ + int res; + __asm__( + "#MAC16_32_Q16\n\t" + "smlawb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(b), "r"(a), "r"(c) + ); + return res; +} +#define MAC16_32_Q16(c, a, b) (MAC16_32_Q16_armv5e(c, a, b)) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#undef MAC16_16 +static OPUS_INLINE opus_val32 MAC16_16_armv5e(opus_val32 c, opus_val16 a, + opus_val16 b) +{ + int res; + __asm__( + "#MAC16_16\n\t" + "smlabb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(a), "r"(b), "r"(c) + ); + return res; +} +#define MAC16_16(c, a, b) (MAC16_16_armv5e(c, a, b)) + +/** 16x16 multiplication where the result fits in 32 bits */ +#undef MULT16_16 +static OPUS_INLINE opus_val32 MULT16_16_armv5e(opus_val16 a, opus_val16 b) +{ + int res; + __asm__( + "#MULT16_16\n\t" + "smulbb %0, %1, %2;\n" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define MULT16_16(a, b) (MULT16_16_armv5e(a, b)) + +#ifdef OPUS_ARM_INLINE_MEDIA + +#undef SIG2WORD16 +static OPUS_INLINE opus_val16 SIG2WORD16_armv6(opus_val32 x) +{ + celt_sig res; + __asm__( + "#SIG2WORD16\n\t" + "ssat %0, #16, %1, ASR #12\n\t" + : "=r"(res) + : "r"(x+2048) + ); + return EXTRACT16(res); +} +#define SIG2WORD16(x) (SIG2WORD16_armv6(x)) + +#endif /* OPUS_ARM_INLINE_MEDIA */ + +#endif diff --git a/native/codec/libraries/opus/celt/arm/kiss_fft_armv4.h b/native/codec/libraries/opus/celt/arm/kiss_fft_armv4.h new file mode 100644 index 0000000..e4faad6 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/kiss_fft_armv4.h @@ -0,0 +1,121 @@ +/*Copyright (c) 2013, Xiph.Org Foundation and contributors. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +#ifndef KISS_FFT_ARMv4_H +#define KISS_FFT_ARMv4_H + +#if !defined(KISS_FFT_GUTS_H) +#error "This file should only be included from _kiss_fft_guts.h" +#endif + +#ifdef FIXED_POINT + +#undef C_MUL +#define C_MUL(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MUL\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mi], r1, %[br]\n\t" \ + "smlal %[tt], %[mi], r0, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mr], r0, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #15\n\t" \ + "smlal %[br], %[mr], r1, %[bi]\n\t" \ + "orr %[mi], %[tt], %[mi], lsl #17\n\t" \ + "mov %[br], %[br], lsr #15\n\t" \ + "orr %[mr], %[br], %[mr], lsl #17\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#undef C_MUL4 +#define C_MUL4(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MUL4\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mi], r1, %[br]\n\t" \ + "smlal %[tt], %[mi], r0, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mr], r0, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #17\n\t" \ + "smlal %[br], %[mr], r1, %[bi]\n\t" \ + "orr %[mi], %[tt], %[mi], lsl #15\n\t" \ + "mov %[br], %[br], lsr #17\n\t" \ + "orr %[mr], %[br], %[mr], lsl #15\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#undef C_MULC +#define C_MULC(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MULC\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mr], r0, %[br]\n\t" \ + "smlal %[tt], %[mr], r1, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mi], r1, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #15\n\t" \ + "smlal %[br], %[mi], r0, %[bi]\n\t" \ + "orr %[mr], %[tt], %[mr], lsl #17\n\t" \ + "mov %[br], %[br], lsr #15\n\t" \ + "orr %[mi], %[br], %[mi], lsl #17\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#endif /* FIXED_POINT */ + +#endif /* KISS_FFT_ARMv4_H */ diff --git a/native/codec/libraries/opus/celt/arm/kiss_fft_armv5e.h b/native/codec/libraries/opus/celt/arm/kiss_fft_armv5e.h new file mode 100644 index 0000000..9eca183 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/kiss_fft_armv5e.h @@ -0,0 +1,118 @@ +/*Copyright (c) 2013, Xiph.Org Foundation and contributors. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +#ifndef KISS_FFT_ARMv5E_H +#define KISS_FFT_ARMv5E_H + +#if !defined(KISS_FFT_GUTS_H) +#error "This file should only be included from _kiss_fft_guts.h" +#endif + +#ifdef FIXED_POINT + +#if defined(__thumb__)||defined(__thumb2__) +#define LDRD_CONS "Q" +#else +#define LDRD_CONS "Uq" +#endif + +#undef C_MUL +#define C_MUL(m,a,b) \ + do{ \ + int mr1__; \ + int mr2__; \ + int mi__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MUL\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mi], %H[aval], %[bval]\n\t" \ + "smulwb %[mr1], %[aval], %[bval]\n\t" \ + "smulwt %[mr2], %H[aval], %[bval]\n\t" \ + "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \ + : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHL32(SUB32(mr1__, mr2__), 1); \ + (m).i = SHL32(mi__, 1); \ + } \ + while(0) + +#undef C_MUL4 +#define C_MUL4(m,a,b) \ + do{ \ + int mr1__; \ + int mr2__; \ + int mi__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MUL4\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mi], %H[aval], %[bval]\n\t" \ + "smulwb %[mr1], %[aval], %[bval]\n\t" \ + "smulwt %[mr2], %H[aval], %[bval]\n\t" \ + "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \ + : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHR32(SUB32(mr1__, mr2__), 1); \ + (m).i = SHR32(mi__, 1); \ + } \ + while(0) + +#undef C_MULC +#define C_MULC(m,a,b) \ + do{ \ + int mr__; \ + int mi1__; \ + int mi2__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MULC\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mr], %[aval], %[bval]\n\t" \ + "smulwb %[mi1], %H[aval], %[bval]\n\t" \ + "smulwt %[mi2], %[aval], %[bval]\n\t" \ + "smlawt %[mr], %H[aval], %[bval], %[mr]\n\t" \ + : [mr]"=r"(mr__), [mi1]"=r"(mi1__), [mi2]"=r"(mi2__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHL32(mr__, 1); \ + (m).i = SHL32(SUB32(mi1__, mi2__), 1); \ + } \ + while(0) + +#endif /* FIXED_POINT */ + +#endif /* KISS_FFT_GUTS_H */ diff --git a/native/codec/libraries/opus/celt/arm/mdct_arm.h b/native/codec/libraries/opus/celt/arm/mdct_arm.h new file mode 100644 index 0000000..14200ba --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/mdct_arm.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file arm_mdct.h + @brief ARM Neon Intrinsic optimizations for mdct using NE10 library + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(MDCT_ARM_H) +#define MDCT_ARM_H + +#include "mdct.h" + +#if defined(HAVE_ARM_NE10) +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward_neon(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +void clt_mdct_backward_neon(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_OPUS_MDCT (1) +#define clt_mdct_forward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \ + clt_mdct_forward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch) +#define clt_mdct_backward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \ + clt_mdct_backward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch) +#endif /* OPUS_HAVE_RTCD */ +#endif /* HAVE_ARM_NE10 */ + +#endif diff --git a/native/codec/libraries/opus/celt/arm/pitch_arm.h b/native/codec/libraries/opus/celt/arm/pitch_arm.h new file mode 100644 index 0000000..bed8b04 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/pitch_arm.h @@ -0,0 +1,160 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(PITCH_ARM_H) +# define PITCH_ARM_H + +# include "armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N); +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, + const opus_val16 *y02, int N, opus_val32 *xy1, opus_val32 *xy2); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_CELT_INNER_PROD (1) +# define OVERRIDE_DUAL_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((void)(arch), PRESUME_NEON(celt_inner_prod)(x, y, N)) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((void)(arch), PRESUME_NEON(dual_inner_prod)(x, y01, y02, N, xy1, xy2)) +# endif +# endif + +# if !defined(OVERRIDE_CELT_INNER_PROD) +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y, int N); +# define OVERRIDE_CELT_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((*CELT_INNER_PROD_IMPL[(arch)&OPUS_ARCHMASK])(x, y, N)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_CELT_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((void)(arch), celt_inner_prod_neon(x, y, N)) +# endif +# endif + +# if !defined(OVERRIDE_DUAL_INNER_PROD) +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, + const opus_val16 *y01, const opus_val16 *y02, int N, opus_val32 *xy1, opus_val32 *xy2); +# define OVERRIDE_DUAL_INNER_PROD (1) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((*DUAL_INNER_PROD_IMPL[(arch)&OPUS_ARCHMASK])(x, y01, y02, N, xy1, xy2)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_DUAL_INNER_PROD (1) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((void)(arch), dual_inner_prod_neon(x, y01, y02, N, xy1, xy2)) +# endif +# endif + +# if defined(FIXED_POINT) + +# if defined(OPUS_ARM_MAY_HAVE_NEON) +opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) +# define celt_pitch_xcorr_media MAY_HAVE_EDSP(celt_pitch_xcorr) +# endif + +# if defined(OPUS_ARM_MAY_HAVE_EDSP) +opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +# endif + +# if defined(OPUS_HAVE_RTCD) && \ + ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \ + (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \ + (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP))) +extern opus_val32 +(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int); +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \ + ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \ + xcorr, len, max_pitch, arch)) + +# elif defined(OPUS_ARM_PRESUME_EDSP) || \ + defined(OPUS_ARM_PRESUME_MEDIA) || \ + defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr (PRESUME_NEON(celt_pitch_xcorr)) + +# endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void xcorr_kernel_neon_fixed( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len); +# endif + +# if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) + +extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len); + +# define OVERRIDE_XCORR_KERNEL (1) +# define xcorr_kernel(x, y, sum, len, arch) \ + ((*XCORR_KERNEL_IMPL[(arch) & OPUS_ARCHMASK])(x, y, sum, len)) + +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_XCORR_KERNEL (1) +# define xcorr_kernel(x, y, sum, len, arch) \ + ((void)arch, xcorr_kernel_neon_fixed(x, y, sum, len)) + +# endif + +#else /* Start !FIXED_POINT */ +/* Float case */ +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +#endif + +# if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void +(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int); + +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \ + ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \ + xcorr, len, max_pitch, arch)) + +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) + +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr celt_pitch_xcorr_float_neon + +# endif + +#endif /* end !FIXED_POINT */ + +#endif diff --git a/native/codec/libraries/opus/celt/arm/pitch_neon_intr.c b/native/codec/libraries/opus/celt/arm/pitch_neon_intr.c new file mode 100644 index 0000000..1ac38c4 --- /dev/null +++ b/native/codec/libraries/opus/celt/arm/pitch_neon_intr.c @@ -0,0 +1,290 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "pitch.h" + +#ifdef FIXED_POINT + +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy; + int16x8_t x_s16x8, y_s16x8; + int32x4_t xy_s32x4 = vdupq_n_s32(0); + int64x2_t xy_s64x2; + int64x1_t xy_s64x1; + + for (i = 0; i < N - 7; i += 8) { + x_s16x8 = vld1q_s16(&x[i]); + y_s16x8 = vld1q_s16(&y[i]); + xy_s32x4 = vmlal_s16(xy_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y_s16x8)); + xy_s32x4 = vmlal_s16(xy_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y_s16x8)); + } + + if (N - i >= 4) { + const int16x4_t x_s16x4 = vld1_s16(&x[i]); + const int16x4_t y_s16x4 = vld1_s16(&y[i]); + xy_s32x4 = vmlal_s16(xy_s32x4, x_s16x4, y_s16x4); + i += 4; + } + + xy_s64x2 = vpaddlq_s32(xy_s32x4); + xy_s64x1 = vadd_s64(vget_low_s64(xy_s64x2), vget_high_s64(xy_s64x2)); + xy = vget_lane_s32(vreinterpret_s32_s64(xy_s64x1), 0); + + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + +#ifdef OPUS_CHECK_ASM + celt_assert(celt_inner_prod_c(x, y, N) == xy); +#endif + + return xy; +} + +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02; + int16x8_t x_s16x8, y01_s16x8, y02_s16x8; + int32x4_t xy01_s32x4 = vdupq_n_s32(0); + int32x4_t xy02_s32x4 = vdupq_n_s32(0); + int64x2_t xy01_s64x2, xy02_s64x2; + int64x1_t xy01_s64x1, xy02_s64x1; + + for (i = 0; i < N - 7; i += 8) { + x_s16x8 = vld1q_s16(&x[i]); + y01_s16x8 = vld1q_s16(&y01[i]); + y02_s16x8 = vld1q_s16(&y02[i]); + xy01_s32x4 = vmlal_s16(xy01_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y01_s16x8)); + xy02_s32x4 = vmlal_s16(xy02_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y02_s16x8)); + xy01_s32x4 = vmlal_s16(xy01_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y01_s16x8)); + xy02_s32x4 = vmlal_s16(xy02_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y02_s16x8)); + } + + if (N - i >= 4) { + const int16x4_t x_s16x4 = vld1_s16(&x[i]); + const int16x4_t y01_s16x4 = vld1_s16(&y01[i]); + const int16x4_t y02_s16x4 = vld1_s16(&y02[i]); + xy01_s32x4 = vmlal_s16(xy01_s32x4, x_s16x4, y01_s16x4); + xy02_s32x4 = vmlal_s16(xy02_s32x4, x_s16x4, y02_s16x4); + i += 4; + } + + xy01_s64x2 = vpaddlq_s32(xy01_s32x4); + xy02_s64x2 = vpaddlq_s32(xy02_s32x4); + xy01_s64x1 = vadd_s64(vget_low_s64(xy01_s64x2), vget_high_s64(xy01_s64x2)); + xy02_s64x1 = vadd_s64(vget_low_s64(xy02_s64x2), vget_high_s64(xy02_s64x2)); + xy01 = vget_lane_s32(vreinterpret_s32_s64(xy01_s64x1), 0); + xy02 = vget_lane_s32(vreinterpret_s32_s64(xy02_s64x1), 0); + + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; + +#ifdef OPUS_CHECK_ASM + { + opus_val32 xy1_c, xy2_c; + dual_inner_prod_c(x, y01, y02, N, &xy1_c, &xy2_c); + celt_assert(xy1_c == *xy1); + celt_assert(xy2_c == *xy2); + } +#endif +} + +#else /* !FIXED_POINT */ + +/* ========================================================================== */ + +#ifdef OPUS_CHECK_ASM + +/* This part of code simulates floating-point NEON operations. */ + +/* celt_inner_prod_neon_float_c_simulation() simulates the floating-point */ +/* operations of celt_inner_prod_neon(), and both functions should have bit */ +/* exact output. */ +static opus_val32 celt_inner_prod_neon_float_c_simulation(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy, xy0 = 0, xy1 = 0, xy2 = 0, xy3 = 0; + for (i = 0; i < N - 3; i += 4) { + xy0 = MAC16_16(xy0, x[i + 0], y[i + 0]); + xy1 = MAC16_16(xy1, x[i + 1], y[i + 1]); + xy2 = MAC16_16(xy2, x[i + 2], y[i + 2]); + xy3 = MAC16_16(xy3, x[i + 3], y[i + 3]); + } + xy0 += xy2; + xy1 += xy3; + xy = xy0 + xy1; + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + return xy; +} + +/* dual_inner_prod_neon_float_c_simulation() simulates the floating-point */ +/* operations of dual_inner_prod_neon(), and both functions should have bit */ +/* exact output. */ +static void dual_inner_prod_neon_float_c_simulation(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02, xy01_0 = 0, xy01_1 = 0, xy01_2 = 0, xy01_3 = 0, xy02_0 = 0, xy02_1 = 0, xy02_2 = 0, xy02_3 = 0; + for (i = 0; i < N - 3; i += 4) { + xy01_0 = MAC16_16(xy01_0, x[i + 0], y01[i + 0]); + xy01_1 = MAC16_16(xy01_1, x[i + 1], y01[i + 1]); + xy01_2 = MAC16_16(xy01_2, x[i + 2], y01[i + 2]); + xy01_3 = MAC16_16(xy01_3, x[i + 3], y01[i + 3]); + xy02_0 = MAC16_16(xy02_0, x[i + 0], y02[i + 0]); + xy02_1 = MAC16_16(xy02_1, x[i + 1], y02[i + 1]); + xy02_2 = MAC16_16(xy02_2, x[i + 2], y02[i + 2]); + xy02_3 = MAC16_16(xy02_3, x[i + 3], y02[i + 3]); + } + xy01_0 += xy01_2; + xy02_0 += xy02_2; + xy01_1 += xy01_3; + xy02_1 += xy02_3; + xy01 = xy01_0 + xy01_1; + xy02 = xy02_0 + xy02_1; + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; +} + +#endif /* OPUS_CHECK_ASM */ + +/* ========================================================================== */ + +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy; + float32x4_t xy_f32x4 = vdupq_n_f32(0); + float32x2_t xy_f32x2; + + for (i = 0; i < N - 7; i += 8) { + float32x4_t x_f32x4, y_f32x4; + x_f32x4 = vld1q_f32(&x[i]); + y_f32x4 = vld1q_f32(&y[i]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + x_f32x4 = vld1q_f32(&x[i + 4]); + y_f32x4 = vld1q_f32(&y[i + 4]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + } + + if (N - i >= 4) { + const float32x4_t x_f32x4 = vld1q_f32(&x[i]); + const float32x4_t y_f32x4 = vld1q_f32(&y[i]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + i += 4; + } + + xy_f32x2 = vadd_f32(vget_low_f32(xy_f32x4), vget_high_f32(xy_f32x4)); + xy_f32x2 = vpadd_f32(xy_f32x2, xy_f32x2); + xy = vget_lane_f32(xy_f32x2, 0); + + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + +#ifdef OPUS_CHECK_ASM + celt_assert(ABS32(celt_inner_prod_neon_float_c_simulation(x, y, N) - xy) <= VERY_SMALL); +#endif + + return xy; +} + +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02; + float32x4_t xy01_f32x4 = vdupq_n_f32(0); + float32x4_t xy02_f32x4 = vdupq_n_f32(0); + float32x2_t xy01_f32x2, xy02_f32x2; + + for (i = 0; i < N - 7; i += 8) { + float32x4_t x_f32x4, y01_f32x4, y02_f32x4; + x_f32x4 = vld1q_f32(&x[i]); + y01_f32x4 = vld1q_f32(&y01[i]); + y02_f32x4 = vld1q_f32(&y02[i]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + x_f32x4 = vld1q_f32(&x[i + 4]); + y01_f32x4 = vld1q_f32(&y01[i + 4]); + y02_f32x4 = vld1q_f32(&y02[i + 4]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + } + + if (N - i >= 4) { + const float32x4_t x_f32x4 = vld1q_f32(&x[i]); + const float32x4_t y01_f32x4 = vld1q_f32(&y01[i]); + const float32x4_t y02_f32x4 = vld1q_f32(&y02[i]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + i += 4; + } + + xy01_f32x2 = vadd_f32(vget_low_f32(xy01_f32x4), vget_high_f32(xy01_f32x4)); + xy02_f32x2 = vadd_f32(vget_low_f32(xy02_f32x4), vget_high_f32(xy02_f32x4)); + xy01_f32x2 = vpadd_f32(xy01_f32x2, xy01_f32x2); + xy02_f32x2 = vpadd_f32(xy02_f32x2, xy02_f32x2); + xy01 = vget_lane_f32(xy01_f32x2, 0); + xy02 = vget_lane_f32(xy02_f32x2, 0); + + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; + +#ifdef OPUS_CHECK_ASM + { + opus_val32 xy1_c, xy2_c; + dual_inner_prod_neon_float_c_simulation(x, y01, y02, N, &xy1_c, &xy2_c); + celt_assert(ABS32(xy1_c - *xy1) <= VERY_SMALL); + celt_assert(ABS32(xy2_c - *xy2) <= VERY_SMALL); + } +#endif +} + +#endif /* FIXED_POINT */ diff --git a/native/codec/libraries/opus/celt/bands.c b/native/codec/libraries/opus/celt/bands.c new file mode 100644 index 0000000..2702963 --- /dev/null +++ b/native/codec/libraries/opus/celt/bands.c @@ -0,0 +1,1672 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2009 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "bands.h" +#include "modes.h" +#include "vq.h" +#include "cwrs.h" +#include "stack_alloc.h" +#include "os_support.h" +#include "mathops.h" +#include "rate.h" +#include "quant_bands.h" +#include "pitch.h" + +int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev) +{ + int i; + for (i=0;iprev && val < thresholds[prev]+hysteresis[prev]) + i=prev; + if (i thresholds[prev-1]-hysteresis[prev-1]) + i=prev; + return i; +} + +opus_uint32 celt_lcg_rand(opus_uint32 seed) +{ + return 1664525 * seed + 1013904223; +} + +/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness + with this approximation is important because it has an impact on the bit allocation */ +opus_int16 bitexact_cos(opus_int16 x) +{ + opus_int32 tmp; + opus_int16 x2; + tmp = (4096+((opus_int32)(x)*(x)))>>13; + celt_sig_assert(tmp<=32767); + x2 = tmp; + x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2))))); + celt_sig_assert(x2<=32766); + return 1+x2; +} + +int bitexact_log2tan(int isin,int icos) +{ + int lc; + int ls; + lc=EC_ILOG(icos); + ls=EC_ILOG(isin); + icos<<=15-lc; + isin<<=15-ls; + return (ls-lc)*(1<<11) + +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932) + -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932); +} + +#ifdef FIXED_POINT +/* Compute the amplitude (sqrt energy) in each of the bands */ +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM, int arch) +{ + int i, c, N; + const opus_int16 *eBands = m->eBands; + (void)arch; + N = m->shortMdctSize< 0) + { + int shift = celt_ilog2(maxval) - 14 + (((m->logN[i]>>BITRES)+LM+1)>>1); + j=eBands[i]<0) + { + do { + sum = MAC16_16(sum, EXTRACT16(SHR32(X[j+c*N],shift)), + EXTRACT16(SHR32(X[j+c*N],shift))); + } while (++jnbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift); + } else { + bandE[i+c*m->nbEBands] = EPSILON; + } + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + i=0; do { + opus_val16 g; + int j,shift; + opus_val16 E; + shift = celt_zlog2(bandE[i+c*m->nbEBands])-13; + E = VSHR32(bandE[i+c*m->nbEBands], shift); + g = EXTRACT16(celt_rcp(SHL32(E,3))); + j=M*eBands[i]; do { + X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g); + } while (++jeBands; + N = m->shortMdctSize<nbEBands] = celt_sqrt(sum); + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands]); + for (j=M*eBands[i];jeBands; + N = M*m->shortMdctSize; + bound = M*eBands[end]; + if (downsample!=1) + bound = IMIN(bound, N/downsample); + if (silence) + { + bound = 0; + start = end = 0; + } + f = freq; + x = X+M*eBands[start]; + for (i=0;i>DB_SHIFT); + if (shift>31) + { + shift=0; + g=0; + } else { + /* Handle the fractional part. */ + g = celt_exp2_frac(lg&((1< 16384 we'd be likely to overflow, so we're + capping the gain here, which is equivalent to a cap of 18 on lg. + This shouldn't trigger unless the bitstream is already corrupted. */ + if (shift <= -2) + { + g = 16384; + shift = -2; + } + do { + *f++ = SHL32(MULT16_16(*x++, g), -shift); + } while (++jeBands[i+1]-m->eBands[i]; + /* depth in 1/8 bits */ + celt_sig_assert(pulses[i]>=0); + depth = celt_udiv(1+pulses[i], (m->eBands[i+1]-m->eBands[i]))>>LM; + +#ifdef FIXED_POINT + thresh32 = SHR32(celt_exp2(-SHL16(depth, 10-BITRES)),1); + thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,thresh32)); + { + opus_val32 t; + t = N0<>1; + t = SHL32(t, (7-shift)<<1); + sqrt_1 = celt_rsqrt_norm(t); + } +#else + thresh = .5f*celt_exp2(-.125f*depth); + sqrt_1 = celt_rsqrt(N0<nbEBands+i]; + prev2 = prev2logE[c*m->nbEBands+i]; + if (C==1) + { + prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]); + prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]); + } + Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2)); + Ediff = MAX32(0, Ediff); + +#ifdef FIXED_POINT + if (Ediff < 16384) + { + opus_val32 r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)),1); + r = 2*MIN16(16383,r32); + } else { + r = 0; + } + if (LM==3) + r = MULT16_16_Q14(23170, MIN32(23169, r)); + r = SHR16(MIN16(thresh, r),1); + r = SHR32(MULT16_16_Q15(sqrt_1, r),shift); +#else + /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because + short blocks don't have the same energy as long */ + r = 2.f*celt_exp2(-Ediff); + if (LM==3) + r *= 1.41421356f; + r = MIN16(thresh, r); + r = r*sqrt_1; +#endif + X = X_+c*size+(m->eBands[i]<nbEBands]))-13; +#endif + left = VSHR32(bandE[i],shift); + right = VSHR32(bandE[i+m->nbEBands],shift); + norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); + a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); + a2 = DIV32_16(SHL32(EXTEND32(right),14),norm); + for (j=0;j>1; + kr = celt_ilog2(Er)>>1; +#endif + t = VSHR32(El, (kl-7)<<1); + lgain = celt_rsqrt_norm(t); + t = VSHR32(Er, (kr-7)<<1); + rgain = celt_rsqrt_norm(t); + +#ifdef FIXED_POINT + if (kl < 7) + kl = 7; + if (kr < 7) + kr = 7; +#endif + + for (j=0;jeBands; + int decision; + int hf_sum=0; + + celt_assert(end>0); + + N0 = M*m->shortMdctSize; + + if (M*(eBands[end]-eBands[end-1]) <= 8) + return SPREAD_NONE; + c=0; do { + for (i=0;im->nbEBands-4) + hf_sum += celt_udiv(32*(tcount[1]+tcount[0]), N); + tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N); + sum += tmp*spread_weight[i]; + nbBands+=spread_weight[i]; + } + } while (++cnbEBands+end)); + *hf_average = (*hf_average+hf_sum)>>1; + hf_sum = *hf_average; + if (*tapset_decision==2) + hf_sum += 4; + else if (*tapset_decision==0) + hf_sum -= 4; + if (hf_sum > 22) + *tapset_decision=2; + else if (hf_sum > 18) + *tapset_decision=1; + else + *tapset_decision=0; + } + /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/ + celt_assert(nbBands>0); /* end has to be non-zero */ + celt_assert(sum>=0); + sum = celt_udiv((opus_int32)sum<<8, nbBands); + /* Recursive averaging */ + sum = (sum+*average)>>1; + *average = sum; + /* Hysteresis */ + sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2; + if (sum < 80) + { + decision = SPREAD_AGGRESSIVE; + } else if (sum < 256) + { + decision = SPREAD_NORMAL; + } else if (sum < 384) + { + decision = SPREAD_LIGHT; + } else { + decision = SPREAD_NONE; + } +#ifdef FUZZING + decision = rand()&0x3; + *tapset_decision=rand()%3; +#endif + return decision; +} + +/* Indexing table for converting from natural Hadamard to ordery Hadamard + This is essentially a bit-reversed Gray, on top of which we've added + an inversion of the order because we want the DC at the end rather than + the beginning. The lines are for N=2, 4, 8, 16 */ +static const int ordery_table[] = { + 1, 0, + 3, 0, 2, 1, + 7, 0, 4, 3, 6, 1, 5, 2, + 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5, +}; + +static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard) +{ + int i,j; + VARDECL(celt_norm, tmp); + int N; + SAVE_STACK; + N = N0*stride; + ALLOC(tmp, N, celt_norm); + celt_assert(stride>0); + if (hadamard) + { + const int *ordery = ordery_table+stride-2; + for (i=0;i>= 1; + for (i=0;i>1)) { + qn = 1; + } else { + qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES)); + qn = (qn+1)>>1<<1; + } + celt_assert(qn <= 256); + return qn; +} + +struct band_ctx { + int encode; + int resynth; + const CELTMode *m; + int i; + int intensity; + int spread; + int tf_change; + ec_ctx *ec; + opus_int32 remaining_bits; + const celt_ener *bandE; + opus_uint32 seed; + int arch; + int theta_round; + int disable_inv; + int avoid_split_noise; +}; + +struct split_ctx { + int inv; + int imid; + int iside; + int delta; + int itheta; + int qalloc; +}; + +static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx, + celt_norm *X, celt_norm *Y, int N, int *b, int B, int B0, + int LM, + int stereo, int *fill) +{ + int qn; + int itheta=0; + int delta; + int imid, iside; + int qalloc; + int pulse_cap; + int offset; + opus_int32 tell; + int inv=0; + int encode; + const CELTMode *m; + int i; + int intensity; + ec_ctx *ec; + const celt_ener *bandE; + + encode = ctx->encode; + m = ctx->m; + i = ctx->i; + intensity = ctx->intensity; + ec = ctx->ec; + bandE = ctx->bandE; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = m->logN[i]+LM*(1<>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET); + qn = compute_qn(N, *b, offset, pulse_cap, stereo); + if (stereo && i>=intensity) + qn = 1; + if (encode) + { + /* theta is the atan() of the ratio between the (normalized) + side and mid. With just that parameter, we can re-scale both + mid and side because we know that 1) they have unit norm and + 2) they are orthogonal. */ + itheta = stereo_itheta(X, Y, stereo, N, ctx->arch); + } + tell = ec_tell_frac(ec); + if (qn!=1) + { + if (encode) + { + if (!stereo || ctx->theta_round == 0) + { + itheta = (itheta*(opus_int32)qn+8192)>>14; + if (!stereo && ctx->avoid_split_noise && itheta > 0 && itheta < qn) + { + /* Check if the selected value of theta will cause the bit allocation + to inject noise on one side. If so, make sure the energy of that side + is zero. */ + int unquantized = celt_udiv((opus_int32)itheta*16384, qn); + imid = bitexact_cos((opus_int16)unquantized); + iside = bitexact_cos((opus_int16)(16384-unquantized)); + delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid)); + if (delta > *b) + itheta = qn; + else if (delta < -*b) + itheta = 0; + } + } else { + int down; + /* Bias quantization towards itheta=0 and itheta=16384. */ + int bias = itheta > 8192 ? 32767/qn : -32767/qn; + down = IMIN(qn-1, IMAX(0, (itheta*(opus_int32)qn + bias)>>14)); + if (ctx->theta_round < 0) + itheta = down; + else + itheta = down+1; + } + } + /* Entropy coding of the angle. We use a uniform pdf for the + time split, a step for stereo, and a triangular one for the rest. */ + if (stereo && N>2) + { + int p0 = 3; + int x = itheta; + int x0 = qn/2; + int ft = p0*(x0+1) + x0; + /* Use a probability of p0 up to itheta=8192 and then use 1 after */ + if (encode) + { + ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + } else { + int fs; + fs=ec_decode(ec,ft); + if (fs<(x0+1)*p0) + x=fs/p0; + else + x=x0+1+(fs-(x0+1)*p0); + ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + itheta = x; + } + } else if (B0>1 || stereo) { + /* Uniform pdf */ + if (encode) + ec_enc_uint(ec, itheta, qn+1); + else + itheta = ec_dec_uint(ec, qn+1); + } else { + int fs=1, ft; + ft = ((qn>>1)+1)*((qn>>1)+1); + if (encode) + { + int fl; + + fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta; + fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 : + ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + + ec_encode(ec, fl, fl+fs, ft); + } else { + /* Triangular pdf */ + int fl=0; + int fm; + fm = ec_decode(ec, ft); + + if (fm < ((qn>>1)*((qn>>1) + 1)>>1)) + { + itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1; + fs = itheta + 1; + fl = itheta*(itheta + 1)>>1; + } + else + { + itheta = (2*(qn + 1) + - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1; + fs = qn + 1 - itheta; + fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + } + + ec_dec_update(ec, fl, fl+fs, ft); + } + } + celt_assert(itheta>=0); + itheta = celt_udiv((opus_int32)itheta*16384, qn); + if (encode && stereo) + { + if (itheta==0) + intensity_stereo(m, X, Y, bandE, i, N); + else + stereo_split(X, Y, N); + } + /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate. + Let's do that at higher complexity */ + } else if (stereo) { + if (encode) + { + inv = itheta > 8192 && !ctx->disable_inv; + if (inv) + { + int j; + for (j=0;j2<remaining_bits > 2<disable_inv) + inv = 0; + itheta = 0; + } + qalloc = ec_tell_frac(ec) - tell; + *b -= qalloc; + + if (itheta == 0) + { + imid = 32767; + iside = 0; + *fill &= (1<inv = inv; + sctx->imid = imid; + sctx->iside = iside; + sctx->delta = delta; + sctx->itheta = itheta; + sctx->qalloc = qalloc; +} +static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b, + celt_norm *lowband_out) +{ + int c; + int stereo; + celt_norm *x = X; + int encode; + ec_ctx *ec; + + encode = ctx->encode; + ec = ctx->ec; + + stereo = Y != NULL; + c=0; do { + int sign=0; + if (ctx->remaining_bits>=1<remaining_bits -= 1<resynth) + x[0] = sign ? -NORM_SCALING : NORM_SCALING; + x = Y; + } while (++c<1+stereo); + if (lowband_out) + lowband_out[0] = SHR16(X[0],4); + return 1; +} + +/* This function is responsible for encoding and decoding a mono partition. + It can split the band in two and transmit the energy difference with + the two half-bands. It can be called recursively so bands can end up being + split in 8 parts. */ +static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X, + int N, int b, int B, celt_norm *lowband, + int LM, + opus_val16 gain, int fill) +{ + const unsigned char *cache; + int q; + int curr_bits; + int imid=0, iside=0; + int B0=B; + opus_val16 mid=0, side=0; + unsigned cm=0; + celt_norm *Y=NULL; + int encode; + const CELTMode *m; + int i; + int spread; + ec_ctx *ec; + + encode = ctx->encode; + m = ctx->m; + i = ctx->i; + spread = ctx->spread; + ec = ctx->ec; + + /* If we need 1.5 more bit than we can produce, split the band in two. */ + cache = m->cache.bits + m->cache.index[(LM+1)*m->nbEBands+i]; + if (LM != -1 && b > cache[cache[0]]+12 && N>2) + { + int mbits, sbits, delta; + int itheta; + int qalloc; + struct split_ctx sctx; + celt_norm *next_lowband2=NULL; + opus_int32 rebalance; + + N >>= 1; + Y = X+N; + LM -= 1; + if (B==1) + fill = (fill&1)|(fill<<1); + B = (B+1)>>1; + + compute_theta(ctx, &sctx, X, Y, N, &b, B, B0, LM, 0, &fill); + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; +#ifdef FIXED_POINT + mid = imid; + side = iside; +#else + mid = (1.f/32768)*imid; + side = (1.f/32768)*iside; +#endif + + /* Give more bits to low-energy MDCTs than they would otherwise deserve */ + if (B0>1 && (itheta&0x3fff)) + { + if (itheta > 8192) + /* Rough approximation for pre-echo masking */ + delta -= delta>>(4-LM); + else + /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */ + delta = IMIN(0, delta + (N<>(5-LM))); + } + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + ctx->remaining_bits -= qalloc; + + if (lowband) + next_lowband2 = lowband+N; /* >32-bit split case */ + + rebalance = ctx->remaining_bits; + if (mbits >= sbits) + { + cm = quant_partition(ctx, X, N, mbits, B, lowband, LM, + MULT16_16_P15(gain,mid), fill); + rebalance = mbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<>B)<<(B0>>1); + } else { + cm = quant_partition(ctx, Y, N, sbits, B, next_lowband2, LM, + MULT16_16_P15(gain,side), fill>>B)<<(B0>>1); + rebalance = sbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<remaining_bits -= curr_bits; + + /* Ensures we can never bust the budget */ + while (ctx->remaining_bits < 0 && q > 0) + { + ctx->remaining_bits += curr_bits; + q--; + curr_bits = pulses2bits(m, i, LM, q); + ctx->remaining_bits -= curr_bits; + } + + if (q!=0) + { + int K = get_pulses(q); + + /* Finally do the actual quantization */ + if (encode) + { + cm = alg_quant(X, N, K, spread, B, ec, gain, ctx->resynth, ctx->arch); + } else { + cm = alg_unquant(X, N, K, spread, B, ec, gain); + } + } else { + /* If there's no pulse, fill the band anyway */ + int j; + if (ctx->resynth) + { + unsigned cm_mask; + /* B can be as large as 16, so this shift might overflow an int on a + 16-bit platform; use a long to get defined behavior.*/ + cm_mask = (unsigned)(1UL<seed = celt_lcg_rand(ctx->seed); + X[j] = (celt_norm)((opus_int32)ctx->seed>>20); + } + cm = cm_mask; + } else { + /* Folded spectrum */ + for (j=0;jseed = celt_lcg_rand(ctx->seed); + /* About 48 dB below the "normal" folding level */ + tmp = QCONST16(1.0f/256, 10); + tmp = (ctx->seed)&0x8000 ? tmp : -tmp; + X[j] = lowband[j]+tmp; + } + cm = fill; + } + renormalise_vector(X, N, gain, ctx->arch); + } + } + } + } + + return cm; +} + + +/* This function is responsible for encoding and decoding a band for the mono case. */ +static unsigned quant_band(struct band_ctx *ctx, celt_norm *X, + int N, int b, int B, celt_norm *lowband, + int LM, celt_norm *lowband_out, + opus_val16 gain, celt_norm *lowband_scratch, int fill) +{ + int N0=N; + int N_B=N; + int N_B0; + int B0=B; + int time_divide=0; + int recombine=0; + int longBlocks; + unsigned cm=0; + int k; + int encode; + int tf_change; + + encode = ctx->encode; + tf_change = ctx->tf_change; + + longBlocks = B0==1; + + N_B = celt_udiv(N_B, B); + + /* Special case for one sample */ + if (N==1) + { + return quant_band_n1(ctx, X, NULL, b, lowband_out); + } + + if (tf_change>0) + recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband_scratch && lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1)) + { + OPUS_COPY(lowband_scratch, lowband, N); + lowband = lowband_scratch; + } + + for (k=0;k>k, 1<>k, 1<>4]<<2; + } + B>>=recombine; + N_B<<=recombine; + + /* Increasing the time resolution */ + while ((N_B&1) == 0 && tf_change<0) + { + if (encode) + haar1(X, N_B, B); + if (lowband) + haar1(lowband, N_B, B); + fill |= fill<>= 1; + time_divide++; + tf_change++; + } + B0=B; + N_B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (B0>1) + { + if (encode) + deinterleave_hadamard(X, N_B>>recombine, B0<>recombine, B0<resynth) + { + /* Undo the sample reorganization going from time order to frequency order */ + if (B0>1) + interleave_hadamard(X, N_B>>recombine, B0<>= 1; + N_B <<= 1; + cm |= cm>>B; + haar1(X, N_B, B); + } + + for (k=0;k>k, 1<encode; + ec = ctx->ec; + + /* Special case for one sample */ + if (N==1) + { + return quant_band_n1(ctx, X, Y, b, lowband_out); + } + + orig_fill = fill; + + compute_theta(ctx, &sctx, X, Y, N, &b, B, B, LM, 1, &fill); + inv = sctx.inv; + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; +#ifdef FIXED_POINT + mid = imid; + side = iside; +#else + mid = (1.f/32768)*imid; + side = (1.f/32768)*iside; +#endif + + /* This is a special case for N=2 that only works for stereo and takes + advantage of the fact that mid and side are orthogonal to encode + the side with just one bit. */ + if (N==2) + { + int c; + int sign=0; + celt_norm *x2, *y2; + mbits = b; + sbits = 0; + /* Only need one bit for the side. */ + if (itheta != 0 && itheta != 16384) + sbits = 1< 8192; + ctx->remaining_bits -= qalloc+sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) + { + if (encode) + { + /* Here we only need to encode a sign for the side. */ + sign = x2[0]*y2[1] - x2[1]*y2[0] < 0; + ec_enc_bits(ec, sign, 1); + } else { + sign = ec_dec_bits(ec, 1); + } + } + sign = 1-2*sign; + /* We use orig_fill here because we want to fold the side, but if + itheta==16384, we'll have cleared the low bits of fill. */ + cm = quant_band(ctx, x2, N, mbits, B, lowband, LM, lowband_out, Q15ONE, + lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), + and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign*x2[1]; + y2[1] = sign*x2[0]; + if (ctx->resynth) + { + celt_norm tmp; + X[0] = MULT16_16_Q15(mid, X[0]); + X[1] = MULT16_16_Q15(mid, X[1]); + Y[0] = MULT16_16_Q15(side, Y[0]); + Y[1] = MULT16_16_Q15(side, Y[1]); + tmp = X[0]; + X[0] = SUB16(tmp,Y[0]); + Y[0] = ADD16(tmp,Y[0]); + tmp = X[1]; + X[1] = SUB16(tmp,Y[1]); + Y[1] = ADD16(tmp,Y[1]); + } + } else { + /* "Normal" split code */ + opus_int32 rebalance; + + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + ctx->remaining_bits -= qalloc; + + rebalance = ctx->remaining_bits; + if (mbits >= sbits) + { + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized + mid for folding later. */ + cm = quant_band(ctx, X, N, mbits, B, lowband, LM, lowband_out, Q15ONE, + lowband_scratch, fill); + rebalance = mbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<>B); + } else { + /* For a stereo split, the high bits of fill are always zero, so no + folding will be done to the side. */ + cm = quant_band(ctx, Y, N, sbits, B, NULL, LM, NULL, side, NULL, fill>>B); + rebalance = sbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<resynth) + { + if (N!=2) + stereo_merge(X, Y, mid, N, ctx->arch); + if (inv) + { + int j; + for (j=0;jeBands; + n1 = M*(eBands[start+1]-eBands[start]); + n2 = M*(eBands[start+2]-eBands[start+1]); + /* Duplicate enough of the first band folding data to be able to fold the second band. + Copies no data for CELT-only mode. */ + OPUS_COPY(&norm[n1], &norm[2*n1 - n2], n2-n1); + if (dual_stereo) + OPUS_COPY(&norm2[n1], &norm2[2*n1 - n2], n2-n1); +} + +void quant_all_bands(int encode, const CELTMode *m, int start, int end, + celt_norm *X_, celt_norm *Y_, unsigned char *collapse_masks, + const celt_ener *bandE, int *pulses, int shortBlocks, int spread, + int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits, + opus_int32 balance, ec_ctx *ec, int LM, int codedBands, + opus_uint32 *seed, int complexity, int arch, int disable_inv) +{ + int i; + opus_int32 remaining_bits; + const opus_int16 * OPUS_RESTRICT eBands = m->eBands; + celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2; + VARDECL(celt_norm, _norm); + VARDECL(celt_norm, _lowband_scratch); + VARDECL(celt_norm, X_save); + VARDECL(celt_norm, Y_save); + VARDECL(celt_norm, X_save2); + VARDECL(celt_norm, Y_save2); + VARDECL(celt_norm, norm_save2); + int resynth_alloc; + celt_norm *lowband_scratch; + int B; + int M; + int lowband_offset; + int update_lowband = 1; + int C = Y_ != NULL ? 2 : 1; + int norm_offset; + int theta_rdo = encode && Y_!=NULL && !dual_stereo && complexity>=8; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !encode || theta_rdo; +#endif + struct band_ctx ctx; + SAVE_STACK; + + M = 1<nbEBands-1]-norm_offset), celt_norm); + norm = _norm; + norm2 = norm + M*eBands[m->nbEBands-1]-norm_offset; + + /* For decoding, we can use the last band as scratch space because we don't need that + scratch space for the last band and we don't care about the data there until we're + decoding the last band. */ + if (encode && resynth) + resynth_alloc = M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]); + else + resynth_alloc = ALLOC_NONE; + ALLOC(_lowband_scratch, resynth_alloc, celt_norm); + if (encode && resynth) + lowband_scratch = _lowband_scratch; + else + lowband_scratch = X_+M*eBands[m->nbEBands-1]; + ALLOC(X_save, resynth_alloc, celt_norm); + ALLOC(Y_save, resynth_alloc, celt_norm); + ALLOC(X_save2, resynth_alloc, celt_norm); + ALLOC(Y_save2, resynth_alloc, celt_norm); + ALLOC(norm_save2, resynth_alloc, celt_norm); + + lowband_offset = 0; + ctx.bandE = bandE; + ctx.ec = ec; + ctx.encode = encode; + ctx.intensity = intensity; + ctx.m = m; + ctx.seed = *seed; + ctx.spread = spread; + ctx.arch = arch; + ctx.disable_inv = disable_inv; + ctx.resynth = resynth; + ctx.theta_round = 0; + /* Avoid injecting noise in the first band on transients. */ + ctx.avoid_split_noise = B > 1; + for (i=start;i 0); + tell = ec_tell_frac(ec); + + /* Compute how many bits we want to allocate to this band */ + if (i != start) + balance -= tell; + remaining_bits = total_bits-tell-1; + ctx.remaining_bits = remaining_bits; + if (i <= codedBands-1) + { + curr_balance = celt_sudiv(balance, IMIN(3, codedBands-i)); + b = IMAX(0, IMIN(16383, IMIN(remaining_bits+1,pulses[i]+curr_balance))); + } else { + b = 0; + } + +#ifndef DISABLE_UPDATE_DRAFT + if (resynth && (M*eBands[i]-N >= M*eBands[start] || i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + if (i == start+1) + special_hybrid_folding(m, norm, norm2, start, M, dual_stereo); +#else + if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0)) + lowband_offset = i; +#endif + + tf_change = tf_res[i]; + ctx.tf_change = tf_change; + if (i>=m->effEBands) + { + X=norm; + if (Y_!=NULL) + Y = norm; + lowband_scratch = NULL; + } + if (last && !theta_rdo) + lowband_scratch = NULL; + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0)) + { + int fold_start; + int fold_end; + int fold_i; + /* This ensures we never repeat spectral content within one band */ + effective_lowband = IMAX(0, M*eBands[lowband_offset]-norm_offset-N); + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband+norm_offset); + fold_end = lowband_offset-1; +#ifndef DISABLE_UPDATE_DRAFT + while(++fold_end < i && M*eBands[fold_end] < effective_lowband+norm_offset+N); +#else + while(M*eBands[++fold_end] < effective_lowband+norm_offset+N); +#endif + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + y_cm |= collapse_masks[fold_i*C+C-1]; + } while (++fold_inbEBands], w); + /* Make a copy. */ + cm = x_cm|y_cm; + ec_save = *ec; + ctx_save = ctx; + OPUS_COPY(X_save, X, N); + OPUS_COPY(Y_save, Y, N); + /* Encode and round down. */ + ctx.theta_round = -1; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm); + dist0 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch)); + + /* Save first result. */ + cm2 = x_cm; + ec_save2 = *ec; + ctx_save2 = ctx; + OPUS_COPY(X_save2, X, N); + OPUS_COPY(Y_save2, Y, N); + if (!last) + OPUS_COPY(norm_save2, norm+M*eBands[i]-norm_offset, N); + nstart_bytes = ec_save.offs; + nend_bytes = ec_save.storage; + bytes_buf = ec_save.buf+nstart_bytes; + save_bytes = nend_bytes-nstart_bytes; + OPUS_COPY(bytes_save, bytes_buf, save_bytes); + + /* Restore */ + *ec = ec_save; + ctx = ctx_save; + OPUS_COPY(X, X_save, N); + OPUS_COPY(Y, Y_save, N); +#ifndef DISABLE_UPDATE_DRAFT + if (i == start+1) + special_hybrid_folding(m, norm, norm2, start, M, dual_stereo); +#endif + /* Encode and round up. */ + ctx.theta_round = 1; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm); + dist1 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch)); + if (dist0 >= dist1) { + x_cm = cm2; + *ec = ec_save2; + ctx = ctx_save2; + OPUS_COPY(X, X_save2, N); + OPUS_COPY(Y, Y_save2, N); + if (!last) + OPUS_COPY(norm+M*eBands[i]-norm_offset, norm_save2, N); + OPUS_COPY(bytes_buf, bytes_save, save_bytes); + } + } else { + ctx.theta_round = 0; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm); + } + } else { + x_cm = quant_band(&ctx, X, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm); + } + y_cm = x_cm; + } + collapse_masks[i*C+0] = (unsigned char)x_cm; + collapse_masks[i*C+C-1] = (unsigned char)y_cm; + balance += pulses[i] + tell; + + /* Update the folding position only as long as we have 1 bit/sample depth. */ + update_lowband = b>(N< +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +#if defined(MIPSr1_ASM) +#include "mips/celt_mipsr1.h" +#endif + + +int resampling_factor(opus_int32 rate) +{ + int ret; + switch (rate) + { + case 48000: + ret = 1; + break; + case 24000: + ret = 2; + break; + case 16000: + ret = 3; + break; + case 12000: + ret = 4; + break; + case 8000: + ret = 6; + break; + default: +#ifndef CUSTOM_MODES + celt_assert(0); +#endif + ret = 0; + break; + } + return ret; +} + +#if !defined(OVERRIDE_COMB_FILTER_CONST) || defined(NON_STATIC_COMB_FILTER_CONST_C) +/* This version should be faster on ARM */ +#ifdef OPUS_ARM_ASM +#ifndef NON_STATIC_COMB_FILTER_CONST_C +static +#endif +void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + opus_val16 g10, opus_val16 g11, opus_val16 g12) +{ + opus_val32 x0, x1, x2, x3, x4; + int i; + x4 = SHL32(x[-T-2], 1); + x3 = SHL32(x[-T-1], 1); + x2 = SHL32(x[-T], 1); + x1 = SHL32(x[-T+1], 1); + for (i=0;inbEBands;i++) + { + int N; + N=(m->eBands[i+1]-m->eBands[i])<cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2; + } +} + + + +const char *opus_strerror(int error) +{ + static const char * const error_strings[8] = { + "success", + "invalid argument", + "buffer too small", + "internal error", + "corrupted stream", + "request not implemented", + "invalid state", + "memory allocation failed" + }; + if (error > 0 || error < -7) + return "unknown error"; + else + return error_strings[-error]; +} + +const char *opus_get_version_string(void) +{ + return "libopus " PACKAGE_VERSION + /* Applications may rely on the presence of this substring in the version + string to determine if they have a fixed-point or floating-point build + at runtime. */ +#ifdef FIXED_POINT + "-fixed" +#endif +#ifdef FUZZING + "-fuzzing" +#endif + ; +} diff --git a/native/codec/libraries/opus/celt/celt.h b/native/codec/libraries/opus/celt/celt.h new file mode 100644 index 0000000..24b6b2b --- /dev/null +++ b/native/codec/libraries/opus/celt/celt.h @@ -0,0 +1,251 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CELT_H +#define CELT_H + +#include "opus_types.h" +#include "opus_defines.h" +#include "opus_custom.h" +#include "entenc.h" +#include "entdec.h" +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CELTEncoder OpusCustomEncoder +#define CELTDecoder OpusCustomDecoder +#define CELTMode OpusCustomMode + +#define LEAK_BANDS 19 + +typedef struct { + int valid; + float tonality; + float tonality_slope; + float noisiness; + float activity; + float music_prob; + float music_prob_min; + float music_prob_max; + int bandwidth; + float activity_probability; + float max_pitch_ratio; + /* Store as Q6 char to save space. */ + unsigned char leak_boost[LEAK_BANDS]; +} AnalysisInfo; + +typedef struct { + int signalType; + int offset; +} SILKInfo; + +#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr))) + +#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr))) + +#define __celt_check_silkinfo_ptr(ptr) ((ptr) + ((ptr) - (const SILKInfo*)(ptr))) + +/* Encoder/decoder Requests */ + + +#define CELT_SET_PREDICTION_REQUEST 10002 +/** Controls the use of interframe prediction. + 0=Independent frames + 1=Short term interframe prediction allowed + 2=Long term prediction allowed + */ +#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x) + +#define CELT_SET_INPUT_CLIPPING_REQUEST 10004 +#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x) + +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 +#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x) + +#define CELT_SET_CHANNELS_REQUEST 10008 +#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x) + + +/* Internal */ +#define CELT_SET_START_BAND_REQUEST 10010 +#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x) + +#define CELT_SET_END_BAND_REQUEST 10012 +#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x) + +#define CELT_GET_MODE_REQUEST 10015 +/** Get the CELTMode used by an encoder or decoder */ +#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x) + +#define CELT_SET_SIGNALLING_REQUEST 10016 +#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x) + +#define CELT_SET_TONALITY_REQUEST 10018 +#define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x) +#define CELT_SET_TONALITY_SLOPE_REQUEST 10020 +#define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x) + +#define CELT_SET_ANALYSIS_REQUEST 10022 +#define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x) + +#define OPUS_SET_LFE_REQUEST 10024 +#define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x) + +#define OPUS_SET_ENERGY_MASK_REQUEST 10026 +#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x) + +#define CELT_SET_SILK_INFO_REQUEST 10028 +#define CELT_SET_SILK_INFO(x) CELT_SET_SILK_INFO_REQUEST, __celt_check_silkinfo_ptr(x) + +/* Encoder stuff */ + +int celt_encoder_get_size(int channels); + +int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, + int arch); + + + +/* Decoder stuff */ + +int celt_decoder_get_size(int channels); + + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels); + +int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, + int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum); + +#define celt_encoder_ctl opus_custom_encoder_ctl +#define celt_decoder_ctl opus_custom_decoder_ctl + + +#ifdef CUSTOM_MODES +#define OPUS_CUSTOM_NOSTATIC +#else +#define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE +#endif + +static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; +/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ +static const unsigned char spread_icdf[4] = {25, 23, 2, 0}; + +static const unsigned char tapset_icdf[3]={2,1,0}; + +#ifdef CUSTOM_MODES +static const unsigned char toOpusTable[20] = { + 0xE0, 0xE8, 0xF0, 0xF8, + 0xC0, 0xC8, 0xD0, 0xD8, + 0xA0, 0xA8, 0xB0, 0xB8, + 0x00, 0x00, 0x00, 0x00, + 0x80, 0x88, 0x90, 0x98, +}; + +static const unsigned char fromOpusTable[16] = { + 0x80, 0x88, 0x90, 0x98, + 0x40, 0x48, 0x50, 0x58, + 0x20, 0x28, 0x30, 0x38, + 0x00, 0x08, 0x10, 0x18 +}; + +static OPUS_INLINE int toOpus(unsigned char c) +{ + int ret=0; + if (c<0xA0) + ret = toOpusTable[c>>3]; + if (ret == 0) + return -1; + else + return ret|(c&0x7); +} + +static OPUS_INLINE int fromOpus(unsigned char c) +{ + if (c<0x80) + return -1; + else + return fromOpusTable[(c>>3)-16] | (c&0x7); +} +#endif /* CUSTOM_MODES */ + +#define COMBFILTER_MAXPERIOD 1024 +#define COMBFILTER_MINPERIOD 15 + +extern const signed char tf_select_table[4][8]; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +void validate_celt_decoder(CELTDecoder *st); +#define VALIDATE_CELT_DECODER(st) validate_celt_decoder(st) +#else +#define VALIDATE_CELT_DECODER(st) +#endif + +int resampling_factor(opus_int32 rate); + +void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp, + int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip); + +void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, + opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, + const opus_val16 *window, int overlap, int arch); + +#ifdef NON_STATIC_COMB_FILTER_CONST_C +void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + opus_val16 g10, opus_val16 g11, opus_val16 g12); +#endif + +#ifndef OVERRIDE_COMB_FILTER_CONST +# define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \ + ((void)(arch),comb_filter_const_c(y, x, T, N, g10, g11, g12)) +#endif + +void init_caps(const CELTMode *m,int *cap,int LM,int C); + +#ifdef RESYNTH +void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem); +void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[], + opus_val16 *oldBandE, int start, int effEnd, int C, int CC, int isTransient, + int LM, int downsample, int silence); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CELT_H */ diff --git a/native/codec/libraries/opus/celt/celt_decoder.c b/native/codec/libraries/opus/celt/celt_decoder.c new file mode 100644 index 0000000..e6efce9 --- /dev/null +++ b/native/codec/libraries/opus/celt/celt_decoder.c @@ -0,0 +1,1372 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_DECODER_C + +#include "cpu_support.h" +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save + CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The + current value corresponds to a pitch of 66.67 Hz. */ +#define PLC_PITCH_LAG_MAX (720) +/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a + pitch of 480 Hz. */ +#define PLC_PITCH_LAG_MIN (100) + +#if defined(SMALL_FOOTPRINT) && defined(FIXED_POINT) +#define NORM_ALIASING_HACK +#endif +/**********************************************************************/ +/* */ +/* DECODER */ +/* */ +/**********************************************************************/ +#define DECODE_BUFFER_SIZE 2048 + +/** Decoder state + @brief Decoder state + */ +struct OpusCustomDecoder { + const OpusCustomMode *mode; + int overlap; + int channels; + int stream_channels; + + int downsample; + int start, end; + int signalling; + int disable_inv; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define DECODER_RESET_START rng + + opus_uint32 rng; + int error; + int last_pitch_index; + int loss_count; + int skip_plc; + int postfilter_period; + int postfilter_period_old; + opus_val16 postfilter_gain; + opus_val16 postfilter_gain_old; + int postfilter_tapset; + int postfilter_tapset_old; + + celt_sig preemph_memD[2]; + + celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */ + /* opus_val16 lpc[], Size = channels*LPC_ORDER */ + /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */ + /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */ +}; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +/* Make basic checks on the CELT state to ensure we don't end + up writing all over memory. */ +void validate_celt_decoder(CELTDecoder *st) +{ +#ifndef CUSTOM_MODES + celt_assert(st->mode == opus_custom_mode_create(48000, 960, NULL)); + celt_assert(st->overlap == 120); +#endif + celt_assert(st->channels == 1 || st->channels == 2); + celt_assert(st->stream_channels == 1 || st->stream_channels == 2); + celt_assert(st->downsample > 0); + celt_assert(st->start == 0 || st->start == 17); + celt_assert(st->start < st->end); + celt_assert(st->end <= 21); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif + celt_assert(st->last_pitch_index <= PLC_PITCH_LAG_MAX); + celt_assert(st->last_pitch_index >= PLC_PITCH_LAG_MIN || st->last_pitch_index == 0); + celt_assert(st->postfilter_period < MAX_PERIOD); + celt_assert(st->postfilter_period >= COMBFILTER_MINPERIOD || st->postfilter_period == 0); + celt_assert(st->postfilter_period_old < MAX_PERIOD); + celt_assert(st->postfilter_period_old >= COMBFILTER_MINPERIOD || st->postfilter_period_old == 0); + celt_assert(st->postfilter_tapset <= 2); + celt_assert(st->postfilter_tapset >= 0); + celt_assert(st->postfilter_tapset_old <= 2); + celt_assert(st->postfilter_tapset_old >= 0); +} +#endif + +int celt_decoder_get_size(int channels) +{ + const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_decoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTDecoder) + + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig) + + channels*LPC_ORDER*sizeof(opus_val16) + + 4*2*mode->nbEBands*sizeof(opus_val16); + return size; +} + +#ifdef CUSTOM_MODES +CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels)); + ret = opus_custom_decoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_decoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels) +{ + int ret; + ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); + if (ret != OPUS_OK) + return ret; + st->downsample = resampling_factor(sampling_rate); + if (st->downsample==0) + return OPUS_BAD_ARG; + else + return OPUS_OK; +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->downsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; +#ifndef DISABLE_UPDATE_DRAFT + st->disable_inv = channels == 1; +#else + st->disable_inv = 0; +#endif + st->arch = opus_select_arch(); + + opus_custom_decoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_decoder_destroy(CELTDecoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + +#ifndef CUSTOM_MODES +/* Special case for stereo with no downsampling and no accumulation. This is + quite common and we can make it faster by processing both channels in the + same loop, reducing overhead due to the dependency loop in the IIR filter. */ +static void deemphasis_stereo_simple(celt_sig *in[], opus_val16 *pcm, int N, const opus_val16 coef0, + celt_sig *mem) +{ + celt_sig * OPUS_RESTRICT x0; + celt_sig * OPUS_RESTRICT x1; + celt_sig m0, m1; + int j; + x0=in[0]; + x1=in[1]; + m0 = mem[0]; + m1 = mem[1]; + for (j=0;j1) + { + /* Shortcut for the standard (non-custom modes) case */ + for (j=0;joverlap; + nbEBands = mode->nbEBands; + N = mode->shortMdctSize<shortMdctSize; + shift = mode->maxLM; + } else { + B = 1; + NB = mode->shortMdctSize<maxLM-LM; + } + + if (CC==2&&C==1) + { + /* Copying a mono streams to two channels */ + celt_sig *freq2; + denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, + downsample, silence); + /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */ + freq2 = out_syn[1]+overlap/2; + OPUS_COPY(freq2, freq, N); + for (b=0;bmdct, &freq2[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); + for (b=0;bmdct, &freq[b], out_syn[1]+NB*b, mode->window, overlap, shift, B, arch); + } else if (CC==1&&C==2) + { + /* Downmixing a stereo stream to mono */ + celt_sig *freq2; + freq2 = out_syn[0]+overlap/2; + denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, + downsample, silence); + /* Use the output buffer as temp array before downmixing. */ + denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M, + downsample, silence); + for (i=0;imdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); + } else { + /* Normal case (mono or stereo) */ + c=0; do { + denormalise_bands(mode, X+c*N, freq, oldBandE+c*nbEBands, start, effEnd, M, + downsample, silence); + for (b=0;bmdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch); + } while (++cstorage*8; + tell = ec_tell(dec); + logp = isTransient ? 2 : 4; + tf_select_rsv = LM>0 && tell+logp+1<=budget; + budget -= tf_select_rsv; + tf_changed = curr = 0; + for (i=start;i>1, opus_val16 ); + pitch_downsample(decode_mem, lp_pitch_buf, + DECODE_BUFFER_SIZE, C, arch); + pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf, + DECODE_BUFFER_SIZE-PLC_PITCH_LAG_MAX, + PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch); + pitch_index = PLC_PITCH_LAG_MAX-pitch_index; + RESTORE_STACK; + return pitch_index; +} + +static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) +{ + int c; + int i; + const int C = st->channels; + celt_sig *decode_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + int start; + int loss_count; + int noise_based; + const opus_int16 *eBands; + SAVE_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); + out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+overlap)*C); + oldBandE = lpc+C*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + + loss_count = st->loss_count; + start = st->start; + noise_based = loss_count >= 5 || start != 0 || st->skip_plc; + if (noise_based) + { + /* Noise-based PLC/CNG */ +#ifdef NORM_ALIASING_HACK + celt_norm *X; +#else + VARDECL(celt_norm, X); +#endif + opus_uint32 seed; + int end; + int effEnd; + opus_val16 decay; + end = st->end; + effEnd = IMAX(start, IMIN(end, mode->effEBands)); + +#ifdef NORM_ALIASING_HACK + /* This is an ugly hack that breaks aliasing rules and would be easily broken, + but it saves almost 4kB of stack. */ + X = (celt_norm*)(out_syn[C-1]+overlap/2); +#else + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ +#endif + + /* Energy decay */ + decay = loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT); + c=0; do + { + for (i=start;irng; + for (c=0;c>20); + } + renormalise_vector(X+boffs, blen, Q15ONE, st->arch); + } + } + st->rng = seed; + + c=0; do { + OPUS_MOVE(decode_mem[c], decode_mem[c]+N, + DECODE_BUFFER_SIZE-N+(overlap>>1)); + } while (++cdownsample, 0, st->arch); + } else { + int exc_length; + /* Pitch-based PLC */ + const opus_val16 *window; + opus_val16 *exc; + opus_val16 fade = Q15ONE; + int pitch_index; + VARDECL(opus_val32, etmp); + VARDECL(opus_val16, _exc); + VARDECL(opus_val16, fir_tmp); + + if (loss_count == 0) + { + st->last_pitch_index = pitch_index = celt_plc_pitch_search(decode_mem, C, st->arch); + } else { + pitch_index = st->last_pitch_index; + fade = QCONST16(.8f,15); + } + + /* We want the excitation for 2 pitch periods in order to look for a + decaying signal, but we can't get more than MAX_PERIOD. */ + exc_length = IMIN(2*pitch_index, MAX_PERIOD); + + ALLOC(etmp, overlap, opus_val32); + ALLOC(_exc, MAX_PERIOD+LPC_ORDER, opus_val16); + ALLOC(fir_tmp, exc_length, opus_val16); + exc = _exc+LPC_ORDER; + window = mode->window; + c=0; do { + opus_val16 decay; + opus_val16 attenuation; + opus_val32 S1=0; + celt_sig *buf; + int extrapolation_offset; + int extrapolation_len; + int j; + + buf = decode_mem[c]; + for (i=0;iarch); + /* Add a noise floor of -40 dB. */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Use lag windowing to stabilize the Levinson-Durbin recursion. */ + for (i=1;i<=LPC_ORDER;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(0.008f*0.008f)*i*i; +#endif + } + _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER); +#ifdef FIXED_POINT + /* For fixed-point, apply bandwidth expansion until we can guarantee that + no overflow can happen in the IIR filter. This means: + 32768*sum(abs(filter)) < 2^31 */ + while (1) { + opus_val16 tmp=Q15ONE; + opus_val32 sum=QCONST16(1., SIG_SHIFT); + for (i=0;iarch); + OPUS_COPY(exc+MAX_PERIOD-exc_length, fir_tmp, exc_length); + } + + /* Check if the waveform is decaying, and if so how fast. + We do this to avoid adding energy when concealing in a segment + with decaying energy. */ + { + opus_val32 E1=1, E2=1; + int decay_length; +#ifdef FIXED_POINT + int shift = IMAX(0,2*celt_zlog2(celt_maxabs16(&exc[MAX_PERIOD-exc_length], exc_length))-20); +#endif + decay_length = exc_length>>1; + for (i=0;i= pitch_index) { + j -= pitch_index; + attenuation = MULT16_16_Q15(attenuation, decay); + } + buf[DECODE_BUFFER_SIZE-N+i] = + SHL32(EXTEND32(MULT16_16_Q15(attenuation, + exc[extrapolation_offset+j])), SIG_SHIFT); + /* Compute the energy of the previously decoded signal whose + excitation we're copying. */ + tmp = ROUND16( + buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j], + SIG_SHIFT); + S1 += SHR32(MULT16_16(tmp, tmp), 10); + } + { + opus_val16 lpc_mem[LPC_ORDER]; + /* Copy the last decoded samples (prior to the overlap region) to + synthesis filter memory so we can have a continuous signal. */ + for (i=0;iarch); +#ifdef FIXED_POINT + for (i=0; i < extrapolation_len; i++) + buf[DECODE_BUFFER_SIZE-N+i] = SATURATE(buf[DECODE_BUFFER_SIZE-N+i], SIG_SAT); +#endif + } + + /* Check if the synthesis energy is higher than expected, which can + happen with the signal changes during our window. If so, + attenuate. */ + { + opus_val32 S2=0; + for (i=0;i SHR32(S2,2))) +#else + /* The float test is written this way to catch NaNs in the output + of the IIR filter at the same time. */ + if (!(S1 > 0.2f*S2)) +#endif + { + for (i=0;ipostfilter_period, st->postfilter_period, overlap, + -st->postfilter_gain, -st->postfilter_gain, + st->postfilter_tapset, st->postfilter_tapset, NULL, 0, st->arch); + + /* Simulate TDAC on the concealed audio so that it blends with the + MDCT of the next frame. */ + for (i=0;iloss_count = loss_count+1; + + RESTORE_STACK; +} + +int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, + int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum) +{ + int c, i, N; + int spread_decision; + opus_int32 bits; + ec_dec _dec; +#ifdef NORM_ALIASING_HACK + celt_norm *X; +#else + VARDECL(celt_norm, X); +#endif + VARDECL(int, fine_quant); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *decode_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + + int shortBlocks; + int isTransient; + int intra_ener; + const int CC = st->channels; + int LM, M; + int start; + int end; + int effEnd; + int codedBands; + int alloc_trim; + int postfilter_pitch; + opus_val16 postfilter_gain; + int intensity=0; + int dual_stereo=0; + opus_int32 total_bits; + opus_int32 balance; + opus_int32 tell; + int dynalloc_logp; + int postfilter_tapset; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence; + int C = st->stream_channels; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + ALLOC_STACK; + + VALIDATE_CELT_DECODER(st); + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + start = st->start; + end = st->end; + frame_size *= st->downsample; + + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*CC); + oldBandE = lpc+CC*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + +#ifdef CUSTOM_MODES + if (st->signalling && data!=NULL) + { + int data0=data[0]; + /* Convert "standard mode" to Opus header */ + if (mode->Fs==48000 && mode->shortMdctSize==120) + { + data0 = fromOpus(data0); + if (data0<0) + return OPUS_INVALID_PACKET; + } + st->end = end = IMAX(1, mode->effEBands-2*(data0>>5)); + LM = (data0>>3)&0x3; + C = 1 + ((data0>>2)&0x1); + data++; + len--; + if (LM>mode->maxLM) + return OPUS_INVALID_PACKET; + if (frame_size < mode->shortMdctSize<shortMdctSize<maxLM;LM++) + if (mode->shortMdctSize<mode->maxLM) + return OPUS_BAD_ARG; + } + M=1<1275 || pcm==NULL) + return OPUS_BAD_ARG; + + N = M*mode->shortMdctSize; + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); + out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; + } while (++c mode->effEBands) + effEnd = mode->effEBands; + + if (data == NULL || len<=1) + { + celt_decode_lost(st, N, LM); + deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); + RESTORE_STACK; + return frame_size/st->downsample; + } + + /* Check if there are at least two packets received consecutively before + * turning on the pitch-based PLC */ + st->skip_plc = st->loss_count != 0; + + if (dec == NULL) + { + ec_dec_init(&_dec,(unsigned char*)data,len); + dec = &_dec; + } + + if (C==1) + { + for (i=0;i= total_bits) + silence = 1; + else if (tell==1) + silence = ec_dec_bit_logp(dec, 15); + else + silence = 0; + if (silence) + { + /* Pretend we've read all the remaining bits */ + tell = len*8; + dec->nbits_total+=tell-ec_tell(dec); + } + + postfilter_gain = 0; + postfilter_pitch = 0; + postfilter_tapset = 0; + if (start==0 && tell+16 <= total_bits) + { + if(ec_dec_bit_logp(dec, 1)) + { + int qg, octave; + octave = ec_dec_uint(dec, 6); + postfilter_pitch = (16< 0 && tell+3 <= total_bits) + { + isTransient = ec_dec_bit_logp(dec, 3); + tell = ec_tell(dec); + } + else + isTransient = 0; + + if (isTransient) + shortBlocks = M; + else + shortBlocks = 0; + + /* Decode the global flags (first symbols in the stream) */ + intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0; + /* Get band energies */ + unquant_coarse_energy(mode, start, end, oldBandE, + intra_ener, dec, C, LM); + + ALLOC(tf_res, nbEBands, int); + tf_decode(start, end, isTransient, tf_res, LM, dec); + + tell = ec_tell(dec); + spread_decision = SPREAD_NORMAL; + if (tell+4 <= total_bits) + spread_decision = ec_dec_icdf(dec, spread_icdf, 5); + + ALLOC(cap, nbEBands, int); + + init_caps(mode,cap,LM,C); + + ALLOC(offsets, nbEBands, int); + + dynalloc_logp = 6; + total_bits<<=BITRES; + tell = ec_tell_frac(dec); + for (i=start;i0) + dynalloc_logp = IMAX(2, dynalloc_logp-1); + } + + ALLOC(fine_quant, nbEBands, int); + alloc_trim = tell+(6<=2&&bits>=((LM+2)<rng, 0, + st->arch, st->disable_inv); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = ec_dec_bits(dec, 1); + } + + unquant_energy_finalise(mode, start, end, oldBandE, + fine_quant, fine_priority, len*8-ec_tell(dec), dec, C); + + if (anti_collapse_on) + anti_collapse(mode, X, collapse_masks, LM, C, N, + start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng, st->arch); + + if (silence) + { + for (i=0;idownsample, silence, st->arch); + + c=0; do { + st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD); + st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, mode->shortMdctSize, + st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset, + mode->window, overlap, st->arch); + if (LM!=0) + comb_filter(out_syn[c]+mode->shortMdctSize, out_syn[c]+mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-mode->shortMdctSize, + st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset, + mode->window, overlap, st->arch); + + } while (++cpostfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + st->postfilter_period = postfilter_pitch; + st->postfilter_gain = postfilter_gain; + st->postfilter_tapset = postfilter_tapset; + if (LM!=0) + { + st->postfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + } + + if (C==1) + OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); + + /* In case start or end were to change */ + if (!isTransient) + { + opus_val16 max_background_increase; + OPUS_COPY(oldLogE2, oldLogE, 2*nbEBands); + OPUS_COPY(oldLogE, oldBandE, 2*nbEBands); + /* In normal circumstances, we only allow the noise floor to increase by + up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB + increase for each update.*/ + if (st->loss_count < 10) + max_background_increase = M*QCONST16(0.001f,DB_SHIFT); + else + max_background_increase = QCONST16(1.f,DB_SHIFT); + for (i=0;i<2*nbEBands;i++) + backgroundLogE[i] = MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]); + } else { + for (i=0;i<2*nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + c=0; do + { + for (i=0;irng = dec->rng; + + deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); + st->loss_count = 0; + RESTORE_STACK; + if (ec_tell(dec) > 8*len) + return OPUS_INTERNAL_ERROR; + if(ec_get_error(dec)) + st->error = 1; + return frame_size/st->downsample; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size) +{ + return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size) +{ + int j, ret, C, N; + VARDECL(opus_int16, out); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + + ALLOC(out, C*N, opus_int16); + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); + if (ret>0) + for (j=0;jchannels; + N = frame_size; + ALLOC(out, C*N, celt_sig); + + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); + + if (ret>0) + for (j=0;j=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case CELT_GET_AND_CLEAR_ERROR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value=st->error; + st->error = 0; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->overlap/st->downsample; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2; + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels); + oldBandE = lpc+st->channels*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->DECODER_RESET_START, + opus_custom_decoder_get_size(st->mode, st->channels)- + ((char*)&st->DECODER_RESET_START - (char*)st)); + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->skip_plc = 1; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->postfilter_period; + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->disable_inv = value; + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->disable_inv; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} diff --git a/native/codec/libraries/opus/celt/celt_encoder.c b/native/codec/libraries/opus/celt/celt_encoder.c new file mode 100644 index 0000000..44cb085 --- /dev/null +++ b/native/codec/libraries/opus/celt/celt_encoder.c @@ -0,0 +1,2607 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_ENCODER_C + +#include "cpu_support.h" +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + + +/** Encoder state + @brief Encoder state + */ +struct OpusCustomEncoder { + const OpusCustomMode *mode; /**< Mode used by the encoder */ + int channels; + int stream_channels; + + int force_intra; + int clip; + int disable_pf; + int complexity; + int upsample; + int start, end; + + opus_int32 bitrate; + int vbr; + int signalling; + int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ + int loss_rate; + int lsb_depth; + int lfe; + int disable_inv; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define ENCODER_RESET_START rng + + opus_uint32 rng; + int spread_decision; + opus_val32 delayedIntra; + int tonal_average; + int lastCodedBands; + int hf_average; + int tapset_decision; + + int prefilter_period; + opus_val16 prefilter_gain; + int prefilter_tapset; +#ifdef RESYNTH + int prefilter_period_old; + opus_val16 prefilter_gain_old; + int prefilter_tapset_old; +#endif + int consec_transient; + AnalysisInfo analysis; + SILKInfo silk_info; + + opus_val32 preemph_memE[2]; + opus_val32 preemph_memD[2]; + + /* VBR-related parameters */ + opus_int32 vbr_reservoir; + opus_int32 vbr_drift; + opus_int32 vbr_offset; + opus_int32 vbr_count; + opus_val32 overlap_max; + opus_val16 stereo_saving; + int intensity; + opus_val16 *energy_mask; + opus_val16 spec_avg; + +#ifdef RESYNTH + /* +MAX_PERIOD/2 to make space for overlap */ + celt_sig syn_mem[2][2*MAX_PERIOD+MAX_PERIOD/2]; +#endif + + celt_sig in_mem[1]; /* Size = channels*mode->overlap */ + /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD */ + /* opus_val16 oldBandE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = channels*mode->nbEBands */ + /* opus_val16 energyError[], Size = channels*mode->nbEBands */ +}; + +int celt_encoder_get_size(int channels) +{ + CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_encoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTEncoder) + + (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */ + + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */ + + 4*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE2[channels*mode->nbEBands]; */ + /* opus_val16 energyError[channels*mode->nbEBands]; */ + return size; +} + +#ifdef CUSTOM_MODES +CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels)); + /* init will handle the NULL case */ + ret = opus_custom_encoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_encoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode, + int channels, int arch) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL || mode==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels)); + + st->mode = mode; + st->stream_channels = st->channels = channels; + + st->upsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + st->arch = arch; + + st->constrained_vbr = 1; + st->clip = 1; + + st->bitrate = OPUS_BITRATE_MAX; + st->vbr = 0; + st->force_intra = 0; + st->complexity = 5; + st->lsb_depth=24; + + opus_custom_encoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels) +{ + return opus_custom_encoder_init_arch(st, mode, channels, opus_select_arch()); +} +#endif + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, + int arch) +{ + int ret; + ret = opus_custom_encoder_init_arch(st, + opus_custom_mode_create(48000, 960, NULL), channels, arch); + if (ret != OPUS_OK) + return ret; + st->upsample = resampling_factor(sampling_rate); + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_encoder_destroy(CELTEncoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + + +static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C, + opus_val16 *tf_estimate, int *tf_chan, int allow_weak_transients, + int *weak_transient) +{ + int i; + VARDECL(opus_val16, tmp); + opus_val32 mem0,mem1; + int is_transient = 0; + opus_int32 mask_metric = 0; + int c; + opus_val16 tf_max; + int len2; + /* Forward masking: 6.7 dB/ms. */ +#ifdef FIXED_POINT + int forward_shift = 4; +#else + opus_val16 forward_decay = QCONST16(.0625f,15); +#endif + /* Table of 6*64/x, trained on real data to minimize the average error */ + static const unsigned char inv_table[128] = { + 255,255,156,110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25, + 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, + 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + }; + SAVE_STACK; + ALLOC(tmp, len, opus_val16); + + *weak_transient = 0; + /* For lower bitrates, let's be more conservative and have a forward masking + decay of 3.3 dB/ms. This avoids having to code transients at very low + bitrate (mostly for hybrid), which can result in unstable energy and/or + partial collapse. */ + if (allow_weak_transients) + { +#ifdef FIXED_POINT + forward_shift = 5; +#else + forward_decay = QCONST16(.03125f,15); +#endif + } + len2=len/2; + for (c=0;c=0;i--) + { + /* Backward masking: 13.9 dB/ms. */ +#ifdef FIXED_POINT + /* FIXME: Use PSHR16() instead */ + tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3); +#else + tmp[i] = mem0 + MULT16_16_P15(QCONST16(0.125f,15),tmp[i]-mem0); +#endif + mem0 = tmp[i]; + maxE = MAX16(maxE, mem0); + } + /*for (i=0;i>1))); +#else + mean = celt_sqrt(mean * maxE*.5*len2); +#endif + /* Inverse of the mean energy in Q15+6 */ + norm = SHL32(EXTEND32(len2),6+14)/ADD32(EPSILON,SHR32(mean,1)); + /* Compute harmonic mean discarding the unreliable boundaries + The data is smooth, so we only take 1/4th of the samples */ + unmask=0; + /* We should never see NaNs here. If we find any, then something really bad happened and we better abort + before it does any damage later on. If these asserts are disabled (no hardening), then the table + lookup a few lines below (id = ...) is likely to crash dur to an out-of-bounds read. DO NOT FIX + that crash on NaN since it could result in a worse issue later on. */ + celt_assert(!celt_isnan(tmp[0])); + celt_assert(!celt_isnan(norm)); + for (i=12;imask_metric) + { + *tf_chan = c; + mask_metric = unmask; + } + } + is_transient = mask_metric>200; + /* For low bitrates, define "weak transients" that need to be + handled differently to avoid partial collapse. */ + if (allow_weak_transients && is_transient && mask_metric<600) { + is_transient = 0; + *weak_transient = 1; + } + /* Arbitrary metric for VBR boost */ + tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42); + /* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */ + *tf_estimate = celt_sqrt(MAX32(0, SHL32(MULT16_16(QCONST16(0.0069,14),MIN16(163,tf_max)),14)-QCONST32(0.139,28))); + /*printf("%d %f\n", tf_max, mask_metric);*/ + RESTORE_STACK; +#ifdef FUZZING + is_transient = rand()&0x1; +#endif + /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/ + return is_transient; +} + +/* Looks for sudden increases of energy to decide whether we need to patch + the transient decision */ +static int patch_transient_decision(opus_val16 *newE, opus_val16 *oldE, int nbEBands, + int start, int end, int C) +{ + int i, c; + opus_val32 mean_diff=0; + opus_val16 spread_old[26]; + /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to + avoid false detection caused by irrelevant bands */ + if (C==1) + { + spread_old[start] = oldE[start]; + for (i=start+1;i=start;i--) + spread_old[i] = MAX16(spread_old[i], spread_old[i+1]-QCONST16(1.0f, DB_SHIFT)); + /* Compute mean increase */ + c=0; do { + for (i=IMAX(2,start);i QCONST16(1.f, DB_SHIFT); +} + +/** Apply window and compute the MDCT for all sub-frames and + all channels in a frame */ +static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in, + celt_sig * OPUS_RESTRICT out, int C, int CC, int LM, int upsample, + int arch) +{ + const int overlap = mode->overlap; + int N; + int B; + int shift; + int i, b, c; + if (shortBlocks) + { + B = shortBlocks; + N = mode->shortMdctSize; + shift = mode->maxLM; + } else { + B = 1; + N = mode->shortMdctSize<maxLM-LM; + } + c=0; do { + for (b=0;bmdct, in+c*(B*N+overlap)+b*N, + &out[b+c*N*B], mode->window, overlap, shift, B, + arch); + } + } while (++ceBands[len]-m->eBands[len-1])<eBands[len]-m->eBands[len-1])<eBands[i+1]-m->eBands[i])<eBands[i+1]-m->eBands[i])==1; + OPUS_COPY(tmp, &X[tf_chan*N0 + (m->eBands[i]<eBands[i]<>LM, 1<>k, 1<=0;i--) + { + if (tf_res[i+1] == 1) + tf_res[i] = path1[i+1]; + else + tf_res[i] = path0[i+1]; + } + /*printf("%d %f\n", *tf_sum, tf_estimate);*/ + RESTORE_STACK; +#ifdef FUZZING + tf_select = rand()&0x1; + tf_res[0] = rand()&0x1; + for (i=1;istorage*8; + tell = ec_tell(enc); + logp = isTransient ? 2 : 4; + /* Reserve space to code the tf_select decision. */ + tf_select_rsv = LM>0 && tell+logp+1 <= budget; + budget -= tf_select_rsv; + curr = tf_changed = 0; + for (i=start;i> 10; + trim = QCONST16(4.f, 8) + QCONST16(1.f/16.f, 8)*frac; + } + if (C==2) + { + opus_val16 sum = 0; /* Q10 */ + opus_val16 minXC; /* Q10 */ + /* Compute inter-channel correlation for low frequencies */ + for (i=0;i<8;i++) + { + opus_val32 partial; + partial = celt_inner_prod(&X[m->eBands[i]<eBands[i]<eBands[i+1]-m->eBands[i])<eBands[i]<eBands[i]<eBands[i+1]-m->eBands[i])<nbEBands]*(opus_int32)(2+2*i-end); + } + } while (++cvalid) + { + trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), + (opus_val16)(QCONST16(2.f, 8)*(analysis->tonality_slope+.05f)))); + } +#else + (void)analysis; +#endif + +#ifdef FIXED_POINT + trim_index = PSHR32(trim, 8); +#else + trim_index = (int)floor(.5f+trim); +#endif + trim_index = IMAX(0, IMIN(10, trim_index)); + /*printf("%d\n", trim_index);*/ +#ifdef FUZZING + trim_index = rand()%11; +#endif + return trim_index; +} + +static int stereo_analysis(const CELTMode *m, const celt_norm *X, + int LM, int N0) +{ + int i; + int thetas; + opus_val32 sumLR = EPSILON, sumMS = EPSILON; + + /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */ + for (i=0;i<13;i++) + { + int j; + for (j=m->eBands[i]<eBands[i+1]<eBands[13]<<(LM+1))+thetas, sumMS) + > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR); +} + +#define MSWAP(a,b) do {opus_val16 tmp = a;a=b;b=tmp;} while(0) +static opus_val16 median_of_5(const opus_val16 *x) +{ + opus_val16 t0, t1, t2, t3, t4; + t2 = x[2]; + if (x[0] > x[1]) + { + t0 = x[1]; + t1 = x[0]; + } else { + t0 = x[0]; + t1 = x[1]; + } + if (x[3] > x[4]) + { + t3 = x[4]; + t4 = x[3]; + } else { + t3 = x[3]; + t4 = x[4]; + } + if (t0 > t3) + { + MSWAP(t0, t3); + MSWAP(t1, t4); + } + if (t2 > t1) + { + if (t1 < t3) + return MIN16(t2, t3); + else + return MIN16(t4, t1); + } else { + if (t2 < t3) + return MIN16(t1, t3); + else + return MIN16(t2, t4); + } +} + +static opus_val16 median_of_3(const opus_val16 *x) +{ + opus_val16 t0, t1, t2; + if (x[0] > x[1]) + { + t0 = x[1]; + t1 = x[0]; + } else { + t0 = x[0]; + t1 = x[1]; + } + t2 = x[2]; + if (t1 < t2) + return t1; + else if (t0 < t2) + return t2; + else + return t0; +} + +static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2, + int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN, + int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM, + int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc, + AnalysisInfo *analysis, int *importance, int *spread_weight) +{ + int i, c; + opus_int32 tot_boost=0; + opus_val16 maxDepth; + VARDECL(opus_val16, follower); + VARDECL(opus_val16, noise_floor); + SAVE_STACK; + ALLOC(follower, C*nbEBands, opus_val16); + ALLOC(noise_floor, C*nbEBands, opus_val16); + OPUS_CLEAR(offsets, nbEBands); + /* Dynamic allocation code */ + maxDepth=-QCONST16(31.9f, DB_SHIFT); + for (i=0;i=0;i--) + mask[i] = MAX16(mask[i], mask[i+1] - QCONST16(3.f, DB_SHIFT)); + for (i=0;i> shift; + } + /*for (i=0;i 50 && LM>=1 && !lfe) + { + int last=0; + c=0;do + { + opus_val16 offset; + opus_val16 tmp; + opus_val16 *f; + f = &follower[c*nbEBands]; + f[0] = bandLogE2[c*nbEBands]; + for (i=1;i bandLogE2[c*nbEBands+i-1]+QCONST16(.5f,DB_SHIFT)) + last=i; + f[i] = MIN16(f[i-1]+QCONST16(1.5f,DB_SHIFT), bandLogE2[c*nbEBands+i]); + } + for (i=last-1;i>=0;i--) + f[i] = MIN16(f[i], MIN16(f[i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*nbEBands+i])); + + /* Combine with a median filter to avoid dynalloc triggering unnecessarily. + The "offset" value controls how conservative we are -- a higher offset + reduces the impact of the median filter and makes dynalloc use more bits. */ + offset = QCONST16(1.f, DB_SHIFT); + for (i=2;i=12) + follower[i] = HALF16(follower[i]); + } +#ifdef DISABLE_FLOAT_API + (void)analysis; +#else + if (analysis->valid) + { + for (i=start;ileak_boost[i]; + } +#endif + for (i=start;i 48) { + boost = (int)SHR32(EXTEND32(follower[i])*8,DB_SHIFT); + boost_bits = (boost*width<>BITRES>>3 > 2*effectiveBytes/3) + { + opus_int32 cap = ((2*effectiveBytes/3)<mode; + overlap = mode->overlap; + ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig); + + pre[0] = _pre; + pre[1] = _pre + (N+COMBFILTER_MAXPERIOD); + + + c=0; do { + OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); + OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+overlap)+overlap, N); + } while (++c>1, opus_val16); + + pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC, st->arch); + /* Don't search for the fir last 1.5 octave of the range because + there's too many false-positives due to short-term correlation */ + pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N, + COMBFILTER_MAXPERIOD-3*COMBFILTER_MINPERIOD, &pitch_index, + st->arch); + pitch_index = COMBFILTER_MAXPERIOD-pitch_index; + + gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD, + N, &pitch_index, st->prefilter_period, st->prefilter_gain, st->arch); + if (pitch_index > COMBFILTER_MAXPERIOD-2) + pitch_index = COMBFILTER_MAXPERIOD-2; + gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1); + /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st->analysis.tonality);*/ + if (st->loss_rate>2) + gain1 = HALF32(gain1); + if (st->loss_rate>4) + gain1 = HALF32(gain1); + if (st->loss_rate>8) + gain1 = 0; + } else { + gain1 = 0; + pitch_index = COMBFILTER_MINPERIOD; + } +#ifndef DISABLE_FLOAT_API + if (analysis->valid) + gain1 = (opus_val16)(gain1 * analysis->max_pitch_ratio); +#else + (void)analysis; +#endif + /* Gain threshold for enabling the prefilter/postfilter */ + pf_threshold = QCONST16(.2f,15); + + /* Adjusting the threshold based on rate and continuity */ + if (abs(pitch_index-st->prefilter_period)*10>pitch_index) + pf_threshold += QCONST16(.2f,15); + if (nbAvailableBytes<25) + pf_threshold += QCONST16(.1f,15); + if (nbAvailableBytes<35) + pf_threshold += QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.4f,15)) + pf_threshold -= QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.55f,15)) + pf_threshold -= QCONST16(.1f,15); + + /* Hard threshold at 0.2 */ + pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15)); + if (gain1prefilter_gain)prefilter_gain; + +#ifdef FIXED_POINT + qg = ((gain1+1536)>>10)/3-1; +#else + qg = (int)floor(.5f+gain1*32/3)-1; +#endif + qg = IMAX(0, IMIN(7, qg)); + gain1 = QCONST16(0.09375f,15)*(qg+1); + pf_on = 1; + } + /*printf("%d %f\n", pitch_index, gain1);*/ + + c=0; do { + int offset = mode->shortMdctSize-overlap; + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + OPUS_COPY(in+c*(N+overlap), st->in_mem+c*(overlap), overlap); + if (offset) + comb_filter(in+c*(N+overlap)+overlap, pre[c]+COMBFILTER_MAXPERIOD, + st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain, + st->prefilter_tapset, st->prefilter_tapset, NULL, 0, st->arch); + + comb_filter(in+c*(N+overlap)+overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset, + st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1, + st->prefilter_tapset, prefilter_tapset, mode->window, overlap, st->arch); + OPUS_COPY(st->in_mem+c*(overlap), in+c*(N+overlap)+N, overlap); + + if (N>COMBFILTER_MAXPERIOD) + { + OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD); + } else { + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N); + OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N); + } + } while (++cnbEBands; + eBands = mode->eBands; + + coded_bands = lastCodedBands ? lastCodedBands : nbEBands; + coded_bins = eBands[coded_bands]<analysis.activity, st->analysis.tonality, tf_estimate, st->stereo_saving, tot_boost, coded_bands);*/ +#ifndef DISABLE_FLOAT_API + if (analysis->valid && analysis->activity<.4) + target -= (opus_int32)((coded_bins<activity)); +#endif + /* Stereo savings */ + if (C==2) + { + int coded_stereo_bands; + int coded_stereo_dof; + opus_val16 max_frac; + coded_stereo_bands = IMIN(intensity, coded_bands); + coded_stereo_dof = (eBands[coded_stereo_bands]<valid && !lfe) + { + opus_int32 tonal_target; + float tonal; + + /* Tonality boost (compensating for the average). */ + tonal = MAX16(0.f,analysis->tonality-.15f)-0.12f; + tonal_target = target + (opus_int32)((coded_bins<tonality, tonal);*/ + target = tonal_target; + } +#else + (void)analysis; + (void)pitch_change; +#endif + + if (has_surround_mask&&!lfe) + { + opus_int32 surround_target = target + (opus_int32)SHR32(MULT16_16(surround_masking,coded_bins<end, st->intensity, surround_target, target, st->bitrate);*/ + target = IMAX(target/4, surround_target); + } + + { + opus_int32 floor_depth; + int bins; + bins = eBands[nbEBands-2]<>2); + target = IMIN(target, floor_depth); + /*printf("%f %d\n", maxDepth, floor_depth);*/ + } + + /* Make VBR less aggressive for constrained VBR because we can't keep a higher bitrate + for long. Needs tuning. */ + if ((!has_surround_mask||lfe) && constrained_vbr) + { + target = base_target + (opus_int32)MULT16_32_Q15(QCONST16(0.67f, 15), target-base_target); + } + + if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14)) + { + opus_val16 amount; + opus_val16 tvbr_factor; + amount = MULT16_16_Q15(QCONST16(.0000031f, 30), IMAX(0, IMIN(32000, 96000-bitrate))); + tvbr_factor = SHR32(MULT16_16(temporal_vbr, amount), DB_SHIFT); + target += (opus_int32)MULT16_32_Q15(tvbr_factor, target); + } + + /* Don't allow more than doubling the rate */ + target = IMIN(2*base_target, target); + + return target; +} + +int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ + int i, c, N; + opus_int32 bits; + ec_enc _enc; + VARDECL(celt_sig, in); + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(opus_val16, bandLogE); + VARDECL(opus_val16, bandLogE2); + VARDECL(int, fine_quant); + VARDECL(opus_val16, error); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, importance); + VARDECL(int, spread_weight); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *prefilter_mem; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *energyError; + int shortBlocks=0; + int isTransient=0; + const int CC = st->channels; + const int C = st->stream_channels; + int LM, M; + int tf_select; + int nbFilledBytes, nbAvailableBytes; + int start; + int end; + int effEnd; + int codedBands; + int alloc_trim; + int pitch_index=COMBFILTER_MINPERIOD; + opus_val16 gain1 = 0; + int dual_stereo=0; + int effectiveBytes; + int dynalloc_logp; + opus_int32 vbr_rate; + opus_int32 total_bits; + opus_int32 total_boost; + opus_int32 balance; + opus_int32 tell; + opus_int32 tell0_frac; + int prefilter_tapset=0; + int pf_on; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence=0; + int tf_chan = 0; + opus_val16 tf_estimate; + int pitch_change=0; + opus_int32 tot_boost; + opus_val32 sample_max; + opus_val16 maxDepth; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + int secondMdct; + int signalBandwidth; + int transient_got_disabled=0; + opus_val16 surround_masking=0; + opus_val16 temporal_vbr=0; + opus_val16 surround_trim = 0; + opus_int32 equiv_rate; + int hybrid; + int weak_transient = 0; + int enable_tf_analysis; + VARDECL(opus_val16, surround_dynalloc); + ALLOC_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + start = st->start; + end = st->end; + hybrid = start != 0; + tf_estimate = 0; + if (nbCompressedBytes<2 || pcm==NULL) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + frame_size *= st->upsample; + for (LM=0;LM<=mode->maxLM;LM++) + if (mode->shortMdctSize<mode->maxLM) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + M=1<shortMdctSize; + + prefilter_mem = st->in_mem+CC*(overlap); + oldBandE = (opus_val16*)(st->in_mem+CC*(overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + CC*nbEBands; + oldLogE2 = oldLogE + CC*nbEBands; + energyError = oldLogE2 + CC*nbEBands; + + if (enc==NULL) + { + tell0_frac=tell=1; + nbFilledBytes=0; + } else { + tell0_frac=ec_tell_frac(enc); + tell=ec_tell(enc); + nbFilledBytes=(tell+4)>>3; + } + +#ifdef CUSTOM_MODES + if (st->signalling && enc==NULL) + { + int tmp = (mode->effEBands-end)>>1; + end = st->end = IMAX(1, mode->effEBands-tmp); + compressed[0] = tmp<<5; + compressed[0] |= LM<<3; + compressed[0] |= (C==2)<<2; + /* Convert "standard mode" to Opus header */ + if (mode->Fs==48000 && mode->shortMdctSize==120) + { + int c0 = toOpus(compressed[0]); + if (c0<0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + compressed[0] = c0; + } + compressed++; + nbCompressedBytes--; + } +#else + celt_assert(st->signalling==0); +#endif + + /* Can't produce more than 1275 output bytes */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275); + nbAvailableBytes = nbCompressedBytes - nbFilledBytes; + + if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX) + { + opus_int32 den=mode->Fs>>BITRES; + vbr_rate=(st->bitrate*frame_size+(den>>1))/den; +#ifdef CUSTOM_MODES + if (st->signalling) + vbr_rate -= 8<>(3+BITRES); + } else { + opus_int32 tmp; + vbr_rate = 0; + tmp = st->bitrate*frame_size; + if (tell>1) + tmp += tell; + if (st->bitrate!=OPUS_BITRATE_MAX) + nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, + (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling)); + effectiveBytes = nbCompressedBytes - nbFilledBytes; + } + equiv_rate = ((opus_int32)nbCompressedBytes*8*50 >> (3-LM)) - (40*C+20)*((400>>LM) - 50); + if (st->bitrate != OPUS_BITRATE_MAX) + equiv_rate = IMIN(equiv_rate, st->bitrate - (40*C+20)*((400>>LM) - 50)); + + if (enc==NULL) + { + ec_enc_init(&_enc, compressed, nbCompressedBytes); + enc = &_enc; + } + + if (vbr_rate>0) + { + /* Computes the max bit-rate allowed in VBR mode to avoid violating the + target rate and buffering. + We must do this up front so that bust-prevention logic triggers + correctly if we don't have enough bits. */ + if (st->constrained_vbr) + { + opus_int32 vbr_bound; + opus_int32 max_allowed; + /* We could use any multiple of vbr_rate as bound (depending on the + delay). + This is clamped to ensure we use at least two bytes if the encoder + was entirely empty, but to allow 0 in hybrid mode. */ + vbr_bound = vbr_rate; + max_allowed = IMIN(IMAX(tell==1?2:0, + (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)), + nbAvailableBytes); + if(max_allowed < nbAvailableBytes) + { + nbCompressedBytes = nbFilledBytes+max_allowed; + nbAvailableBytes = max_allowed; + ec_enc_shrink(enc, nbCompressedBytes); + } + } + } + total_bits = nbCompressedBytes*8; + + effEnd = end; + if (effEnd > mode->effEBands) + effEnd = mode->effEBands; + + ALLOC(in, CC*(N+overlap), celt_sig); + + sample_max=MAX32(st->overlap_max, celt_maxabs16(pcm, C*(N-overlap)/st->upsample)); + st->overlap_max=celt_maxabs16(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample); + sample_max=MAX32(sample_max, st->overlap_max); +#ifdef FIXED_POINT + silence = (sample_max==0); +#else + silence = (sample_max <= (opus_val16)1/(1<lsb_depth)); +#endif +#ifdef FUZZING + if ((rand()&0x3F)==0) + silence = 1; +#endif + if (tell==1) + ec_enc_bit_logp(enc, silence, 15); + else + silence=0; + if (silence) + { + /*In VBR mode there is no need to send more than the minimum. */ + if (vbr_rate>0) + { + effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2); + total_bits=nbCompressedBytes*8; + nbAvailableBytes=2; + ec_enc_shrink(enc, nbCompressedBytes); + } + /* Pretend we've filled all the remaining bits with zeros + (that's what the initialiser did anyway) */ + tell = nbCompressedBytes*8; + enc->nbits_total+=tell-ec_tell(enc); + } + c=0; do { + int need_clip=0; +#ifndef FIXED_POINT + need_clip = st->clip && sample_max>65536.f; +#endif + celt_preemphasis(pcm+c, in+c*(N+overlap)+overlap, N, CC, st->upsample, + mode->preemph, st->preemph_memE+c, need_clip); + } while (++clfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && !hybrid && !silence && !st->disable_pf + && st->complexity >= 5; + + prefilter_tapset = st->tapset_decision; + pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes, &st->analysis); + if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3) + && (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period)) + pitch_change = 1; + if (pf_on==0) + { + if(!hybrid && tell+16<=total_bits) + ec_enc_bit_logp(enc, 0, 1); + } else { + /*This block is not gated by a total bits check only because + of the nbAvailableBytes check above.*/ + int octave; + ec_enc_bit_logp(enc, 1, 1); + pitch_index += 1; + octave = EC_ILOG(pitch_index)-5; + ec_enc_uint(enc, octave, 6); + ec_enc_bits(enc, pitch_index-(16<complexity >= 1 && !st->lfe) + { + /* Reduces the likelihood of energy instability on fricatives at low bitrate + in hybrid mode. It seems like we still want to have real transients on vowels + though (small SILK quantization offset value). */ + int allow_weak_transients = hybrid && effectiveBytes<15 && st->silk_info.signalType != 2; + isTransient = transient_analysis(in, N+overlap, CC, + &tf_estimate, &tf_chan, allow_weak_transients, &weak_transient); + } + if (LM>0 && ec_tell(enc)+3<=total_bits) + { + if (isTransient) + shortBlocks = M; + } else { + isTransient = 0; + transient_got_disabled=1; + } + + ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(bandE,nbEBands*CC, celt_ener); + ALLOC(bandLogE,nbEBands*CC, opus_val16); + + secondMdct = shortBlocks && st->complexity>=8; + ALLOC(bandLogE2, C*nbEBands, opus_val16); + if (secondMdct) + { + compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample, st->arch); + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + amp2Log2(mode, effEnd, end, bandE, bandLogE2, C); + for (i=0;iupsample, st->arch); + /* This should catch any NaN in the CELT input. Since we're not supposed to see any (they're filtered + at the Opus layer), just abort. */ + celt_assert(!celt_isnan(freq[0]) && (C==1 || !celt_isnan(freq[N]))); + if (CC==2&&C==1) + tf_chan = 0; + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + + if (st->lfe) + { + for (i=2;ienergy_mask&&!st->lfe) + { + int mask_end; + int midband; + int count_dynalloc; + opus_val32 mask_avg=0; + opus_val32 diff=0; + int count=0; + mask_end = IMAX(2,st->lastCodedBands); + for (c=0;cenergy_mask[nbEBands*c+i], + QCONST16(.25f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT)); + if (mask > 0) + mask = HALF16(mask); + mask_avg += MULT16_16(mask, eBands[i+1]-eBands[i]); + count += eBands[i+1]-eBands[i]; + diff += MULT16_16(mask, 1+2*i-mask_end); + } + } + celt_assert(count>0); + mask_avg = DIV32_16(mask_avg,count); + mask_avg += QCONST16(.2f, DB_SHIFT); + diff = diff*6/(C*(mask_end-1)*(mask_end+1)*mask_end); + /* Again, being conservative */ + diff = HALF32(diff); + diff = MAX32(MIN32(diff, QCONST32(.031f, DB_SHIFT)), -QCONST32(.031f, DB_SHIFT)); + /* Find the band that's in the middle of the coded spectrum */ + for (midband=0;eBands[midband+1] < eBands[mask_end]/2;midband++); + count_dynalloc=0; + for(i=0;ienergy_mask[i], st->energy_mask[nbEBands+i]); + else + unmask = st->energy_mask[i]; + unmask = MIN16(unmask, QCONST16(.0f, DB_SHIFT)); + unmask -= lin; + if (unmask > QCONST16(.25f, DB_SHIFT)) + { + surround_dynalloc[i] = unmask - QCONST16(.25f, DB_SHIFT); + count_dynalloc++; + } + } + if (count_dynalloc>=3) + { + /* If we need dynalloc in many bands, it's probably because our + initial masking rate was too low. */ + mask_avg += QCONST16(.25f, DB_SHIFT); + if (mask_avg>0) + { + /* Something went really wrong in the original calculations, + disabling masking. */ + mask_avg = 0; + diff = 0; + OPUS_CLEAR(surround_dynalloc, mask_end); + } else { + for(i=0;ilfe) + { + opus_val16 follow=-QCONST16(10.0f,DB_SHIFT); + opus_val32 frame_avg=0; + opus_val16 offset = shortBlocks?HALF16(SHL16(LM, DB_SHIFT)):0; + for(i=start;ispec_avg); + temporal_vbr = MIN16(QCONST16(3.f, DB_SHIFT), MAX16(-QCONST16(1.5f, DB_SHIFT), temporal_vbr)); + st->spec_avg += MULT16_16_Q15(QCONST16(.02f, 15), temporal_vbr); + } + /*for (i=0;i<21;i++) + printf("%f ", bandLogE[i]); + printf("\n");*/ + + if (!secondMdct) + { + OPUS_COPY(bandLogE2, bandLogE, C*nbEBands); + } + + /* Last chance to catch any transient we might have missed in the + time-domain analysis */ + if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe && !hybrid) + { + if (patch_transient_decision(bandLogE, oldBandE, nbEBands, start, end, C)) + { + isTransient = 1; + shortBlocks = M; + compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch); + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + amp2Log2(mode, effEnd, end, bandE, bandLogE, C); + /* Compensate for the scaling of short vs long mdcts */ + for (i=0;i0 && ec_tell(enc)+3<=total_bits) + ec_enc_bit_logp(enc, isTransient, 3); + + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + + /* Band normalisation */ + normalise_bands(mode, freq, X, bandE, effEnd, C, M); + + enable_tf_analysis = effectiveBytes>=15*C && !hybrid && st->complexity>=2 && !st->lfe; + + ALLOC(offsets, nbEBands, int); + ALLOC(importance, nbEBands, int); + ALLOC(spread_weight, nbEBands, int); + + maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets, + st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr, + eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc, &st->analysis, importance, spread_weight); + + ALLOC(tf_res, nbEBands, int); + /* Disable variable tf resolution for hybrid and at very low bitrate */ + if (enable_tf_analysis) + { + int lambda; + lambda = IMAX(80, 20480/effectiveBytes + 2); + tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, tf_estimate, tf_chan, importance); + for (i=effEnd;isilk_info.signalType != 2) + { + /* For low bitrate hybrid, we force temporal resolution to 5 ms rather than 2.5 ms. */ + for (i=0;iforce_intra, + &st->delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe); + + tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc); + + if (ec_tell(enc)+4<=total_bits) + { + if (st->lfe) + { + st->tapset_decision = 0; + st->spread_decision = SPREAD_NORMAL; + } else if (hybrid) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else if (isTransient) + st->spread_decision = SPREAD_NORMAL; + else + st->spread_decision = SPREAD_AGGRESSIVE; + } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else + st->spread_decision = SPREAD_NORMAL; + } else { + /* Disable new spreading+tapset estimator until we can show it works + better than the old one. So far it seems like spreading_decision() + works best. */ +#if 0 + if (st->analysis.valid) + { + static const opus_val16 spread_thresholds[3] = {-QCONST16(.6f, 15), -QCONST16(.2f, 15), -QCONST16(.07f, 15)}; + static const opus_val16 spread_histeresis[3] = {QCONST16(.15f, 15), QCONST16(.07f, 15), QCONST16(.02f, 15)}; + static const opus_val16 tapset_thresholds[2] = {QCONST16(.0f, 15), QCONST16(.15f, 15)}; + static const opus_val16 tapset_histeresis[2] = {QCONST16(.1f, 15), QCONST16(.05f, 15)}; + st->spread_decision = hysteresis_decision(-st->analysis.tonality, spread_thresholds, spread_histeresis, 3, st->spread_decision); + st->tapset_decision = hysteresis_decision(st->analysis.tonality_slope, tapset_thresholds, tapset_histeresis, 2, st->tapset_decision); + } else +#endif + { + st->spread_decision = spreading_decision(mode, X, + &st->tonal_average, st->spread_decision, &st->hf_average, + &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M, spread_weight); + } + /*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/ + /*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/ + } + ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5); + } + + /* For LFE, everything interesting is in the first band */ + if (st->lfe) + offsets[0] = IMIN(8, effectiveBytes/3); + ALLOC(cap, nbEBands, int); + init_caps(mode,cap,LM,C); + + dynalloc_logp = 6; + total_bits<<=BITRES; + total_boost = 0; + tell = ec_tell_frac(enc); + for (i=start;iintensity = hysteresis_decision((opus_val16)(equiv_rate/1000), + intensity_thresholds, intensity_histeresis, 21, st->intensity); + st->intensity = IMIN(end,IMAX(start, st->intensity)); + } + + alloc_trim = 5; + if (tell+(6< 0 || st->lfe) + { + st->stereo_saving = 0; + alloc_trim = 5; + } else { + alloc_trim = alloc_trim_analysis(mode, X, bandLogE, + end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate, + st->intensity, surround_trim, equiv_rate, st->arch); + } + ec_enc_icdf(enc, alloc_trim, trim_icdf, 7); + tell = ec_tell_frac(enc); + } + + /* Variable bitrate */ + if (vbr_rate>0) + { + opus_val16 alpha; + opus_int32 delta; + /* The target rate in 8th bits per frame */ + opus_int32 target, base_target; + opus_int32 min_allowed; + int lm_diff = mode->maxLM - LM; + + /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms. + The CELT allocator will just not be able to use more than that anyway. */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM)); + if (!hybrid) + { + base_target = vbr_rate - ((40*C+20)<constrained_vbr) + base_target += (st->vbr_offset>>lm_diff); + + if (!hybrid) + { + target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate, + st->lastCodedBands, C, st->intensity, st->constrained_vbr, + st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth, + st->lfe, st->energy_mask!=NULL, surround_masking, + temporal_vbr); + } else { + target = base_target; + /* Tonal frames (offset<100) need more bits than noisy (offset>100) ones. */ + if (st->silk_info.offset < 100) target += 12 << BITRES >> (3-LM); + if (st->silk_info.offset > 100) target -= 18 << BITRES >> (3-LM); + /* Boosting bitrate on transients and vowels with significant temporal + spikes. */ + target += (opus_int32)MULT16_16_Q14(tf_estimate-QCONST16(.25f,14), (50< QCONST16(.7f,14)) + target = IMAX(target, 50<>(BITRES+3)) + 2; + /* Take into account the 37 bits we need to have left in the packet to + signal a redundant frame in hybrid mode. Creating a shorter packet would + create an entropy coder desync. */ + if (hybrid) + min_allowed = IMAX(min_allowed, (tell0_frac+(37<>(BITRES+3)); + + nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3); + nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes); + nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + + /* By how much did we "miss" the target on that frame */ + delta = target - vbr_rate; + + target=nbAvailableBytes<<(BITRES+3); + + /*If the frame is silent we don't adjust our drift, otherwise + the encoder will shoot to very high rates after hitting a + span of silence, but we do allow the bitres to refill. + This means that we'll undershoot our target in CVBR/VBR modes + on files with lots of silence. */ + if(silence) + { + nbAvailableBytes = 2; + target = 2*8<vbr_count < 970) + { + st->vbr_count++; + alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16)); + } else + alpha = QCONST16(.001f,15); + /* How many bits have we used in excess of what we're allowed */ + if (st->constrained_vbr) + st->vbr_reservoir += target - vbr_rate; + /*printf ("%d\n", st->vbr_reservoir);*/ + + /* Compute the offset we need to apply in order to reach the target */ + if (st->constrained_vbr) + { + st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<vbr_offset-st->vbr_drift); + st->vbr_offset = -st->vbr_drift; + } + /*printf ("%d\n", st->vbr_drift);*/ + + if (st->constrained_vbr && st->vbr_reservoir < 0) + { + /* We're under the min value -- increase rate */ + int adjust = (-st->vbr_reservoir)/(8<vbr_reservoir = 0; + /*printf ("+%d\n", adjust);*/ + } + nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + /*printf("%d\n", nbCompressedBytes*50*8);*/ + /* This moves the raw bits to take into account the new compressed size */ + ec_enc_shrink(enc, nbCompressedBytes); + } + + /* Bit allocation */ + ALLOC(fine_quant, nbEBands, int); + ALLOC(pulses, nbEBands, int); + ALLOC(fine_priority, nbEBands, int); + + /* bits = packet size - where we are - safety*/ + bits = (((opus_int32)nbCompressedBytes*8)<=2&&bits>=((LM+2)<analysis.valid) + { + int min_bandwidth; + if (equiv_rate < (opus_int32)32000*C) + min_bandwidth = 13; + else if (equiv_rate < (opus_int32)48000*C) + min_bandwidth = 16; + else if (equiv_rate < (opus_int32)60000*C) + min_bandwidth = 18; + else if (equiv_rate < (opus_int32)80000*C) + min_bandwidth = 19; + else + min_bandwidth = 20; + signalBandwidth = IMAX(st->analysis.bandwidth, min_bandwidth); + } +#endif + if (st->lfe) + signalBandwidth = 1; + codedBands = clt_compute_allocation(mode, start, end, offsets, cap, + alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth); + if (st->lastCodedBands) + st->lastCodedBands = IMIN(st->lastCodedBands+1,IMAX(st->lastCodedBands-1,codedBands)); + else + st->lastCodedBands = codedBands; + + quant_fine_energy(mode, start, end, oldBandE, error, fine_quant, enc, C); + + /* Residual quantisation */ + ALLOC(collapse_masks, C*nbEBands, unsigned char); + quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks, + bandE, pulses, shortBlocks, st->spread_decision, + dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<rng, st->complexity, st->arch, st->disable_inv); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = st->consec_transient<2; +#ifdef FUZZING + anti_collapse_on = rand()&0x1; +#endif + ec_enc_bits(enc, anti_collapse_on, 1); + } + quant_energy_finalise(mode, start, end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C); + OPUS_CLEAR(energyError, nbEBands*CC); + c=0; + do { + for (i=start;irng); + } + + c=0; do { + OPUS_MOVE(st->syn_mem[c], st->syn_mem[c]+N, 2*MAX_PERIOD-N+overlap/2); + } while (++csyn_mem[c]+2*MAX_PERIOD-N; + } while (++cupsample, silence, st->arch); + + c=0; do { + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, mode->shortMdctSize, + st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset, + mode->window, overlap); + if (LM!=0) + comb_filter(out_mem[c]+mode->shortMdctSize, out_mem[c]+mode->shortMdctSize, st->prefilter_period, pitch_index, N-mode->shortMdctSize, + st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset, + mode->window, overlap); + } while (++cupsample, mode->preemph, st->preemph_memD); + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + st->prefilter_period = pitch_index; + st->prefilter_gain = gain1; + st->prefilter_tapset = prefilter_tapset; +#ifdef RESYNTH + if (LM!=0) + { + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + if (CC==2&&C==1) { + OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); + } + + if (!isTransient) + { + OPUS_COPY(oldLogE2, oldLogE, CC*nbEBands); + OPUS_COPY(oldLogE, oldBandE, CC*nbEBands); + } else { + for (i=0;iconsec_transient++; + else + st->consec_transient=0; + st->rng = enc->rng; + + /* If there's any room left (can only happen for very high rates), + it's already filled with zeros */ + ec_enc_done(enc); + +#ifdef CUSTOM_MODES + if (st->signalling) + nbCompressedBytes++; +#endif + + RESTORE_STACK; + if (ec_get_error(enc)) + return OPUS_INTERNAL_ERROR; + else + return nbCompressedBytes; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + int j, ret, C, N; + VARDECL(opus_int16, in); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + ALLOC(in, C*N, opus_int16); + + for (j=0;jchannels; + N=frame_size; + ALLOC(in, C*N, celt_sig); + for (j=0;j10) + goto bad_arg; + st->complexity = value; + } + break; + case CELT_SET_START_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<0 || value>=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_PREDICTION_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>2) + goto bad_arg; + st->disable_pf = value<=1; + st->force_intra = value==0; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>100) + goto bad_arg; + st->loss_rate = value; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->constrained_vbr = value; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->vbr = value; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<=500 && value!=OPUS_BITRATE_MAX) + goto bad_arg; + value = IMIN(value, 260000*st->channels); + st->bitrate = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + goto bad_arg; + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value=st->lsb_depth; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->disable_inv = value; + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->disable_inv; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; + oldBandE = (opus_val16*)(st->in_mem+st->channels*(st->mode->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + st->channels*st->mode->nbEBands; + oldLogE2 = oldLogE + st->channels*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->ENCODER_RESET_START, + opus_custom_encoder_get_size(st->mode, st->channels)- + ((char*)&st->ENCODER_RESET_START - (char*)st)); + for (i=0;ichannels*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->vbr_offset = 0; + st->delayedIntra = 1; + st->spread_decision = SPREAD_NORMAL; + st->tonal_average = 256; + st->hf_average = 0; + st->tapset_decision = 0; + } + break; +#ifdef CUSTOM_MODES + case CELT_SET_INPUT_CLIPPING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->clip = value; + } + break; +#endif + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case CELT_SET_ANALYSIS_REQUEST: + { + AnalysisInfo *info = va_arg(ap, AnalysisInfo *); + if (info) + OPUS_COPY(&st->analysis, info, 1); + } + break; + case CELT_SET_SILK_INFO_REQUEST: + { + SILKInfo *info = va_arg(ap, SILKInfo *); + if (info) + OPUS_COPY(&st->silk_info, info, 1); + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + case OPUS_SET_LFE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->lfe = value; + } + break; + case OPUS_SET_ENERGY_MASK_REQUEST: + { + opus_val16 *value = va_arg(ap, opus_val16*); + st->energy_mask = value; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} diff --git a/native/codec/libraries/opus/celt/celt_lpc.c b/native/codec/libraries/opus/celt/celt_lpc.c new file mode 100644 index 0000000..8ecb693 --- /dev/null +++ b/native/codec/libraries/opus/celt/celt_lpc.c @@ -0,0 +1,296 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +void _celt_lpc( + opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */ +const opus_val32 *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + opus_val32 r; + opus_val32 error = ac[0]; +#ifdef FIXED_POINT + opus_val32 lpc[LPC_ORDER]; +#else + float *lpc = _lpc; +#endif + + OPUS_CLEAR(lpc, p); + if (ac[0] != 0) + { + for (i = 0; i < p; i++) { + /* Sum up this iteration's reflection coefficient */ + opus_val32 rr = 0; + for (j = 0; j < i; j++) + rr += MULT32_32_Q31(lpc[j],ac[i - j]); + rr += SHR32(ac[i + 1],3); + r = -frac_div32(SHL32(rr,3), error); + /* Update LPC coefficients and total error */ + lpc[i] = SHR32(r,3); + for (j = 0; j < (i+1)>>1; j++) + { + opus_val32 tmp1, tmp2; + tmp1 = lpc[j]; + tmp2 = lpc[i-1-j]; + lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2); + lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1); + } + + error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error); + /* Bail out once we get 30 dB gain */ +#ifdef FIXED_POINT + if (error=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = SROUND16(sum, SIG_SHIFT); + _y[i] = sum; + } +#else + int i,j; + VARDECL(opus_val16, rden); + VARDECL(opus_val16, y); + SAVE_STACK; + + celt_assert((ord&3)==0); + ALLOC(rden, ord, opus_val16); + ALLOC(y, N+ord, opus_val16); + for(i=0;i0); + celt_assert(overlap>=0); + if (overlap == 0) + { + xptr = x; + } else { + for (i=0;i0) + { + for(i=0;i= 536870912) + { + int shift2=1; + if (ac[0] >= 1073741824) + shift2++; + for (i=0;i<=lag;i++) + ac[i] = SHR32(ac[i], shift2); + shift += shift2; + } +#endif + + RESTORE_STACK; + return shift; +} diff --git a/native/codec/libraries/opus/celt/celt_lpc.h b/native/codec/libraries/opus/celt/celt_lpc.h new file mode 100644 index 0000000..a4c5fd6 --- /dev/null +++ b/native/codec/libraries/opus/celt/celt_lpc.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PLC_H +#define PLC_H + +#include "arch.h" +#include "cpu_support.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/celt_lpc_sse.h" +#endif + +#define LPC_ORDER 24 + +void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p); + +void celt_fir_c( + const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + int arch); + +#if !defined(OVERRIDE_CELT_FIR) +#define celt_fir(x, num, y, N, ord, arch) \ + (celt_fir_c(x, num, y, N, ord, arch)) +#endif + +void celt_iir(const opus_val32 *x, + const opus_val16 *den, + opus_val32 *y, + int N, + int ord, + opus_val16 *mem, + int arch); + +int _celt_autocorr(const opus_val16 *x, opus_val32 *ac, + const opus_val16 *window, int overlap, int lag, int n, int arch); + +#endif /* PLC_H */ diff --git a/native/codec/libraries/opus/celt/cpu_support.h b/native/codec/libraries/opus/celt/cpu_support.h new file mode 100644 index 0000000..68fc606 --- /dev/null +++ b/native/codec/libraries/opus/celt/cpu_support.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CPU_SUPPORT_H +#define CPU_SUPPORT_H + +#include "opus_types.h" +#include "opus_defines.h" + +#if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/armcpu.h" + +/* We currently support 4 ARM variants: + * arch[0] -> ARMv4 + * arch[1] -> ARMv5E + * arch[2] -> ARMv6 + * arch[3] -> NEON + */ +#define OPUS_ARCHMASK 3 + +#elif (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)) || \ + (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)) || \ + (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \ + (defined(OPUS_X86_MAY_HAVE_AVX) && !defined(OPUS_X86_PRESUME_AVX)) + +#include "x86/x86cpu.h" +/* We currently support 5 x86 variants: + * arch[0] -> non-sse + * arch[1] -> sse + * arch[2] -> sse2 + * arch[3] -> sse4.1 + * arch[4] -> avx + */ +#define OPUS_ARCHMASK 7 +int opus_select_arch(void); + +#else +#define OPUS_ARCHMASK 0 + +static OPUS_INLINE int opus_select_arch(void) +{ + return 0; +} +#endif +#endif diff --git a/native/codec/libraries/opus/celt/cwrs.c b/native/codec/libraries/opus/celt/cwrs.c new file mode 100644 index 0000000..a552e4f --- /dev/null +++ b/native/codec/libraries/opus/celt/cwrs.c @@ -0,0 +1,715 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include "cwrs.h" +#include "mathops.h" +#include "arch.h" + +#ifdef CUSTOM_MODES + +/*Guaranteed to return a conservatively large estimate of the binary logarithm + with frac bits of fractional precision. + Tested for all possible 32-bit inputs with frac=4, where the maximum + overestimation is 0.06254243 bits.*/ +int log2_frac(opus_uint32 val, int frac) +{ + int l; + l=EC_ILOG(val); + if(val&(val-1)){ + /*This is (val>>l-16), but guaranteed to round up, even if adding a bias + before the shift would cause overflow (e.g., for 0xFFFFxxxx). + Doesn't work for val=0, but that case fails the test above.*/ + if(l>16)val=((val-1)>>(l-16))+1; + else val<<=16-l; + l=(l-1)<>16); + l+=b<>b; + val=(val*val+0x7FFF)>>15; + } + while(frac-->0); + /*If val is not exactly 0x8000, then we have to round up the remainder.*/ + return l+(val>0x8000); + } + /*Exact powers of two require no rounding.*/ + else return (l-1)<0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1, + where choose() is the binomial function. + A table of values for N<10 and K<10 looks like: + V[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, + {1, 4, 8, 12, 16, 20, 24, 28, 32, 36}, + {1, 6, 18, 38, 66, 102, 146, 198, 258, 326}, + {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992}, + {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290}, + {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436}, + {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598}, + {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688}, + {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146} + }; + + U(N,K) = the number of such combinations wherein N-1 objects are taken at + most K-1 at a time. + This is given by + U(N,K) = sum(k=0...K-1,V(N-1,k)) + = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0. + The latter expression also makes clear that U(N,K) is half the number of such + combinations wherein the first object is taken at least once. + Although it may not be clear from either of these definitions, U(N,K) is the + natural function to work with when enumerating the pulse vector codebooks, + not V(N,K). + U(N,K) is not well-defined for N=0, but with the extension + U(0,K) = K>0 ? 0 : 1, + the function becomes symmetric: U(N,K) = U(K,N), with a similar table: + U[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 1, 3, 5, 7, 9, 11, 13, 15, 17}, + {0, 1, 5, 13, 25, 41, 61, 85, 113, 145}, + {0, 1, 7, 25, 63, 129, 231, 377, 575, 833}, + {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649}, + {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073}, + {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081}, + {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545}, + {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729} + }; + + With this extension, V(N,K) may be written in terms of U(N,K): + V(N,K) = U(N,K) + U(N,K+1) + for all N>=0, K>=0. + Thus U(N,K+1) represents the number of combinations where the first element + is positive or zero, and U(N,K) represents the number of combinations where + it is negative. + With a large enough table of U(N,K) values, we could write O(N) encoding + and O(min(N*log(K),N+K)) decoding routines, but such a table would be + prohibitively large for small embedded devices (K may be as large as 32767 + for small N, and N may be as large as 200). + + Both functions obey the same recurrence relation: + V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), + U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1), + for all N>0, K>0, with different initial conditions at N=0 or K=0. + This allows us to construct a row of one of the tables above given the + previous row or the next row. + Thus we can derive O(NK) encoding and decoding routines with O(K) memory + using only addition and subtraction. + + When encoding, we build up from the U(2,K) row and work our way forwards. + When decoding, we need to start at the U(N,K) row and work our way backwards, + which requires a means of computing U(N,K). + U(N,K) may be computed from two previous values with the same N: + U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2) + for all N>1, and since U(N,K) is symmetric, a similar relation holds for two + previous values with the same K: + U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K) + for all K>1. + This allows us to construct an arbitrary row of the U(N,K) table by starting + with the first two values, which are constants. + This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K) + multiplications. + Similar relations can be derived for V(N,K), but are not used here. + + For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree + polynomial for fixed N. + The first few are + U(1,K) = 1, + U(2,K) = 2*K-1, + U(3,K) = (2*K-2)*K+1, + U(4,K) = (((4*K-6)*K+8)*K-3)/3, + U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3, + and + V(1,K) = 2, + V(2,K) = 4*K, + V(3,K) = 4*K*K+2, + V(4,K) = 8*(K*K+2)*K/3, + V(5,K) = ((4*K*K+20)*K*K+6)/3, + for all K>0. + This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for + small N (and indeed decoding is also O(N) for N<3). + + @ARTICLE{Fis86, + author="Thomas R. Fischer", + title="A Pyramid Vector Quantizer", + journal="IEEE Transactions on Information Theory", + volume="IT-32", + number=4, + pages="568--583", + month=Jul, + year=1986 + }*/ + +#if !defined(SMALL_FOOTPRINT) + +/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/ +# define CELT_PVQ_U(_n,_k) (CELT_PVQ_U_ROW[IMIN(_n,_k)][IMAX(_n,_k)]) +/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N + with K pulses allocated to it.*/ +# define CELT_PVQ_V(_n,_k) (CELT_PVQ_U(_n,_k)+CELT_PVQ_U(_n,(_k)+1)) + +/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)). + Thus, the number of entries in row I is the larger of the maximum number of + pulses we will ever allocate for a given N=I (K=128, or however many fit in + 32 bits, whichever is smaller), plus one, and the maximum N for which + K=I-1 pulses fit in 32 bits. + The largest band size in an Opus Custom mode is 208. + Otherwise, we can limit things to the set of N which can be achieved by + splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48, + 44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/ +#if defined(CUSTOM_MODES) +static const opus_uint32 CELT_PVQ_U_DATA[1488]={ +#else +static const opus_uint32 CELT_PVQ_U_DATA[1272]={ +#endif + /*N=0, K=0...176:*/ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#if defined(CUSTOM_MODES) + /*...208:*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +#endif + /*N=1, K=1...176:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +#if defined(CUSTOM_MODES) + /*...208:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, +#endif + /*N=2, K=2...176:*/ + 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, + 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, + 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, + 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, + 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, + 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, + 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, + 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, + 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, + 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, + 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, +#if defined(CUSTOM_MODES) + /*...208:*/ + 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, + 383, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 411, + 413, 415, +#endif + /*N=3, K=3...176:*/ + 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613, + 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861, + 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785, + 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385, + 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661, + 9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961, + 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745, + 17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013, + 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765, + 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001, + 31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721, + 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925, + 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613, + 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785, + 57461, 58141, 58825, 59513, 60205, 60901, 61601, +#if defined(CUSTOM_MODES) + /*...208:*/ + 62305, 63013, 63725, 64441, 65161, 65885, 66613, 67345, 68081, 68821, 69565, + 70313, 71065, 71821, 72581, 73345, 74113, 74885, 75661, 76441, 77225, 78013, + 78805, 79601, 80401, 81205, 82013, 82825, 83641, 84461, 85285, 86113, +#endif + /*N=4, K=4...176:*/ + 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017, + 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775, + 30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153, + 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193, + 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575, + 267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217, + 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951, + 597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609, + 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023, + 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407, + 1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759, + 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175, + 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751, + 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583, + 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767, + 3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399, + 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575, + 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391, + 6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943, + 7085049, 7207551, +#if defined(CUSTOM_MODES) + /*...208:*/ + 7331457, 7456775, 7583513, 7711679, 7841281, 7972327, 8104825, 8238783, + 8374209, 8511111, 8649497, 8789375, 8930753, 9073639, 9218041, 9363967, + 9511425, 9660423, 9810969, 9963071, 10116737, 10271975, 10428793, 10587199, + 10747201, 10908807, 11072025, 11236863, 11403329, 11571431, 11741177, + 11912575, +#endif + /*N=5, K=5...176:*/ + 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041, + 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401, + 330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241, + 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241, + 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801, + 4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849, + 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849, + 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809, + 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881, + 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641, + 40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081, + 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609, + 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049, + 95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641, + 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041, + 155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321, + 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969, + 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889, + 290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401, + 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241, + 420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561, + 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929, + 590359041, 604167209, 618216201, 632508801, +#if defined(CUSTOM_MODES) + /*...208:*/ + 647047809, 661836041, 676876329, 692171521, 707724481, 723538089, 739615241, + 755958849, 772571841, 789457161, 806617769, 824056641, 841776769, 859781161, + 878072841, 896654849, 915530241, 934702089, 954173481, 973947521, 994027329, + 1014416041, 1035116809, 1056132801, 1077467201, 1099123209, 1121104041, + 1143412929, 1166053121, 1189027881, 1212340489, 1235994241, +#endif + /*N=6, K=6...96:*/ + 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047, + 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409, + 2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793, + 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455, + 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189, + 64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651, + 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185, + 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647, + 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229, + 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283, + 1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135, + 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187, + 2011371957, 2120032959, +#if defined(CUSTOM_MODES) + /*...109:*/ + 2233340609U, 2351442379U, 2474488829U, 2602633639U, 2736033641U, 2874848851U, + 3019242501U, 3169381071U, 3325434321U, 3487575323U, 3655980493U, 3830829623U, + 4012305913U, +#endif + /*N=7, K=7...54*/ + 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777, + 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233, + 19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013, + 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805, + 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433, + 793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821, + 1667010073, 1870535785, 2094367717, +#if defined(CUSTOM_MODES) + /*...60:*/ + 2340095869U, 2609401873U, 2904062449U, 3225952925U, 3577050821U, 3959439497U, +#endif + /*N=8, K=8...37*/ + 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767, + 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017, + 104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351, + 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615, + 2229491905U, +#if defined(CUSTOM_MODES) + /*...40:*/ + 2691463695U, 3233240945U, 3866006015U, +#endif + /*N=9, K=9...28:*/ + 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777, + 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145, + 628496897, 872893441, 1196924561, 1621925137, 2173806145U, +#if defined(CUSTOM_MODES) + /*...29:*/ + 2883810113U, +#endif + /*N=10, K=10...24:*/ + 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073, + 254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U, + 3375210671U, + /*N=11, K=11...19:*/ + 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585, + 948062325, 1616336765, +#if defined(CUSTOM_MODES) + /*...20:*/ + 2684641785U, +#endif + /*N=12, K=12...18:*/ + 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185, + 3248227095U, + /*N=13, K=13...16:*/ + 251595969, 579168825, 1267854873, 2653649025U, + /*N=14, K=14:*/ + 1409933619 +}; + +#if defined(CUSTOM_MODES) +static const opus_uint32 *const CELT_PVQ_U_ROW[15]={ + CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 208,CELT_PVQ_U_DATA+ 415, + CELT_PVQ_U_DATA+ 621,CELT_PVQ_U_DATA+ 826,CELT_PVQ_U_DATA+1030, + CELT_PVQ_U_DATA+1233,CELT_PVQ_U_DATA+1336,CELT_PVQ_U_DATA+1389, + CELT_PVQ_U_DATA+1421,CELT_PVQ_U_DATA+1441,CELT_PVQ_U_DATA+1455, + CELT_PVQ_U_DATA+1464,CELT_PVQ_U_DATA+1470,CELT_PVQ_U_DATA+1473 +}; +#else +static const opus_uint32 *const CELT_PVQ_U_ROW[15]={ + CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 176,CELT_PVQ_U_DATA+ 351, + CELT_PVQ_U_DATA+ 525,CELT_PVQ_U_DATA+ 698,CELT_PVQ_U_DATA+ 870, + CELT_PVQ_U_DATA+1041,CELT_PVQ_U_DATA+1131,CELT_PVQ_U_DATA+1178, + CELT_PVQ_U_DATA+1207,CELT_PVQ_U_DATA+1226,CELT_PVQ_U_DATA+1240, + CELT_PVQ_U_DATA+1248,CELT_PVQ_U_DATA+1254,CELT_PVQ_U_DATA+1257 +}; +#endif + +#if defined(CUSTOM_MODES) +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + for(k=1;k<=_maxk;k++)_bits[k]=log2_frac(CELT_PVQ_V(_n,k),_frac); +} +#endif + +static opus_uint32 icwrs(int _n,const int *_y){ + opus_uint32 i; + int j; + int k; + celt_assert(_n>=2); + j=_n-1; + i=_y[j]<0; + k=abs(_y[j]); + do{ + j--; + i+=CELT_PVQ_U(_n-j,k); + k+=abs(_y[j]); + if(_y[j]<0)i+=CELT_PVQ_U(_n-j,k+1); + } + while(j>0); + return i; +} + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + celt_assert(_k>0); + ec_enc_uint(_enc,icwrs(_n,_y),CELT_PVQ_V(_n,_k)); +} + +static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int k0; + opus_int16 val; + opus_val32 yy=0; + celt_assert(_k>0); + celt_assert(_n>1); + while(_n>2){ + opus_uint32 q; + /*Lots of pulses case:*/ + if(_k>=_n){ + const opus_uint32 *row; + row=CELT_PVQ_U_ROW[_n]; + /*Are the pulses in this dimension negative?*/ + p=row[_k+1]; + s=-(_i>=p); + _i-=p&s; + /*Count how many pulses were placed in this dimension.*/ + k0=_k; + q=row[_n]; + if(q>_i){ + celt_sig_assert(p>q); + _k=_n; + do p=CELT_PVQ_U_ROW[--_k][_n]; + while(p>_i); + } + else for(p=row[_k];p>_i;p=row[_k])_k--; + _i-=p; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + } + /*Lots of dimensions case:*/ + else{ + /*Are there any pulses in this dimension at all?*/ + p=CELT_PVQ_U_ROW[_k][_n]; + q=CELT_PVQ_U_ROW[_k+1][_n]; + if(p<=_i&&_i=q); + _i-=q&s; + /*Count how many pulses were placed in this dimension.*/ + k0=_k; + do p=CELT_PVQ_U_ROW[--_k][_n]; + while(p>_i); + _i-=p; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + } + } + _n--; + } + /*_n==2*/ + p=2*_k+1; + s=-(_i>=p); + _i-=p&s; + k0=_k; + _k=(_i+1)>>1; + if(_k)_i-=2*_k-1; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + /*_n==1*/ + s=-(int)_i; + val=(_k+s)^s; + *_y=val; + yy=MAC16_16(yy,val,val); + return yy; +} + +opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){ + return cwrsi(_n,_k,ec_dec_uint(_dec,CELT_PVQ_V(_n,_k)),_y); +} + +#else /* SMALL_FOOTPRINT */ + +/*Computes the next row/column of any recurrence that obeys the relation + u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static OPUS_INLINE void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_len); + _ui[j-1]=_ui0; +} + +/*Computes the previous row/column of any recurrence that obeys the relation + u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static OPUS_INLINE void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_n); + _ui[j-1]=_ui0; +} + +/*Compute V(_n,_k), as well as U(_n,0..._k+1). + _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/ +static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){ + opus_uint32 um2; + unsigned len; + unsigned k; + len=_k+2; + /*We require storage at least 3 values (e.g., _k>0).*/ + celt_assert(len>=3); + _u[0]=0; + _u[1]=um2=1; + /*If _n==0, _u[0] should be 1 and the rest should be 0.*/ + /*If _n==1, _u[i] should be 1 for i>1.*/ + celt_assert(_n>=2); + /*If _k==0, the following do-while loop will overflow the buffer.*/ + celt_assert(_k>0); + k=2; + do _u[k]=(k<<1)-1; + while(++k0); + j=0; + do{ + opus_uint32 p; + int s; + int yj; + p=_u[_k+1]; + s=-(_i>=p); + _i-=p&s; + yj=_k; + p=_u[_k]; + while(p>_i)p=_u[--_k]; + _i-=p; + yj-=_k; + val=(yj+s)^s; + _y[j]=val; + yy=MAC16_16(yy,val,val); + uprev(_u,_k+2,0); + } + while(++j<_n); + return yy; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 1 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static OPUS_INLINE opus_uint32 icwrs1(const int *_y,int *_k){ + *_k=abs(_y[0]); + return _y[0]<0; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size _n with associated sign bits. + _y: The vector of pulses, whose sum of absolute values must be _k. + _nc: Returns V(_n,_k).*/ +static OPUS_INLINE opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y, + opus_uint32 *_u){ + opus_uint32 i; + int j; + int k; + /*We can't unroll the first two iterations of the loop unless _n>=2.*/ + celt_assert(_n>=2); + _u[0]=0; + for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1; + i=icwrs1(_y+_n-1,&k); + j=_n-2; + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + while(j-->0){ + unext(_u,_k+2,0); + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + } + *_nc=_u[k]+_u[k+1]; + return i; +} + +#ifdef CUSTOM_MODES +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + if (_n==1) + { + for (k=1;k<=_maxk;k++) + _bits[k] = 1<<_frac; + } + else { + VARDECL(opus_uint32,u); + SAVE_STACK; + ALLOC(u,_maxk+2U,opus_uint32); + ncwrs_urow(_n,_maxk,u); + for(k=1;k<=_maxk;k++) + _bits[k]=log2_frac(u[k]+u[k+1],_frac); + RESTORE_STACK; + } +} +#endif /* CUSTOM_MODES */ + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + opus_uint32 i; + VARDECL(opus_uint32,u); + opus_uint32 nc; + SAVE_STACK; + celt_assert(_k>0); + ALLOC(u,_k+2U,opus_uint32); + i=icwrs(_n,_k,&nc,_y,u); + ec_enc_uint(_enc,i,nc); + RESTORE_STACK; +} + +opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){ + VARDECL(opus_uint32,u); + int ret; + SAVE_STACK; + celt_assert(_k>0); + ALLOC(u,_k+2U,opus_uint32); + ret = cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u); + RESTORE_STACK; + return ret; +} + +#endif /* SMALL_FOOTPRINT */ diff --git a/native/codec/libraries/opus/celt/cwrs.h b/native/codec/libraries/opus/celt/cwrs.h new file mode 100644 index 0000000..7cd4717 --- /dev/null +++ b/native/codec/libraries/opus/celt/cwrs.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CWRS_H +#define CWRS_H + +#include "arch.h" +#include "stack_alloc.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef CUSTOM_MODES +int log2_frac(opus_uint32 val, int frac); +#endif + +void get_required_bits(opus_int16 *bits, int N, int K, int frac); + +void encode_pulses(const int *_y, int N, int K, ec_enc *enc); + +opus_val32 decode_pulses(int *_y, int N, int K, ec_dec *dec); + +#endif /* CWRS_H */ diff --git a/native/codec/libraries/opus/celt/dump_modes/dump_modes.c b/native/codec/libraries/opus/celt/dump_modes/dump_modes.c new file mode 100644 index 0000000..9105a53 --- /dev/null +++ b/native/codec/libraries/opus/celt/dump_modes/dump_modes.c @@ -0,0 +1,353 @@ +/* Copyright (c) 2008 CSIRO + Copyright (c) 2008-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "modes.h" +#include "celt.h" +#include "rate.h" +#include "dump_modes_arch.h" + +#define INT16 "%d" +#define INT32 "%d" +#define FLOAT "%#0.8gf" + +#ifdef FIXED_POINT +#define WORD16 INT16 +#define WORD32 INT32 +#else +#define WORD16 FLOAT +#define WORD32 FLOAT +#endif + +void dump_modes(FILE *file, CELTMode **modes, int nb_modes) +{ + int i, j, k; + int mdct_twiddles_size; + fprintf(file, "/* The contents of this file was automatically generated by dump_modes.c\n"); + fprintf(file, " with arguments:"); + for (i=0;iFs,mode->shortMdctSize*mode->nbShortMdcts); + } + fprintf(file, "\n It contains static definitions for some pre-defined modes. */\n"); + fprintf(file, "#include \"modes.h\"\n"); + fprintf(file, "#include \"rate.h\"\n"); + fprintf(file, "\n#ifdef HAVE_ARM_NE10\n"); + fprintf(file, "#define OVERRIDE_FFT 1\n"); + fprintf(file, "#include \"%s\"\n", ARM_NE10_ARCH_FILE_NAME); + fprintf(file, "#endif\n"); + + fprintf(file, "\n"); + + for (i=0;ishortMdctSize*mode->nbShortMdcts; + standard = (mode->Fs == 400*(opus_int32)mode->shortMdctSize); + framerate = mode->Fs/mode->shortMdctSize; + + if (!standard) + { + fprintf(file, "#ifndef DEF_EBANDS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define DEF_EBANDS%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const opus_int16 eBands%d_%d[%d] = {\n", mode->Fs, mdctSize, mode->nbEBands+2); + for (j=0;jnbEBands+2;j++) + fprintf (file, "%d, ", mode->eBands[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#ifndef DEF_WINDOW%d\n", mode->overlap); + fprintf(file, "#define DEF_WINDOW%d\n", mode->overlap); + fprintf (file, "static const opus_val16 window%d[%d] = {\n", mode->overlap, mode->overlap); + for (j=0;joverlap;j++) + fprintf (file, WORD16 ",%c", mode->window[j],(j+6)%5==0?'\n':' '); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + if (!standard) + { + fprintf(file, "#ifndef DEF_ALLOC_VECTORS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define DEF_ALLOC_VECTORS%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const unsigned char allocVectors%d_%d[%d] = {\n", mode->Fs, mdctSize, mode->nbEBands*mode->nbAllocVectors); + for (j=0;jnbAllocVectors;j++) + { + for (k=0;knbEBands;k++) + fprintf (file, "%2d, ", mode->allocVectors[j*mode->nbEBands+k]); + fprintf (file, "\n"); + } + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#ifndef DEF_LOGN%d\n", framerate); + fprintf(file, "#define DEF_LOGN%d\n", framerate); + fprintf (file, "static const opus_int16 logN%d[%d] = {\n", framerate, mode->nbEBands); + for (j=0;jnbEBands;j++) + fprintf (file, "%d, ", mode->logN[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* Pulse cache */ + fprintf(file, "#ifndef DEF_PULSE_CACHE%d\n", mode->Fs/mdctSize); + fprintf(file, "#define DEF_PULSE_CACHE%d\n", mode->Fs/mdctSize); + fprintf (file, "static const opus_int16 cache_index%d[%d] = {\n", mode->Fs/mdctSize, (mode->maxLM+2)*mode->nbEBands); + for (j=0;jnbEBands*(mode->maxLM+2);j++) + fprintf (file, "%d,%c", mode->cache.index[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + fprintf (file, "static const unsigned char cache_bits%d[%d] = {\n", mode->Fs/mdctSize, mode->cache.size); + for (j=0;jcache.size;j++) + fprintf (file, "%d,%c", mode->cache.bits[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + fprintf (file, "static const unsigned char cache_caps%d[%d] = {\n", mode->Fs/mdctSize, (mode->maxLM+1)*2*mode->nbEBands); + for (j=0;j<(mode->maxLM+1)*2*mode->nbEBands;j++) + fprintf (file, "%d,%c", mode->cache.caps[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* FFT twiddles */ + fprintf(file, "#ifndef FFT_TWIDDLES%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define FFT_TWIDDLES%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const kiss_twiddle_cpx fft_twiddles%d_%d[%d] = {\n", + mode->Fs, mdctSize, mode->mdct.kfft[0]->nfft); + for (j=0;jmdct.kfft[0]->nfft;j++) + fprintf (file, "{" WORD16 ", " WORD16 "},%c", mode->mdct.kfft[0]->twiddles[j].r, mode->mdct.kfft[0]->twiddles[j].i,(j+3)%2==0?'\n':' '); + fprintf (file, "};\n"); + +#ifdef OVERRIDE_FFT + dump_mode_arch(mode); +#endif + /* FFT Bitrev tables */ + for (k=0;k<=mode->mdct.maxshift;k++) + { + fprintf(file, "#ifndef FFT_BITREV%d\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "#define FFT_BITREV%d\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "static const opus_int16 fft_bitrev%d[%d] = {\n", + mode->mdct.kfft[k]->nfft, mode->mdct.kfft[k]->nfft); + for (j=0;jmdct.kfft[k]->nfft;j++) + fprintf (file, "%d,%c", mode->mdct.kfft[k]->bitrev[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + /* FFT States */ + for (k=0;k<=mode->mdct.maxshift;k++) + { + fprintf(file, "#ifndef FFT_STATE%d_%d_%d\n", mode->Fs, mdctSize, k); + fprintf(file, "#define FFT_STATE%d_%d_%d\n", mode->Fs, mdctSize, k); + fprintf (file, "static const kiss_fft_state fft_state%d_%d_%d = {\n", + mode->Fs, mdctSize, k); + fprintf (file, "%d, /* nfft */\n", mode->mdct.kfft[k]->nfft); + fprintf (file, WORD16 ", /* scale */\n", mode->mdct.kfft[k]->scale); +#ifdef FIXED_POINT + fprintf (file, "%d, /* scale_shift */\n", mode->mdct.kfft[k]->scale_shift); +#endif + fprintf (file, "%d, /* shift */\n", mode->mdct.kfft[k]->shift); + fprintf (file, "{"); + for (j=0;j<2*MAXFACTORS;j++) + fprintf (file, "%d, ", mode->mdct.kfft[k]->factors[j]); + fprintf (file, "}, /* factors */\n"); + fprintf (file, "fft_bitrev%d, /* bitrev */\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "fft_twiddles%d_%d, /* bitrev */\n", mode->Fs, mdctSize); + + fprintf (file, "#ifdef OVERRIDE_FFT\n"); + fprintf (file, "(arch_fft_state *)&cfg_arch_%d,\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "#else\n"); + fprintf (file, "NULL,\n"); + fprintf(file, "#endif\n"); + + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* MDCT twiddles */ + mdct_twiddles_size = mode->mdct.n-(mode->mdct.n/2>>mode->mdct.maxshift); + fprintf(file, "#ifndef MDCT_TWIDDLES%d\n", mdctSize); + fprintf(file, "#define MDCT_TWIDDLES%d\n", mdctSize); + fprintf (file, "static const opus_val16 mdct_twiddles%d[%d] = {\n", + mdctSize, mdct_twiddles_size); + for (j=0;jmdct.trig[j],(j+6)%5==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + + /* Print the actual mode data */ + fprintf(file, "static const CELTMode mode%d_%d_%d = {\n", mode->Fs, mdctSize, mode->overlap); + fprintf(file, INT32 ", /* Fs */\n", mode->Fs); + fprintf(file, "%d, /* overlap */\n", mode->overlap); + fprintf(file, "%d, /* nbEBands */\n", mode->nbEBands); + fprintf(file, "%d, /* effEBands */\n", mode->effEBands); + fprintf(file, "{"); + for (j=0;j<4;j++) + fprintf(file, WORD16 ", ", mode->preemph[j]); + fprintf(file, "}, /* preemph */\n"); + if (standard) + fprintf(file, "eband5ms, /* eBands */\n"); + else + fprintf(file, "eBands%d_%d, /* eBands */\n", mode->Fs, mdctSize); + + fprintf(file, "%d, /* maxLM */\n", mode->maxLM); + fprintf(file, "%d, /* nbShortMdcts */\n", mode->nbShortMdcts); + fprintf(file, "%d, /* shortMdctSize */\n", mode->shortMdctSize); + + fprintf(file, "%d, /* nbAllocVectors */\n", mode->nbAllocVectors); + if (standard) + fprintf(file, "band_allocation, /* allocVectors */\n"); + else + fprintf(file, "allocVectors%d_%d, /* allocVectors */\n", mode->Fs, mdctSize); + + fprintf(file, "logN%d, /* logN */\n", framerate); + fprintf(file, "window%d, /* window */\n", mode->overlap); + fprintf(file, "{%d, %d, {", mode->mdct.n, mode->mdct.maxshift); + for (k=0;k<=mode->mdct.maxshift;k++) + fprintf(file, "&fft_state%d_%d_%d, ", mode->Fs, mdctSize, k); + fprintf (file, "}, mdct_twiddles%d}, /* mdct */\n", mdctSize); + + fprintf(file, "{%d, cache_index%d, cache_bits%d, cache_caps%d}, /* cache */\n", + mode->cache.size, mode->Fs/mdctSize, mode->Fs/mdctSize, mode->Fs/mdctSize); + fprintf(file, "};\n"); + } + fprintf(file, "\n"); + fprintf(file, "/* List of all the available modes */\n"); + fprintf(file, "#define TOTAL_MODES %d\n", nb_modes); + fprintf(file, "static const CELTMode * const static_mode_list[TOTAL_MODES] = {\n"); + for (i=0;ishortMdctSize*mode->nbShortMdcts; + fprintf(file, "&mode%d_%d_%d,\n", mode->Fs, mdctSize, mode->overlap); + } + fprintf(file, "};\n"); +} + +void dump_header(FILE *file, CELTMode **modes, int nb_modes) +{ + int i; + int channels = 0; + int frame_size = 0; + int overlap = 0; + fprintf (file, "/* This header file is generated automatically*/\n"); + for (i=0;ishortMdctSize*mode->nbShortMdcts; + else if (frame_size != mode->shortMdctSize*mode->nbShortMdcts) + frame_size = -1; + if (overlap==0) + overlap = mode->overlap; + else if (overlap != mode->overlap) + overlap = -1; + } + if (channels>0) + { + fprintf (file, "#define CHANNELS(mode) %d\n", channels); + if (channels==1) + fprintf (file, "#define DISABLE_STEREO\n"); + } + if (frame_size>0) + { + fprintf (file, "#define FRAMESIZE(mode) %d\n", frame_size); + } + if (overlap>0) + { + fprintf (file, "#define OVERLAP(mode) %d\n", overlap); + } +} + +#ifdef FIXED_POINT +#define BASENAME "static_modes_fixed" +#else +#define BASENAME "static_modes_float" +#endif + +int main(int argc, char **argv) +{ + int i, nb; + FILE *file; + CELTMode **m; + if (argc%2 != 1 || argc<3) + { + fprintf (stderr, "Usage: %s rate frame_size [rate frame_size] [rate frame_size]...\n",argv[0]); + return 1; + } + nb = (argc-1)/2; + m = malloc(nb*sizeof(CELTMode*)); + for (i=0;i +#include +#include "modes.h" +#include "dump_modes_arch.h" +#include + +#if !defined(FIXED_POINT) +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_float32_t +# define NE10_FFT_CPX_TYPE_T_STR "ne10_fft_cpx_float32_t" +# define NE10_FFT_STATE_TYPE_T_STR "ne10_fft_state_float32_t" +#else +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_int32_t +# define NE10_FFT_CPX_TYPE_T_STR "ne10_fft_cpx_int32_t" +# define NE10_FFT_STATE_TYPE_T_STR "ne10_fft_state_int32_t" +#endif + +static FILE *file; + +void dump_modes_arch_init(CELTMode **modes, int nb_modes) +{ + int i; + + file = fopen(ARM_NE10_ARCH_FILE_NAME, "w"); + fprintf(file, "/* The contents of this file was automatically generated by\n"); + fprintf(file, " * dump_mode_arm_ne10.c with arguments:"); + for (i=0;iFs,mode->shortMdctSize*mode->nbShortMdcts); + } + fprintf(file, "\n * It contains static definitions for some pre-defined modes. */\n"); + fprintf(file, "#include \n\n"); +} + +void dump_modes_arch_finalize() +{ + fclose(file); +} + +void dump_mode_arch(CELTMode *mode) +{ + int k, j; + int mdctSize; + + mdctSize = mode->shortMdctSize*mode->nbShortMdcts; + + fprintf(file, "#ifndef NE10_FFT_PARAMS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define NE10_FFT_PARAMS%d_%d\n", mode->Fs, mdctSize); + /* cfg->factors */ + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) + continue; + fprintf(file, "static const ne10_int32_t ne10_factors_%d[%d] = {\n", + mode->mdct.kfft[k]->nfft, (NE10_MAXFACTORS * 2)); + for(j=0;j<(NE10_MAXFACTORS * 2);j++) { + fprintf(file, "%d,%c", cfg->factors[j],(j+16)%15==0?'\n':' '); + } + fprintf (file, "};\n"); + } + + /* cfg->twiddles */ + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) + continue; + fprintf(file, "static const %s ne10_twiddles_%d[%d] = {\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft, + mode->mdct.kfft[k]->nfft); + for(j=0;jmdct.kfft[k]->nfft;j++) { +#if !defined(FIXED_POINT) + fprintf(file, "{%#0.8gf,%#0.8gf},%c", + cfg->twiddles[j].r, cfg->twiddles[j].i,(j+4)%3==0?'\n':' '); +#else + fprintf(file, "{%d,%d},%c", + cfg->twiddles[j].r, cfg->twiddles[j].i,(j+4)%3==0?'\n':' '); +#endif + } + fprintf (file, "};\n"); + } + + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) { + fprintf(file, "/* Ne10 does not support scaled FFT for length = %d */\n", + mode->mdct.kfft[k]->nfft); + fprintf(file, "static const arch_fft_state cfg_arch_%d = {\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "0,\n"); + fprintf(file, "NULL\n"); + fprintf(file, "};\n"); + continue; + } + fprintf(file, "static const %s %s_%d = {\n", NE10_FFT_STATE_TYPE_T_STR, + NE10_FFT_STATE_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "%d,\n", cfg->nfft); + fprintf(file, "(ne10_int32_t *)ne10_factors_%d,\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "(%s *)ne10_twiddles_%d,\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "NULL,\n"); /* buffer */ + fprintf(file, "(%s *)&ne10_twiddles_%d[%d],\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft, cfg->nfft); +#if !defined(FIXED_POINT) + fprintf(file, "/* is_forward_scaled = true */\n"); + fprintf(file, "(ne10_int32_t) 1,\n"); + fprintf(file, "/* is_backward_scaled = false */\n"); + fprintf(file, "(ne10_int32_t) 0,\n"); +#endif + fprintf(file, "};\n"); + + fprintf(file, "static const arch_fft_state cfg_arch_%d = {\n", + mode->mdct.kfft[k]->nfft); + fprintf(file, "1,\n"); + fprintf(file, "(void *)&%s_%d,\n", + NE10_FFT_STATE_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "};\n\n"); + } + fprintf(file, "#endif /* end NE10_FFT_PARAMS%d_%d */\n", mode->Fs, mdctSize); +} diff --git a/native/codec/libraries/opus/celt/ecintrin.h b/native/codec/libraries/opus/celt/ecintrin.h new file mode 100644 index 0000000..2263cff --- /dev/null +++ b/native/codec/libraries/opus/celt/ecintrin.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2003-2008 Timothy B. Terriberry + Copyright (c) 2008 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*Some common macros for potential platform-specific optimization.*/ +#include "opus_types.h" +#include +#include +#include "arch.h" +#if !defined(_ecintrin_H) +# define _ecintrin_H (1) + +/*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly + versions of these functions which can substantially improve performance. + We define macros for them to allow easy incorporation of these non-ANSI + features.*/ + +/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if + given an appropriate architecture, but the branchless bit-twiddling versions + are just as fast, and do not require any special target architecture. + Earlier gcc versions (3.x) compiled both code to the same assembly + instructions, because of the way they represented ((_b)>(_a)) internally.*/ +# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a)))) + +/*Count leading zeros. + This macro should only be used for implementing ec_ilog(), if it is defined. + All other code should use EC_ILOG() instead.*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +# include +/*In _DEBUG mode this is not an intrinsic by default.*/ +# pragma intrinsic(_BitScanReverse) + +static __inline int ec_bsr(unsigned long _x){ + unsigned long ret; + _BitScanReverse(&ret,_x); + return (int)ret; +} +# define EC_CLZ0 (1) +# define EC_CLZ(_x) (-ec_bsr(_x)) +#elif defined(ENABLE_TI_DSPLIB) +# include "dsplib.h" +# define EC_CLZ0 (31) +# define EC_CLZ(_x) (_lnorm(_x)) +#elif __GNUC_PREREQ(3,4) +# if INT_MAX>=2147483647 +# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clz(_x)) +# elif LONG_MAX>=2147483647L +# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clzl(_x)) +# endif +#endif + +#if defined(EC_CLZ) +/*Note that __builtin_clz is not defined when _x==0, according to the gcc + documentation (and that of the BSR instruction that implements it on x86). + The majority of the time we can never pass it zero. + When we need to, it can be special cased.*/ +# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) +#else +int ec_ilog(opus_uint32 _v); +# define EC_ILOG(_x) (ec_ilog(_x)) +#endif +#endif diff --git a/native/codec/libraries/opus/celt/entcode.c b/native/codec/libraries/opus/celt/entcode.c new file mode 100644 index 0000000..70f3201 --- /dev/null +++ b/native/codec/libraries/opus/celt/entcode.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "entcode.h" +#include "arch.h" + +#if !defined(EC_CLZ) +/*This is a fallback for systems where we don't know how to access + a BSR or CLZ instruction (see ecintrin.h). + If you are optimizing Opus on a new platform and it has a native CLZ or + BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be + an easy performance win.*/ +int ec_ilog(opus_uint32 _v){ + /*On a Pentium M, this branchless version tested as the fastest on + 1,000,000,000 random 32-bit integers, edging out a similar version with + branches, and a 256-entry LUT version.*/ + int ret; + int m; + ret=!!_v; + m=!!(_v&0xFFFF0000)<<4; + _v>>=m; + ret|=m; + m=!!(_v&0xFF00)<<3; + _v>>=m; + ret|=m; + m=!!(_v&0xF0)<<2; + _v>>=m; + ret|=m; + m=!!(_v&0xC)<<1; + _v>>=m; + ret|=m; + ret+=!!(_v&0x2); + return ret; +} +#endif + +#if 1 +/* This is a faster version of ec_tell_frac() that takes advantage + of the low (1/8 bit) resolution to use just a linear function + followed by a lookup to determine the exact transition thresholds. */ +opus_uint32 ec_tell_frac(ec_ctx *_this){ + static const unsigned correction[8] = + {35733, 38967, 42495, 46340, + 50535, 55109, 60097, 65535}; + opus_uint32 nbits; + opus_uint32 r; + int l; + unsigned b; + nbits=_this->nbits_total<rng); + r=_this->rng>>(l-16); + b = (r>>12)-8; + b += r>correction[b]; + l = (l<<3)+b; + return nbits-l; +} +#else +opus_uint32 ec_tell_frac(ec_ctx *_this){ + opus_uint32 nbits; + opus_uint32 r; + int l; + int i; + /*To handle the non-integral number of bits still left in the encoder/decoder + state, we compute the worst-case number of bits of val that must be + encoded to ensure that the value is inside the range for any possible + subsequent bits. + The computation here is independent of val itself (the decoder does not + even track that value), even though the real number of bits used after + ec_enc_done() may be 1 smaller if rng is a power of two and the + corresponding trailing bits of val are all zeros. + If we did try to track that special case, then coding a value with a + probability of 1/(1<nbits_total<rng); + r=_this->rng>>(l-16); + for(i=BITRES;i-->0;){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} +#endif + +#ifdef USE_SMALL_DIV_TABLE +/* Result of 2^32/(2*i+1), except for i=0. */ +const opus_uint32 SMALL_DIV_TABLE[129] = { + 0xFFFFFFFF, 0x55555555, 0x33333333, 0x24924924, + 0x1C71C71C, 0x1745D174, 0x13B13B13, 0x11111111, + 0x0F0F0F0F, 0x0D79435E, 0x0C30C30C, 0x0B21642C, + 0x0A3D70A3, 0x097B425E, 0x08D3DCB0, 0x08421084, + 0x07C1F07C, 0x07507507, 0x06EB3E45, 0x06906906, + 0x063E7063, 0x05F417D0, 0x05B05B05, 0x0572620A, + 0x05397829, 0x05050505, 0x04D4873E, 0x04A7904A, + 0x047DC11F, 0x0456C797, 0x04325C53, 0x04104104, + 0x03F03F03, 0x03D22635, 0x03B5CC0E, 0x039B0AD1, + 0x0381C0E0, 0x0369D036, 0x03531DEC, 0x033D91D2, + 0x0329161F, 0x03159721, 0x03030303, 0x02F14990, + 0x02E05C0B, 0x02D02D02, 0x02C0B02C, 0x02B1DA46, + 0x02A3A0FD, 0x0295FAD4, 0x0288DF0C, 0x027C4597, + 0x02702702, 0x02647C69, 0x02593F69, 0x024E6A17, + 0x0243F6F0, 0x0239E0D5, 0x02302302, 0x0226B902, + 0x021D9EAD, 0x0214D021, 0x020C49BA, 0x02040810, + 0x01FC07F0, 0x01F44659, 0x01ECC07B, 0x01E573AC, + 0x01DE5D6E, 0x01D77B65, 0x01D0CB58, 0x01CA4B30, + 0x01C3F8F0, 0x01BDD2B8, 0x01B7D6C3, 0x01B20364, + 0x01AC5701, 0x01A6D01A, 0x01A16D3F, 0x019C2D14, + 0x01970E4F, 0x01920FB4, 0x018D3018, 0x01886E5F, + 0x0183C977, 0x017F405F, 0x017AD220, 0x01767DCE, + 0x01724287, 0x016E1F76, 0x016A13CD, 0x01661EC6, + 0x01623FA7, 0x015E75BB, 0x015AC056, 0x01571ED3, + 0x01539094, 0x01501501, 0x014CAB88, 0x0149539E, + 0x01460CBC, 0x0142D662, 0x013FB013, 0x013C995A, + 0x013991C2, 0x013698DF, 0x0133AE45, 0x0130D190, + 0x012E025C, 0x012B404A, 0x01288B01, 0x0125E227, + 0x01234567, 0x0120B470, 0x011E2EF3, 0x011BB4A4, + 0x01194538, 0x0116E068, 0x011485F0, 0x0112358E, + 0x010FEF01, 0x010DB20A, 0x010B7E6E, 0x010953F3, + 0x01073260, 0x0105197F, 0x0103091B, 0x01010101 +}; +#endif diff --git a/native/codec/libraries/opus/celt/entcode.h b/native/codec/libraries/opus/celt/entcode.h new file mode 100644 index 0000000..3763e3f --- /dev/null +++ b/native/codec/libraries/opus/celt/entcode.h @@ -0,0 +1,152 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "opus_types.h" +#include "opus_defines.h" + +#if !defined(_entcode_H) +# define _entcode_H (1) +# include +# include +# include "ecintrin.h" + +extern const opus_uint32 SMALL_DIV_TABLE[129]; + +#ifdef OPUS_ARM_ASM +#define USE_SMALL_DIV_TABLE +#endif + +/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a + larger type, you can speed up the decoder by using it here.*/ +typedef opus_uint32 ec_window; +typedef struct ec_ctx ec_ctx; +typedef struct ec_ctx ec_enc; +typedef struct ec_ctx ec_dec; + +# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT) + +/*The number of bits to use for the range-coded part of unsigned integers.*/ +# define EC_UINT_BITS (8) + +/*The resolution of fractional-precision bit usage measurements, i.e., + 3 => 1/8th bits.*/ +# define BITRES 3 + +/*The entropy encoder/decoder context. + We use the same structure for both, so that common functions like ec_tell() + can be used on either one.*/ +struct ec_ctx{ + /*Buffered input/output.*/ + unsigned char *buf; + /*The size of the buffer.*/ + opus_uint32 storage; + /*The offset at which the last byte containing raw bits was read/written.*/ + opus_uint32 end_offs; + /*Bits that will be read from/written at the end.*/ + ec_window end_window; + /*Number of valid bits in end_window.*/ + int nend_bits; + /*The total number of whole bits read/written. + This does not include partial bits currently in the range coder.*/ + int nbits_total; + /*The offset at which the next range coder byte will be read/written.*/ + opus_uint32 offs; + /*The number of values in the current range.*/ + opus_uint32 rng; + /*In the decoder: the difference between the top of the current range and + the input value, minus one. + In the encoder: the low end of the current range.*/ + opus_uint32 val; + /*In the decoder: the saved normalization factor from ec_decode(). + In the encoder: the number of oustanding carry propagating symbols.*/ + opus_uint32 ext; + /*A buffered input/output symbol, awaiting carry propagation.*/ + int rem; + /*Nonzero if an error occurred.*/ + int error; +}; + +static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){ + return _this->offs; +} + +static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){ + return _this->buf; +} + +static OPUS_INLINE int ec_get_error(ec_ctx *_this){ + return _this->error; +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +static OPUS_INLINE int ec_tell(ec_ctx *_this){ + return _this->nbits_total-EC_ILOG(_this->rng); +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits scaled by 2**BITRES. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +opus_uint32 ec_tell_frac(ec_ctx *_this); + +/* Tested exhaustively for all n and for 1<=d<=256 */ +static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) { + celt_sig_assert(d>0); +#ifdef USE_SMALL_DIV_TABLE + if (d>256) + return n/d; + else { + opus_uint32 t, q; + t = EC_ILOG(d&-d); + q = (opus_uint64)SMALL_DIV_TABLE[d>>t]*(n>>(t-1))>>32; + return q+(n-q*d >= d); + } +#else + return n/d; +#endif +} + +static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) { + celt_sig_assert(d>0); +#ifdef USE_SMALL_DIV_TABLE + if (n<0) + return -(opus_int32)celt_udiv(-n, d); + else + return celt_udiv(n, d); +#else + return n/d; +#endif +} + +#endif diff --git a/native/codec/libraries/opus/celt/entdec.c b/native/codec/libraries/opus/celt/entdec.c new file mode 100644 index 0000000..0b3433e --- /dev/null +++ b/native/codec/libraries/opus/celt/entdec.c @@ -0,0 +1,245 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "os_support.h" +#include "arch.h" +#include "entdec.h" +#include "mfrngcod.h" + +/*A range decoder. + This is an entropy decoder based upon \cite{Mar79}, which is itself a + rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}. + It is very similar to arithmetic encoding, except that encoding is done with + digits in any base, instead of with bits, and so it is faster when using + larger bases (i.e.: a byte). + The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$ + is the base, longer than the theoretical optimum, but to my knowledge there + is no published justification for this claim. + This only seems true when using near-infinite precision arithmetic so that + the process is carried out with no rounding errors. + + An excellent description of implementation details is available at + http://www.arturocampos.com/ac_range.html + A recent work \cite{MNW98} which proposes several changes to arithmetic + encoding for efficiency actually re-discovers many of the principles + behind range encoding, and presents a good theoretical analysis of them. + + End of stream is handled by writing out the smallest number of bits that + ensures that the stream will be correctly decoded regardless of the value of + any subsequent bits. + ec_tell() can be used to determine how many bits were needed to decode + all the symbols thus far; other data can be packed in the remaining bits of + the input buffer. + @PHDTHESIS{Pas76, + author="Richard Clark Pasco", + title="Source coding algorithms for fast data compression", + school="Dept. of Electrical Engineering, Stanford University", + address="Stanford, CA", + month=May, + year=1976 + } + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video & Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_read_byte(ec_dec *_this){ + return _this->offs<_this->storage?_this->buf[_this->offs++]:0; +} + +static int ec_read_byte_from_end(ec_dec *_this){ + return _this->end_offs<_this->storage? + _this->buf[_this->storage-++(_this->end_offs)]:0; +} + +/*Normalizes the contents of val and rng so that rng lies entirely in the + high-order symbol.*/ +static void ec_dec_normalize(ec_dec *_this){ + /*If the range is too small, rescale it and input some bits.*/ + while(_this->rng<=EC_CODE_BOT){ + int sym; + _this->nbits_total+=EC_SYM_BITS; + _this->rng<<=EC_SYM_BITS; + /*Use up the remaining bits from our last symbol.*/ + sym=_this->rem; + /*Read the next value from the input.*/ + _this->rem=ec_read_byte(_this); + /*Take the rest of the bits we need from this new symbol.*/ + sym=(sym<rem)>>(EC_SYM_BITS-EC_CODE_EXTRA); + /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ + _this->val=((_this->val<buf=_buf; + _this->storage=_storage; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits. + The final value after the ec_dec_normalize() call will be the same as in + the encoder, but we have to compensate for the bits that are added there.*/ + _this->nbits_total=EC_CODE_BITS+1 + -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS; + _this->offs=0; + _this->rng=1U<rem=ec_read_byte(_this); + _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA)); + _this->error=0; + /*Normalize the interval.*/ + ec_dec_normalize(_this); +} + +unsigned ec_decode(ec_dec *_this,unsigned _ft){ + unsigned s; + _this->ext=celt_udiv(_this->rng,_ft); + s=(unsigned)(_this->val/_this->ext); + return _ft-EC_MINI(s+1,_ft); +} + +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){ + unsigned s; + _this->ext=_this->rng>>_bits; + s=(unsigned)(_this->val/_this->ext); + return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits); +} + +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 s; + s=IMUL32(_this->ext,_ft-_fh); + _this->val-=s; + _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s; + ec_dec_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + int ret; + r=_this->rng; + d=_this->val; + s=r>>_logp; + ret=dval=d-s; + _this->rng=ret?s:r-s; + ec_dec_normalize(_this); + return ret; +} + +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + opus_uint32 t; + int ret; + s=_this->rng; + d=_this->val; + r=s>>_ftb; + ret=-1; + do{ + t=s; + s=IMUL32(r,_icdf[++ret]); + } + while(dval=d-s; + _this->rng=t-s; + ec_dec_normalize(_this); + return ret; +} + +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){ + unsigned ft; + unsigned s; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + opus_uint32 t; + ftb-=EC_UINT_BITS; + ft=(unsigned)(_ft>>ftb)+1; + s=ec_decode(_this,ft); + ec_dec_update(_this,s,s+1,ft); + t=(opus_uint32)s<error=1; + return _ft; + } + else{ + _ft++; + s=ec_decode(_this,(unsigned)_ft); + ec_dec_update(_this,s,s+1,(unsigned)_ft); + return s; + } +} + +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){ + ec_window window; + int available; + opus_uint32 ret; + window=_this->end_window; + available=_this->nend_bits; + if((unsigned)available<_bits){ + do{ + window|=(ec_window)ec_read_byte_from_end(_this)<>=_bits; + available-=_bits; + _this->end_window=window; + _this->nend_bits=available; + _this->nbits_total+=_bits; + return ret; +} diff --git a/native/codec/libraries/opus/celt/entdec.h b/native/codec/libraries/opus/celt/entdec.h new file mode 100644 index 0000000..025fc18 --- /dev/null +++ b/native/codec/libraries/opus/celt/entdec.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entdec_H) +# define _entdec_H (1) +# include +# include "entcode.h" + +/*Initializes the decoder. + _buf: The input buffer to use. + Return: 0 on success, or a negative value on error.*/ +void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage); + +/*Calculates the cumulative frequency for the next symbol. + This can then be fed into the probability model to determine what that + symbol is, and the additional frequency information required to advance to + the next symbol. + This function cannot be called more than once without a corresponding call to + ec_dec_update(), or decoding will not proceed correctly. + _ft: The total frequency of the symbols in the alphabet the next symbol was + encoded with. + Return: A cumulative frequency representing the encoded symbol. + If the cumulative frequency of all the symbols before the one that + was encoded was fl, and the cumulative frequency of all the symbols + up to and including the one encoded is fh, then the returned value + will fall in the range [fl,fh).*/ +unsigned ec_decode(ec_dec *_this,unsigned _ft); + +/*Equivalent to ec_decode() with _ft==1<<_bits.*/ +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits); + +/*Advance the decoder past the next symbol using the frequency information the + symbol was encoded with. + Exactly one call to ec_decode() must have been made so that all necessary + intermediate calculations are performed. + _fl: The cumulative frequency of all symbols that come before the symbol + decoded. + _fh: The cumulative frequency of all symbols up to and including the symbol + decoded. + Together with _fl, this defines the range [_fl,_fh) in which the value + returned above must fall. + _ft: The total frequency of the symbols in the alphabet the symbol decoded + was encoded in. + This must be the same as passed to the preceding call to ec_decode().*/ +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/* Decode a bit that has a 1/(1<<_logp) probability of being a one */ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp); + +/*Decodes a symbol given an "inverse" CDF table. + No call to ec_dec_update() is necessary after this call. + _icdf: The "inverse" CDF, such that symbol s falls in the range + [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution. + Return: The decoded symbol s.*/ +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); + +/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream. + The bits must have been encoded with ec_enc_uint(). + No call to ec_dec_update() is necessary after this call. + _ft: The number of integers that can be decoded (one more than the max). + This must be at least 2, and no more than 2**32-1. + Return: The decoded bits.*/ +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft); + +/*Extracts a sequence of raw bits from the stream. + The bits must have been encoded with ec_enc_bits(). + No call to ec_dec_update() is necessary after this call. + _ftb: The number of bits to extract. + This must be between 0 and 25, inclusive. + Return: The decoded bits.*/ +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb); + +#endif diff --git a/native/codec/libraries/opus/celt/entenc.c b/native/codec/libraries/opus/celt/entenc.c new file mode 100644 index 0000000..f1750d2 --- /dev/null +++ b/native/codec/libraries/opus/celt/entenc.c @@ -0,0 +1,294 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if defined(HAVE_CONFIG_H) +# include "config.h" +#endif +#include "os_support.h" +#include "arch.h" +#include "entenc.h" +#include "mfrngcod.h" + +/*A range encoder. + See entdec.c and the references for implementation details \cite{Mar79,MNW98}. + + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video \& Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_write_byte(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->offs++]=(unsigned char)_value; + return 0; +} + +static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value; + return 0; +} + +/*Outputs a symbol, with a carry bit. + If there is a potential to propagate a carry over several symbols, they are + buffered until it can be determined whether or not an actual carry will + occur. + If the counter for the buffered symbols overflows, then the stream becomes + undecodable. + This gives a theoretical limit of a few billion symbols in a single packet on + 32-bit systems. + The alternative is to truncate the range in order to force a carry, but + requires similar carry tracking in the decoder, needlessly slowing it down.*/ +static void ec_enc_carry_out(ec_enc *_this,int _c){ + if(_c!=EC_SYM_MAX){ + /*No further carry propagation possible, flush buffer.*/ + int carry; + carry=_c>>EC_SYM_BITS; + /*Don't output a byte on the first write. + This compare should be taken care of by branch-prediction thereafter.*/ + if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry); + if(_this->ext>0){ + unsigned sym; + sym=(EC_SYM_MAX+carry)&EC_SYM_MAX; + do _this->error|=ec_write_byte(_this,sym); + while(--(_this->ext)>0); + } + _this->rem=_c&EC_SYM_MAX; + } + else _this->ext++; +} + +static OPUS_INLINE void ec_enc_normalize(ec_enc *_this){ + /*If the range is too small, output some bits and rescale it.*/ + while(_this->rng<=EC_CODE_BOT){ + ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT)); + /*Move the next-to-high-order symbol into the high-order position.*/ + _this->val=(_this->val<rng<<=EC_SYM_BITS; + _this->nbits_total+=EC_SYM_BITS; + } +} + +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){ + _this->buf=_buf; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits.*/ + _this->nbits_total=EC_CODE_BITS+1; + _this->offs=0; + _this->rng=EC_CODE_TOP; + _this->rem=-1; + _this->val=0; + _this->ext=0; + _this->storage=_size; + _this->error=0; +} + +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 r; + r=celt_udiv(_this->rng,_ft); + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,(_ft-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,(_ft-_fh)); + ec_enc_normalize(_this); +} + +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){ + opus_uint32 r; + r=_this->rng>>_bits; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,((1U<<_bits)-_fh)); + ec_enc_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){ + opus_uint32 r; + opus_uint32 s; + opus_uint32 l; + r=_this->rng; + l=_this->val; + s=r>>_logp; + r-=s; + if(_val)_this->val=l+r; + _this->rng=_val?s:r; + ec_enc_normalize(_this); +} + +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + r=_this->rng>>_ftb; + if(_s>0){ + _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]); + _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]); + } + else _this->rng-=IMUL32(r,_icdf[_s]); + ec_enc_normalize(_this); +} + +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){ + unsigned ft; + unsigned fl; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + ftb-=EC_UINT_BITS; + ft=(_ft>>ftb)+1; + fl=(unsigned)(_fl>>ftb); + ec_encode(_this,fl,fl+1,ft); + ec_enc_bits(_this,_fl&(((opus_uint32)1<end_window; + used=_this->nend_bits; + celt_assert(_bits>0); + if(used+_bits>EC_WINDOW_SIZE){ + do{ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + while(used>=EC_SYM_BITS); + } + window|=(ec_window)_fl<end_window=window; + _this->nend_bits=used; + _this->nbits_total+=_bits; +} + +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){ + int shift; + unsigned mask; + celt_assert(_nbits<=EC_SYM_BITS); + shift=EC_SYM_BITS-_nbits; + mask=((1<<_nbits)-1)<offs>0){ + /*The first byte has been finalized.*/ + _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<rem>=0){ + /*The first byte is still awaiting carry propagation.*/ + _this->rem=(_this->rem&~mask)|_val<rng<=(EC_CODE_TOP>>_nbits)){ + /*The renormalization loop has never been run.*/ + _this->val=(_this->val&~((opus_uint32)mask<error=-1; +} + +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){ + celt_assert(_this->offs+_this->end_offs<=_size); + OPUS_MOVE(_this->buf+_size-_this->end_offs, + _this->buf+_this->storage-_this->end_offs,_this->end_offs); + _this->storage=_size; +} + +void ec_enc_done(ec_enc *_this){ + ec_window window; + int used; + opus_uint32 msk; + opus_uint32 end; + int l; + /*We output the minimum number of bits that ensures that the symbols encoded + thus far will be decoded correctly regardless of the bits that follow.*/ + l=EC_CODE_BITS-EC_ILOG(_this->rng); + msk=(EC_CODE_TOP-1)>>l; + end=(_this->val+msk)&~msk; + if((end|msk)>=_this->val+_this->rng){ + l++; + msk>>=1; + end=(_this->val+msk)&~msk; + } + while(l>0){ + ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT)); + end=(end<rem>=0||_this->ext>0)ec_enc_carry_out(_this,0); + /*If we have buffered extra bits, flush them as well.*/ + window=_this->end_window; + used=_this->nend_bits; + while(used>=EC_SYM_BITS){ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + /*Clear any excess space and add any remaining extra bits to the last byte.*/ + if(!_this->error){ + OPUS_CLEAR(_this->buf+_this->offs, + _this->storage-_this->offs-_this->end_offs); + if(used>0){ + /*If there's no range coder data at all, give up.*/ + if(_this->end_offs>=_this->storage)_this->error=-1; + else{ + l=-l; + /*If we've busted, don't add too many extra bits to the last byte; it + would corrupt the range coder data, and that's more important.*/ + if(_this->offs+_this->end_offs>=_this->storage&&lerror=-1; + } + _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window; + } + } + } +} diff --git a/native/codec/libraries/opus/celt/entenc.h b/native/codec/libraries/opus/celt/entenc.h new file mode 100644 index 0000000..f502eaf --- /dev/null +++ b/native/codec/libraries/opus/celt/entenc.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entenc_H) +# define _entenc_H (1) +# include +# include "entcode.h" + +/*Initializes the encoder. + _buf: The buffer to store output bytes in. + _size: The size of the buffer, in chars.*/ +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size); +/*Encodes a symbol given its frequency information. + The frequency information must be discernable by the decoder, assuming it + has read only the previous symbols from the stream. + It is allowable to change the frequency information, or even the entire + source alphabet, so long as the decoder can tell from the context of the + previously encoded information that it is supposed to do so as well. + _fl: The cumulative frequency of all symbols that come before the one to be + encoded. + _fh: The cumulative frequency of all symbols up to and including the one to + be encoded. + Together with _fl, this defines the range [_fl,_fh) in which the + decoded value will fall. + _ft: The sum of the frequencies of all the symbols*/ +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/*Equivalent to ec_encode() with _ft==1<<_bits.*/ +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits); + +/* Encode a bit that has a 1/(1<<_logp) probability of being a one */ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp); + +/*Encodes a symbol given an "inverse" CDF table. + _s: The index of the symbol to encode. + _icdf: The "inverse" CDF, such that symbol _s falls in the range + [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution.*/ +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb); + +/*Encodes a raw unsigned integer in the stream. + _fl: The integer to encode. + _ft: The number of integers that can be encoded (one more than the max). + This must be at least 2, and no more than 2**32-1.*/ +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft); + +/*Encodes a sequence of raw bits in the stream. + _fl: The bits to encode. + _ftb: The number of bits to encode. + This must be between 1 and 25, inclusive.*/ +void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb); + +/*Overwrites a few bits at the very start of an existing stream, after they + have already been encoded. + This makes it possible to have a few flags up front, where it is easy for + decoders to access them without parsing the whole stream, even if their + values are not determined until late in the encoding process, without having + to buffer all the intermediate symbols in the encoder. + In order for this to work, at least _nbits bits must have already been + encoded using probabilities that are an exact power of two. + The encoder can verify the number of encoded bits is sufficient, but cannot + check this latter condition. + _val: The bits to encode (in the least _nbits significant bits). + They will be decoded in order from most-significant to least. + _nbits: The number of bits to overwrite. + This must be no more than 8.*/ +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits); + +/*Compacts the data to fit in the target size. + This moves up the raw bits at the end of the current buffer so they are at + the end of the new buffer size. + The caller must ensure that the amount of data that's already been written + will fit in the new size. + _size: The number of bytes in the new buffer. + This must be large enough to contain the bits already written, and + must be no larger than the existing size.*/ +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size); + +/*Indicates that there are no more symbols to encode. + All reamining output bytes are flushed to the output buffer. + ec_enc_init() must be called before the encoder can be used again.*/ +void ec_enc_done(ec_enc *_this); + +#endif diff --git a/native/codec/libraries/opus/celt/fixed_c5x.h b/native/codec/libraries/opus/celt/fixed_c5x.h new file mode 100644 index 0000000..ea95a99 --- /dev/null +++ b/native/codec/libraries/opus/celt/fixed_c5x.h @@ -0,0 +1,79 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_c5x.h + @brief Fixed-point operations for the TI C5x DSP family +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_C5X_H +#define FIXED_C5X_H + +#include "dsplib.h" + +#undef IMUL32 +static OPUS_INLINE long IMUL32(long i, long j) +{ + long ac0, ac1; + ac0 = _lmpy(i>>16,j); + ac1 = ac0 + _lmpy(i,j>>16); + return _lmpyu(i,j) + (ac1<<16); +} + +#undef MAX16 +#define MAX16(a,b) _max(a,b) + +#undef MIN16 +#define MIN16(a,b) _min(a,b) + +#undef MAX32 +#define MAX32(a,b) _lmax(a,b) + +#undef MIN32 +#define MIN32(a,b) _lmin(a,b) + +#undef VSHR32 +#define VSHR32(a, shift) _lshl(a,-(shift)) + +#undef MULT16_16_Q15 +#define MULT16_16_Q15(a,b) (_smpy(a,b)) + +#undef MULT16_16SU +#define MULT16_16SU(a,b) _lmpysu(a,b) + +#undef MULT_16_16 +#define MULT_16_16(a,b) _lmpy(a,b) + +/* FIXME: This is technically incorrect and is bound to cause problems. Is there any cleaner solution? */ +#undef MULT16_32_Q15 +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),(b)),15)) + +#define celt_ilog2(x) (30 - _lnorm(x)) +#define OVERRIDE_CELT_ILOG2 + +#define celt_maxabs16(x, len) MAX32(EXTEND32(maxval((DATA *)x, len)),-EXTEND32(minval((DATA *)x, len))) +#define OVERRIDE_CELT_MAXABS16 + +#endif /* FIXED_C5X_H */ diff --git a/native/codec/libraries/opus/celt/fixed_c6x.h b/native/codec/libraries/opus/celt/fixed_c6x.h new file mode 100644 index 0000000..bb6ad92 --- /dev/null +++ b/native/codec/libraries/opus/celt/fixed_c6x.h @@ -0,0 +1,70 @@ +/* Copyright (C) 2008 CSIRO */ +/** + @file fixed_c6x.h + @brief Fixed-point operations for the TI C6x DSP family +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_C6X_H +#define FIXED_C6X_H + +#undef MULT16_16SU +#define MULT16_16SU(a,b) _mpysu(a,b) + +#undef MULT_16_16 +#define MULT_16_16(a,b) _mpy(a,b) + +#define celt_ilog2(x) (30 - _norm(x)) +#define OVERRIDE_CELT_ILOG2 + +#undef MULT16_32_Q15 +#define MULT16_32_Q15(a,b) (_mpylill(a, b) >> 15) + +#if 0 +#include "dsplib.h" + +#undef MAX16 +#define MAX16(a,b) _max(a,b) + +#undef MIN16 +#define MIN16(a,b) _min(a,b) + +#undef MAX32 +#define MAX32(a,b) _lmax(a,b) + +#undef MIN32 +#define MIN32(a,b) _lmin(a,b) + +#undef VSHR32 +#define VSHR32(a, shift) _lshl(a,-(shift)) + +#undef MULT16_16_Q15 +#define MULT16_16_Q15(a,b) (_smpy(a,b)) + +#define celt_maxabs16(x, len) MAX32(EXTEND32(maxval((DATA *)x, len)),-EXTEND32(minval((DATA *)x, len))) +#define OVERRIDE_CELT_MAXABS16 + +#endif /* FIXED_C6X_H */ diff --git a/native/codec/libraries/opus/celt/fixed_debug.h b/native/codec/libraries/opus/celt/fixed_debug.h new file mode 100644 index 0000000..f435295 --- /dev/null +++ b/native/codec/libraries/opus/celt/fixed_debug.h @@ -0,0 +1,791 @@ +/* Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2012 Xiph.Org Foundation */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include +#include "opus_defines.h" + +#ifdef CELT_C +OPUS_EXPORT opus_int64 celt_mips=0; +#else +extern opus_int64 celt_mips; +#endif + +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16) + +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) +#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1)) + +#define SHR(a,b) SHR32(a,b) +#define PSHR(a,b) PSHR32(a,b) + +/** Add two 32-bit values, ignore any overflows */ +#define ADD32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)+(opus_uint32)(b))) +/** Subtract two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)-(opus_uint32)(b))) +/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */ +/** Negate 32-bit value, ignore any overflows */ +#define NEG32_ovflw(a) (celt_mips+=2,(opus_val32)(0-(opus_uint32)(a))) + +static OPUS_INLINE short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +static OPUS_INLINE int NEG32(opus_int64 x) +{ + opus_int64 res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__) +static OPUS_INLINE short EXTRACT16_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__) +static OPUS_INLINE int EXTEND32_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE short SHR16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE short SHL16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} +#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a)))) +#define SROUND16(x,a) (celt_mips--,EXTRACT16(SATURATE(PSHR32(x,a), 32767))); + +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short ADD16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short SUB16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int ADD32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int SUB32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef UADD32 +#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_UINT(res)) + { + fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef USUB32 +#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (a=((opus_val32)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = (((opus_int64)a)*(opus_int64)b) >> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=3; + else + celt_mips+=4; + return res; +} + +#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__) +static OPUS_INLINE int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (ABS32(b)>=((opus_int64)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<>1))>> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=4; + else + celt_mips+=5; + return res; +} + +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b)))) +#define MAC16_32_Q16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q16((a),(b)))) + +static OPUS_INLINE int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + celt_mips+=3; + return a; +} + +static OPUS_INLINE opus_int16 SATURATE16(opus_int32 a) +{ + celt_mips+=3; + if (a>32767) + return 32767; + else if (a<-32768) + return -32768; + else return a; +} + +static OPUS_INLINE int MULT16_16_Q11_32(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static OPUS_INLINE short MULT16_16_Q13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static OPUS_INLINE short MULT16_16_Q14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} + +#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short MULT16_16_Q15_(int a, int b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=1; + return res; +} + +static OPUS_INLINE short MULT16_16_P13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static OPUS_INLINE short MULT16_16_P14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static OPUS_INLINE short MULT16_16_P15(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__) + +static OPUS_INLINE int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=35; + return res; +} + +#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int DIV32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=70; + return res; +} + +static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x) +{ + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +} +#define SIG2WORD16(x) (SIG2WORD16_generic(x)) + + +#undef PRINT_MIPS +#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0); + +#endif diff --git a/native/codec/libraries/opus/celt/fixed_generic.h b/native/codec/libraries/opus/celt/fixed_generic.h new file mode 100644 index 0000000..5f4abda --- /dev/null +++ b/native/codec/libraries/opus/celt/fixed_generic.h @@ -0,0 +1,178 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */ +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_Q16(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),16)) +#else +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#endif + +/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_P16(a,b) ((opus_val32)PSHR((opus_int64)((opus_val16)(a))*(b),16)) +#else +#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#endif + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_Q15(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),15)) +#else +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15)) +#endif + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT32_32_Q31(a,b) ((opus_val32)SHR((opus_int64)(a)*(opus_int64)(b),31)) +#else +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15)) +#endif + +/** Compile-time conversion of float constant to 16-bit value */ +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Compile-time conversion of float constant to 32-bit value */ +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Negate a 16-bit value */ +#define NEG16(x) (-(x)) +/** Negate a 32-bit value */ +#define NEG32(x) (-(x)) + +/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */ +#define EXTRACT16(x) ((opus_val16)(x)) +/** Change a 16-bit value into a 32-bit value */ +#define EXTEND32(x) ((opus_val32)(x)) + +/** Arithmetic shift-right of a 16-bit value */ +#define SHR16(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 16-bit value */ +#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift))) +/** Arithmetic shift-right of a 32-bit value */ +#define SHR32(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 32-bit value */ +#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift))) + +/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +/** 32-bit arithmetic shift right where the argument can be negative */ +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +/** "RAW" macros, should not be used outside of this header file */ +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) SHL32(a,shift) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define SATURATE16(x) (EXTRACT16((x)>32767 ? 32767 : (x)<-32768 ? -32768 : (x))) + +/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */ +#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a)))) +/** Shift by a and round-to-neareast 32-bit value. Result is a saturated 16-bit value */ +#define SROUND16(x,a) EXTRACT16(SATURATE(PSHR32(x,a), 32767)); + +/** Divide by two */ +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +/** Add two 16-bit values */ +#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b))) +/** Subtract two 16-bit values */ +#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b)) +/** Add two 32-bit values */ +#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b)) +/** Subtract two 32-bit values */ +#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b)) + +/** Add two 32-bit values, ignore any overflows */ +#define ADD32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)+(opus_uint32)(b))) +/** Subtract two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)-(opus_uint32)(b))) +/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */ +/** Negate 32-bit value, ignore any overflows */ +#define NEG32_ovflw(a) ((opus_val32)(0-(opus_uint32)(a))) + +/** 16x16 multiplication where the result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b)))) + +/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */ +/** 16x16 multiplication where the result fits in 32 bits */ +#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b))) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#define MAC16_32_Q15(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + +/** 16x32 multiplication, followed by a 16-bit shift right and 32-bit add. + Results fits in 32 bits */ +#define MAC16_32_Q16(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */ +#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b)))) + +/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */ +#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b))) + +#if defined(MIPSr1_ASM) +#include "mips/fixed_generic_mipsr1.h" +#endif + +static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x) +{ + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +} +#define SIG2WORD16(x) (SIG2WORD16_generic(x)) + +#endif diff --git a/native/codec/libraries/opus/celt/float_cast.h b/native/codec/libraries/opus/celt/float_cast.h new file mode 100644 index 0000000..889dae9 --- /dev/null +++ b/native/codec/libraries/opus/celt/float_cast.h @@ -0,0 +1,146 @@ +/* Copyright (C) 2001 Erik de Castro Lopo */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Version 1.1 */ + +#ifndef FLOAT_CAST_H +#define FLOAT_CAST_H + + +#include "arch.h" + +/*============================================================================ +** On Intel Pentium processors (especially PIII and probably P4), converting +** from float to int is very slow. To meet the C specs, the code produced by +** most C compilers targeting Pentium needs to change the FPU rounding mode +** before the float to int conversion is performed. +** +** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It +** is this flushing of the pipeline which is so slow. +** +** Fortunately the ISO C99 specifications define the functions lrint, lrintf, +** llrint and llrintf which fix this problem as a side effect. +** +** On Unix-like systems, the configure process should have detected the +** presence of these functions. If they weren't found we have to replace them +** here with a standard C cast. +*/ + +/* +** The C99 prototypes for lrint and lrintf are as follows: +** +** long int lrintf (float x) ; +** long int lrint (double x) ; +*/ + +/* The presence of the required functions are detected during the configure +** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in +** the config.h file. +*/ + +/* With GCC, when SSE is available, the fastest conversion is cvtss2si. */ +#if defined(__GNUC__) && defined(__SSE__) + +#include +static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_ss(x));} + +#elif defined(HAVE_LRINTF) + +/* These defines enable functionality introduced with the 1999 ISO C +** standard. They must be defined before the inclusion of math.h to +** engage them. If optimisation is enabled, these functions will be +** inlined. With optimisation switched off, you have to link in the +** maths library using -lm. +*/ + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrintf(x) + +#elif (defined(HAVE_LRINT)) + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrint(x) + +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) + #include + + static __inline long int float2int(float value) + { + return _mm_cvtss_si32(_mm_load_ss(&value)); + } +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_IX86) + #include + + /* Win32 doesn't seem to have these functions. + ** Therefore implement OPUS_INLINE versions of these functions here. + */ + + static __inline long int + float2int (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + +#else + +#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) + /* supported by gcc in C99 mode, but not by all other compilers */ + #warning "Don't have the functions lrint() and lrintf ()." + #warning "Replacing these functions with a standard C cast." +#endif /* __STDC_VERSION__ >= 199901L */ + #include + #define float2int(flt) ((int)(floor(.5+flt))) +#endif + +#ifndef DISABLE_FLOAT_API +static OPUS_INLINE opus_int16 FLOAT2INT16(float x) +{ + x = x*CELT_SIG_SCALE; + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return (opus_int16)float2int(x); +} +#endif /* DISABLE_FLOAT_API */ + +#endif /* FLOAT_CAST_H */ diff --git a/native/codec/libraries/opus/celt/kiss_fft.c b/native/codec/libraries/opus/celt/kiss_fft.c new file mode 100644 index 0000000..8377516 --- /dev/null +++ b/native/codec/libraries/opus/celt/kiss_fft.c @@ -0,0 +1,604 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +/* This code is originally from Mark Borgerding's KISS-FFT but has been + heavily modified to better suit Opus */ + +#ifndef SKIP_CONFIG_H +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + complex numbers. It also delares the kf_ internal functions. +*/ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + int m, + int N + ) +{ + kiss_fft_cpx * Fout2; + int i; + (void)m; +#ifdef CUSTOM_MODES + if (m==1) + { + celt_assert(m==1); + for (i=0;itwiddles; + /* m is guaranteed to be a multiple of 4. */ + for (j=0;jtwiddles[fstride*m]; +#endif + for (i=0;itwiddles; + /* For non-custom modes, m is guaranteed to be a multiple of 4. */ + k=m; + do { + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = SUB32_ovflw(Fout->r, HALF_OF(scratch[3].r)); + Fout[m].i = SUB32_ovflw(Fout->i, HALF_OF(scratch[3].i)); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = ADD32_ovflw(Fout[m].r, scratch[0].i); + Fout[m2].i = SUB32_ovflw(Fout[m].i, scratch[0].r); + + Fout[m].r = SUB32_ovflw(Fout[m].r, scratch[0].i); + Fout[m].i = ADD32_ovflw(Fout[m].i, scratch[0].r); + + ++Fout; + } while(--k); + } +} + + +#ifndef OVERRIDE_kf_bfly5 +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + +#ifdef FIXED_POINT + ya.r = 10126; + ya.i = -31164; + yb.r = -26510; + yb.i = -19261; +#else + ya = st->twiddles[fstride*m]; + yb = st->twiddles[fstride*2*m]; +#endif + tw=st->twiddles; + + for (i=0;ir = ADD32_ovflw(Fout0->r, ADD32_ovflw(scratch[7].r, scratch[8].r)); + Fout0->i = ADD32_ovflw(Fout0->i, ADD32_ovflw(scratch[7].i, scratch[8].i)); + + scratch[5].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,ya.r), S_MUL(scratch[8].r,yb.r))); + scratch[5].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,ya.r), S_MUL(scratch[8].i,yb.r))); + + scratch[6].r = ADD32_ovflw(S_MUL(scratch[10].i,ya.i), S_MUL(scratch[9].i,yb.i)); + scratch[6].i = NEG32_ovflw(ADD32_ovflw(S_MUL(scratch[10].r,ya.i), S_MUL(scratch[9].r,yb.i))); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,yb.r), S_MUL(scratch[8].r,ya.r))); + scratch[11].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,yb.r), S_MUL(scratch[8].i,ya.r))); + scratch[12].r = SUB32_ovflw(S_MUL(scratch[9].i,ya.i), S_MUL(scratch[10].i,yb.i)); + scratch[12].i = SUB32_ovflw(S_MUL(scratch[10].r,yb.i), S_MUL(scratch[9].r,ya.i)); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} +#endif /* OVERRIDE_kf_bfly5 */ + + +#endif + + +#ifdef CUSTOM_MODES + +static +void compute_bitrev_table( + int Fout, + opus_int16 *f, + const size_t fstride, + int in_stride, + opus_int16 * factors, + const kiss_fft_state *st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (opus_int32)p*(opus_int32)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; +#ifdef RADIX_TWO_ONLY + if (p!=2 && p != 4) +#else + if (p>5) +#endif + { + return 0; + } + facbuf[2*stages] = p; + if (p==2 && stages > 1) + { + facbuf[2*stages] = 4; + facbuf[2] = 2; + } + stages++; + } while (n > 1); + n = nbak; + /* Reverse the order to get the radix 4 at the end, so we can use the + fast degenerate case. It turns out that reversing the order also + improves the noise behaviour. */ + for (i=0;i= memneeded) + st = (kiss_fft_state*)mem; + *lenmem = memneeded; + } + if (st) { + opus_int16 *bitrev; + kiss_twiddle_cpx *twiddles; + + st->nfft=nfft; +#ifdef FIXED_POINT + st->scale_shift = celt_ilog2(st->nfft); + if (st->nfft == 1<scale_shift) + st->scale = Q15ONE; + else + st->scale = (1073741824+st->nfft/2)/st->nfft>>(15-st->scale_shift); +#else + st->scale = 1.f/nfft; +#endif + if (base != NULL) + { + st->twiddles = base->twiddles; + st->shift = 0; + while (st->shift < 32 && nfft<shift != base->nfft) + st->shift++; + if (st->shift>=32) + goto fail; + } else { + st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft); + compute_twiddles(twiddles, nfft); + st->shift = -1; + } + if (!kf_factor(nfft,st->factors)) + { + goto fail; + } + + /* bitrev */ + st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft); + if (st->bitrev==NULL) + goto fail; + compute_bitrev_table(0, bitrev, 1,1, st->factors,st); + + /* Initialize architecture specific fft parameters */ + if (opus_fft_alloc_arch(st, arch)) + goto fail; + } + return st; +fail: + opus_fft_free(st, arch); + return NULL; +} + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch) +{ + return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL, arch); +} + +void opus_fft_free_arch_c(kiss_fft_state *st) { + (void)st; +} + +void opus_fft_free(const kiss_fft_state *cfg, int arch) +{ + if (cfg) + { + opus_fft_free_arch((kiss_fft_state *)cfg, arch); + opus_free((opus_int16*)cfg->bitrev); + if (cfg->shift < 0) + opus_free((kiss_twiddle_cpx*)cfg->twiddles); + opus_free((kiss_fft_state*)cfg); + } +} + +#endif /* CUSTOM_MODES */ + +void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout) +{ + int m2, m; + int p; + int L; + int fstride[MAXFACTORS]; + int i; + int shift; + + /* st->shift can be -1 */ + shift = st->shift>0 ? st->shift : 0; + + fstride[0] = 1; + L=0; + do { + p = st->factors[2*L]; + m = st->factors[2*L+1]; + fstride[L+1] = fstride[L]*p; + L++; + } while(m!=1); + m = st->factors[2*L-1]; + for (i=L-1;i>=0;i--) + { + if (i!=0) + m2 = st->factors[2*i-1]; + else + m2 = 1; + switch (st->factors[2*i]) + { + case 2: + kf_bfly2(fout, m, fstride[i]); + break; + case 4: + kf_bfly4(fout,fstride[i]<scale_shift-1; +#endif + scale = st->scale; + + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + { + kiss_fft_cpx x = fin[i]; + fout[st->bitrev[i]].r = SHR32(MULT16_32_Q16(scale, x.r), scale_shift); + fout[st->bitrev[i]].i = SHR32(MULT16_32_Q16(scale, x.i), scale_shift); + } + opus_fft_impl(st, fout); +} + + +void opus_ifft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + int i; + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + fout[st->bitrev[i]] = fin[i]; + for (i=0;infft;i++) + fout[i].i = -fout[i].i; + opus_fft_impl(st, fout); + for (i=0;infft;i++) + fout[i].i = -fout[i].i; +} diff --git a/native/codec/libraries/opus/celt/kiss_fft.h b/native/codec/libraries/opus/celt/kiss_fft.h new file mode 100644 index 0000000..bffa2bf --- /dev/null +++ b/native/codec/libraries/opus/celt/kiss_fft.h @@ -0,0 +1,200 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include "arch.h" +#include "cpu_support.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC opus_alloc +#endif + +#ifdef FIXED_POINT +#include "arch.h" + +# define kiss_fft_scalar opus_int32 +# define kiss_twiddle_scalar opus_int16 + + +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# define kiss_twiddle_scalar float +# define KF_SUFFIX _celt_single +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct { + kiss_twiddle_scalar r; + kiss_twiddle_scalar i; +}kiss_twiddle_cpx; + +#define MAXFACTORS 8 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +typedef struct arch_fft_state{ + int is_supported; + void *priv; +} arch_fft_state; + +typedef struct kiss_fft_state{ + int nfft; + opus_val16 scale; +#ifdef FIXED_POINT + int scale_shift; +#endif + int shift; + opus_int16 factors[2*MAXFACTORS]; + const opus_int16 *bitrev; + const kiss_twiddle_cpx *twiddles; + arch_fft_state *arch_fft; +} kiss_fft_state; + +#if defined(HAVE_ARM_NE10) +#include "arm/fft_arm.h" +#endif + +/*typedef struct kiss_fft_state* kiss_fft_cfg;*/ + +/** + * opus_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base, int arch); + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch); + +/** + * opus_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void opus_fft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); +void opus_ifft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout); +void opus_ifft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout); + +void opus_fft_free(const kiss_fft_state *cfg, int arch); + + +void opus_fft_free_arch_c(kiss_fft_state *st); +int opus_fft_alloc_arch_c(kiss_fft_state *st); + +#if !defined(OVERRIDE_OPUS_FFT) +/* Is run-time CPU detection enabled on this platform? */ +#if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) + +extern int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])( + kiss_fft_state *st); + +#define opus_fft_alloc_arch(_st, arch) \ + ((*OPUS_FFT_ALLOC_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st)) + +extern void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])( + kiss_fft_state *st); +#define opus_fft_free_arch(_st, arch) \ + ((*OPUS_FFT_FREE_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st)) + +extern void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, kiss_fft_cpx *fout); +#define opus_fft(_cfg, _fin, _fout, arch) \ + ((*OPUS_FFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout)) + +extern void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, kiss_fft_cpx *fout); +#define opus_ifft(_cfg, _fin, _fout, arch) \ + ((*OPUS_IFFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout)) + +#else /* else for if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */ + +#define opus_fft_alloc_arch(_st, arch) \ + ((void)(arch), opus_fft_alloc_arch_c(_st)) + +#define opus_fft_free_arch(_st, arch) \ + ((void)(arch), opus_fft_free_arch_c(_st)) + +#define opus_fft(_cfg, _fin, _fout, arch) \ + ((void)(arch), opus_fft_c(_cfg, _fin, _fout)) + +#define opus_ifft(_cfg, _fin, _fout, arch) \ + ((void)(arch), opus_ifft_c(_cfg, _fin, _fout)) + +#endif /* end if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */ +#endif /* end if !defined(OVERRIDE_OPUS_FFT) */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/celt/laplace.c b/native/codec/libraries/opus/celt/laplace.c new file mode 100644 index 0000000..a7bca87 --- /dev/null +++ b/native/codec/libraries/opus/celt/laplace.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "laplace.h" +#include "mathops.h" + +/* The minimum probability of an energy delta (out of 32768). */ +#define LAPLACE_LOG_MINP (0) +#define LAPLACE_MINP (1<>15; +} + +void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay) +{ + unsigned fl; + int val = *value; + fl = 0; + if (val) + { + int s; + int i; + s = -(val<0); + val = (val+s)^s; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay); + /* Search the decaying part of the PDF.*/ + for (i=1; fs > 0 && i < val; i++) + { + fs *= 2; + fl += fs+2*LAPLACE_MINP; + fs = (fs*(opus_int32)decay)>>15; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (!fs) + { + int di; + int ndi_max; + ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP; + ndi_max = (ndi_max-s)>>1; + di = IMIN(val - i, ndi_max - 1); + fl += (2*di+1+s)*LAPLACE_MINP; + fs = IMIN(LAPLACE_MINP, 32768-fl); + *value = (i+di+s)^s; + } + else + { + fs += LAPLACE_MINP; + fl += fs&~s; + } + celt_assert(fl+fs<=32768); + celt_assert(fs>0); + } + ec_encode_bin(enc, fl, fl+fs, 15); +} + +int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay) +{ + int val=0; + unsigned fl; + unsigned fm; + fm = ec_decode_bin(dec, 15); + fl = 0; + if (fm >= fs) + { + val++; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP; + /* Search the decaying part of the PDF.*/ + while(fs > LAPLACE_MINP && fm >= fl+2*fs) + { + fs *= 2; + fl += fs; + fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15; + fs += LAPLACE_MINP; + val++; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= LAPLACE_MINP) + { + int di; + di = (fm-fl)>>(LAPLACE_LOG_MINP+1); + val += di; + fl += 2*di*LAPLACE_MINP; + } + if (fm < fl+fs) + val = -val; + else + fl += fs; + } + celt_assert(fl<32768); + celt_assert(fs>0); + celt_assert(fl<=fm); + celt_assert(fm>1; + b=1U<>=1; + bshift--; + } + while(bshift>=0); + return g; +} + +#ifdef FIXED_POINT + +opus_val32 frac_div32(opus_val32 a, opus_val32 b) +{ + opus_val16 rcp; + opus_val32 result, rem; + int shift = celt_ilog2(b)-29; + a = VSHR32(a,shift); + b = VSHR32(b,shift); + /* 16-bit reciprocal */ + rcp = ROUND16(celt_rcp(ROUND16(b,16)),3); + result = MULT16_32_Q15(rcp, a); + rem = PSHR32(a,2)-MULT32_32_Q31(result, b); + result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2)); + if (result >= 536870912) /* 2^29 */ + return 2147483647; /* 2^31 - 1 */ + else if (result <= -536870912) /* -2^29 */ + return -2147483647; /* -2^31 */ + else + return SHL32(result, 2); +} + +/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */ +opus_val16 celt_rsqrt_norm(opus_val32 x) +{ + opus_val16 n; + opus_val16 r; + opus_val16 r2; + opus_val16 y; + /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */ + n = x-32768; + /* Get a rough initial guess for the root. + The optimal minimax quadratic approximation (using relative error) is + r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485). + Coefficients here, and the final result r, are Q14.*/ + r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713)))); + /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14. + We can compute the result from n and r using Q15 multiplies with some + adjustment, carefully done to avoid overflow. + Range of y is [-1564,1594]. */ + r2 = MULT16_16_Q15(r, r); + y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1); + /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5). + This yields the Q14 reciprocal square root of the Q16 x, with a maximum + relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a + peak absolute error of 2.26591/16384. */ + return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y, + SUB16(MULT16_16_Q15(y, 12288), 16384)))); +} + +/** Sqrt approximation (QX input, QX/2 output) */ +opus_val32 celt_sqrt(opus_val32 x) +{ + int k; + opus_val16 n; + opus_val32 rt; + static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664}; + if (x==0) + return 0; + else if (x>=1073741824) + return 32767; + k = (celt_ilog2(x)>>1)-7; + x = VSHR32(x, 2*k); + n = x-32768; + rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], + MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4]))))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static OPUS_INLINE opus_val16 _celt_cos_pi_2(opus_val16 x) +{ + opus_val16 x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2 + )))))))); +} + +#undef L1 +#undef L2 +#undef L3 +#undef L4 + +opus_val16 celt_cos_norm(opus_val32 x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x0); + i = celt_ilog2(x); + /* n is Q15 with range [0,1). */ + n = VSHR32(x,i-15)-32768; + /* Start with a linear approximation: + r = 1.8823529411764706-0.9411764705882353*n. + The coefficients and the result are Q14 in the range [15420,30840].*/ + r = ADD16(30840, MULT16_16_Q15(-15420, n)); + /* Perform two Newton iterations: + r -= r*((r*n)-1.Q15) + = r*((r*n)+(r-1.Q15)). */ + r = SUB16(r, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))); + /* We subtract an extra 1 in the second iteration to avoid overflow; it also + neatly compensates for truncation error in the rest of the process. */ + r = SUB16(r, ADD16(1, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))))); + /* r is now the Q15 solution to 2/(n+1), with a maximum relative error + of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute + error of 1.24665/32768. */ + return VSHR32(EXTEND32(r),i-16); +} + +#endif diff --git a/native/codec/libraries/opus/celt/mathops.h b/native/codec/libraries/opus/celt/mathops.h new file mode 100644 index 0000000..5e86ff0 --- /dev/null +++ b/native/codec/libraries/opus/celt/mathops.h @@ -0,0 +1,290 @@ +/* Copyright (c) 2002-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file mathops.h + @brief Various math functions +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MATHOPS_H +#define MATHOPS_H + +#include "arch.h" +#include "entcode.h" +#include "os_support.h" + +#define PI 3.141592653f + +/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ +#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15) + +unsigned isqrt32(opus_uint32 _val); + +/* CELT doesn't need it for fixed-point, by analysis.c does. */ +#if !defined(FIXED_POINT) || defined(ANALYSIS_C) +#define cA 0.43157974f +#define cB 0.67848403f +#define cC 0.08595542f +#define cE ((float)PI/2) +static OPUS_INLINE float fast_atan2f(float y, float x) { + float x2, y2; + x2 = x*x; + y2 = y*y; + /* For very small values, we don't care about the answer, so + we can just return 0. */ + if (x2 + y2 < 1e-18f) + { + return 0; + } + if(x2>23)-127; + in.i -= integer<<23; + frac = in.f - 1.5f; + frac = -0.41445418f + frac*(0.95909232f + + frac*(-0.33951290f + frac*0.16541097f)); + return 1+integer+frac; +} + +/** Base-2 exponential approximation (2^x). */ +static OPUS_INLINE float celt_exp2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } res; + integer = floor(x); + if (integer < -50) + return 0; + frac = x-integer; + /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ + res.f = 0.99992522f + frac * (0.69583354f + + frac * (0.22606716f + 0.078024523f*frac)); + res.i = (res.i + (integer<<23)) & 0x7fffffff; + return res.f; +} + +#else +#define celt_log2(x) ((float)(1.442695040888963387*log(x))) +#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x))) +#endif + +#endif + +#ifdef FIXED_POINT + +#include "os_support.h" + +#ifndef OVERRIDE_CELT_ILOG2 +/** Integer log in base2. Undefined for zero and negative numbers */ +static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x) +{ + celt_sig_assert(x>0); + return EC_ILOG(x)-1; +} +#endif + + +/** Integer log in base2. Defined for zero, but not for negative numbers */ +static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x) +{ + return x <= 0 ? 0 : celt_ilog2(x); +} + +opus_val16 celt_rsqrt_norm(opus_val32 x); + +opus_val32 celt_sqrt(opus_val32 x); + +opus_val16 celt_cos_norm(opus_val32 x); + +/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */ +static OPUS_INLINE opus_val16 celt_log2(opus_val32 x) +{ + int i; + opus_val16 n, frac; + /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605, + 0.15530808010959576, -0.08556153059057618 */ + static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401}; + if (x==0) + return -32767; + i = celt_ilog2(x); + n = VSHR32(x,i-15)-32768-16384; + frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4])))))))); + return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT); +} + +/* + K0 = 1 + K1 = log(2) + K2 = 3-4*log(2) + K3 = 3*log(2) - 2 +*/ +#define D0 16383 +#define D1 22804 +#define D2 14819 +#define D3 10204 + +static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x) +{ + opus_val16 frac; + frac = SHL16(x, 4); + return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac)))))); +} +/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */ +static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x) +{ + int integer; + opus_val16 frac; + integer = SHR16(x,10); + if (integer>14) + return 0x7f000000; + else if (integer < -15) + return 0; + frac = celt_exp2_frac(x-SHL16(integer,10)); + return VSHR32(EXTEND32(frac), -integer-2); +} + +opus_val32 celt_rcp(opus_val32 x); + +#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b)) + +opus_val32 frac_div32(opus_val32 a, opus_val32 b); + +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +/* Atan approximation using a 4th order polynomial. Input is in Q15 format + and normalized by pi/4. Output is in Q15 format */ +static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* atan2() approximation valid for positive input values */ +static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x) +{ + if (y < x) + { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(y),15),x); + if (arg >= 32767) + arg = 32767; + return SHR16(celt_atan01(EXTRACT16(arg)),1); + } else { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(x),15),y); + if (arg >= 32767) + arg = 32767; + return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1); + } +} + +#endif /* FIXED_POINT */ +#endif /* MATHOPS_H */ diff --git a/native/codec/libraries/opus/celt/mdct.c b/native/codec/libraries/opus/celt/mdct.c new file mode 100644 index 0000000..5c6dab5 --- /dev/null +++ b/native/codec/libraries/opus/celt/mdct.c @@ -0,0 +1,343 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +#if defined(MIPSr1_ASM) +#include "mips/mdct_mipsr1.h" +#endif + + +#ifdef CUSTOM_MODES + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch) +{ + int i; + kiss_twiddle_scalar *trig; + int shift; + int N2=N>>1; + l->n = N; + l->maxshift = maxshift; + for (i=0;i<=maxshift;i++) + { + if (i==0) + l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0, arch); + else + l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0], arch); +#ifndef ENABLE_TI_DSPLIB55 + if (l->kfft[i]==NULL) + return 0; +#endif + } + l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N-(N2>>maxshift))*sizeof(kiss_twiddle_scalar)); + if (l->trig==NULL) + return 0; + for (shift=0;shift<=maxshift;shift++) + { + /* We have enough points that sine isn't necessary */ +#if defined(FIXED_POINT) +#if 1 + for (i=0;i>= 1; + N >>= 1; + } + return 1; +} + +void clt_mdct_clear(mdct_lookup *l, int arch) +{ + int i; + for (i=0;i<=l->maxshift;i++) + opus_fft_free(l->kfft[i], arch); + opus_free((kiss_twiddle_scalar*)l->trig); +} + +#endif /* CUSTOM_MODES */ + +/* Forward MDCT trashes the input array */ +#ifndef OVERRIDE_clt_mdct_forward +void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + opus_val16 scale; +#ifdef FIXED_POINT + /* Allows us to scale with MULT16_32_Q16(), which is faster than + MULT16_32_Q15() on ARM. */ + int scale_shift = st->scale_shift-1; +#endif + SAVE_STACK; + (void)arch; + scale = st->scale; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ibitrev[i]] = yc; + } + } + + /* N/4 complex FFT, does not downscale anymore */ + opus_fft_impl(st, f2); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_cpx * OPUS_RESTRICT fp = f2; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;ii,t[N4+i]) - S_MUL(fp->r,t[i]); + yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} +#endif /* OVERRIDE_clt_mdct_forward */ + +#ifndef OVERRIDE_clt_mdct_backward +void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + const kiss_twiddle_scalar *trig; + (void) arch; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1); + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev; + for(i=0;ikfft[shift], (kiss_fft_cpx*)(out+(overlap>>1))); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * yp0 = out+(overlap>>1); + kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp0[1]; + im = yp0[0]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)); + yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)); + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp1[1]; + im = yp1[0]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)); + yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = SUB32_ovflw(MULT16_32_Q15(*wp2, x2), MULT16_32_Q15(*wp1, x1)); + *xp1-- = ADD32_ovflw(MULT16_32_Q15(*wp1, x2), MULT16_32_Q15(*wp2, x1)); + wp1++; + wp2--; + } + } +} +#endif /* OVERRIDE_clt_mdct_backward */ diff --git a/native/codec/libraries/opus/celt/mdct.h b/native/codec/libraries/opus/celt/mdct.h new file mode 100644 index 0000000..160ae4e --- /dev/null +++ b/native/codec/libraries/opus/celt/mdct.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef MDCT_H +#define MDCT_H + +#include "opus_defines.h" +#include "kiss_fft.h" +#include "arch.h" + +typedef struct { + int n; + int maxshift; + const kiss_fft_state *kfft[4]; + const kiss_twiddle_scalar * OPUS_RESTRICT trig; +} mdct_lookup; + +#if defined(HAVE_ARM_NE10) +#include "arm/mdct_arm.h" +#endif + + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch); +void clt_mdct_clear(mdct_lookup *l, int arch); + +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +/** Compute a backward MDCT (no scaling) and performs weighted overlap-add + (scales implicitly by 1/2) */ +void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, + int overlap, int shift, int stride, int arch); + +#if !defined(OVERRIDE_OPUS_MDCT) +/* Is run-time CPU detection enabled on this platform? */ +#if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) + +extern void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])( + const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window, + int overlap, int shift, int stride, int arch); + +#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + ((*CLT_MDCT_FORWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \ + _window, _overlap, _shift, \ + _stride, _arch)) + +extern void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])( + const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window, + int overlap, int shift, int stride, int arch); + +#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + (*CLT_MDCT_BACKWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \ + _window, _overlap, _shift, \ + _stride, _arch) + +#else /* if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) */ + +#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + clt_mdct_forward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) + +#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + clt_mdct_backward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) + +#endif /* end if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) && !defined(FIXED_POINT) */ +#endif /* end if !defined(OVERRIDE_OPUS_MDCT) */ + +#endif diff --git a/native/codec/libraries/opus/celt/mfrngcod.h b/native/codec/libraries/opus/celt/mfrngcod.h new file mode 100644 index 0000000..809152a --- /dev/null +++ b/native/codec/libraries/opus/celt/mfrngcod.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2001-2008 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_mfrngcode_H) +# define _mfrngcode_H (1) +# include "entcode.h" + +/*Constants used by the entropy encoder/decoder.*/ + +/*The number of bits to output at a time.*/ +# define EC_SYM_BITS (8) +/*The total number of bits in each of the state registers.*/ +# define EC_CODE_BITS (32) +/*The maximum symbol value.*/ +# define EC_SYM_MAX ((1U<>EC_SYM_BITS) +/*The number of bits available for the last, partial symbol in the code field.*/ +# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1) +#endif diff --git a/native/codec/libraries/opus/celt/mips/celt_mipsr1.h b/native/codec/libraries/opus/celt/mips/celt_mipsr1.h new file mode 100644 index 0000000..c332fe0 --- /dev/null +++ b/native/codec/libraries/opus/celt/mips/celt_mipsr1.h @@ -0,0 +1,152 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __CELT_MIPSR1_H__ +#define __CELT_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_C + +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#define OVERRIDE_COMB_FILTER_CONST +#define OVERRIDE_comb_filter +void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, + opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, + const opus_val16 *window, int overlap, int arch) +{ + int i; + opus_val32 x0, x1, x2, x3, x4; + + (void)arch; + + /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */ + opus_val16 g00, g01, g02, g10, g11, g12; + static const opus_val16 gains[3][3] = { + {QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)}, + {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)}, + {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}}; + + if (g0==0 && g1==0) + { + /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */ + if (x!=y) + OPUS_MOVE(y, x, N); + return; + } + + g00 = MULT16_16_P15(g0, gains[tapset0][0]); + g01 = MULT16_16_P15(g0, gains[tapset0][1]); + g02 = MULT16_16_P15(g0, gains[tapset0][2]); + g10 = MULT16_16_P15(g1, gains[tapset1][0]); + g11 = MULT16_16_P15(g1, gains[tapset1][1]); + g12 = MULT16_16_P15(g1, gains[tapset1][2]); + x1 = x[-T1+1]; + x2 = x[-T1 ]; + x3 = x[-T1-1]; + x4 = x[-T1-2]; + /* If the filter didn't change, we don't need the overlap */ + if (g0==g1 && T0==T1 && tapset0==tapset1) + overlap=0; + + for (i=0;itwiddles[fstride*m]; + yb = st->twiddles[fstride*2*m]; +#endif + + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + scratch[5].r = scratch[0].r + S_MUL_ADD(scratch[7].r,ya.r,scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL_ADD(scratch[7].i,ya.r,scratch[8].i,yb.r); + + scratch[6].r = S_MUL_ADD(scratch[10].i,ya.i,scratch[9].i,yb.i); + scratch[6].i = -S_MUL_ADD(scratch[10].r,ya.i,scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL_ADD(scratch[7].r,yb.r,scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL_ADD(scratch[7].i,yb.r,scratch[8].i,ya.r); + + scratch[12].r = S_MUL_SUB(scratch[9].i,ya.i,scratch[10].i,yb.i); + scratch[12].i = S_MUL_SUB(scratch[10].r,yb.i,scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + + +#endif /* KISS_FFT_MIPSR1_H */ diff --git a/native/codec/libraries/opus/celt/mips/mdct_mipsr1.h b/native/codec/libraries/opus/celt/mips/mdct_mipsr1.h new file mode 100644 index 0000000..2934dab --- /dev/null +++ b/native/codec/libraries/opus/celt/mips/mdct_mipsr1.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ +#ifndef __MDCT_MIPSR1_H__ +#define __MDCT_MIPSR1_H__ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +/* Forward MDCT trashes the input array */ +#define OVERRIDE_clt_mdct_forward +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + opus_val16 scale; +#ifdef FIXED_POINT + /* Allows us to scale with MULT16_32_Q16(), which is faster than + MULT16_32_Q15() on ARM. */ + int scale_shift = st->scale_shift-1; +#endif + + (void)arch; + + SAVE_STACK; + scale = st->scale; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = S_MUL_ADD(*wp2, xp1[N2],*wp1,*xp2); + *yp++ = S_MUL_SUB(*wp1, *xp1,*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ibitrev[i]] = yc; + } + } + + /* N/4 complex FFT, does not downscale anymore */ + opus_fft_impl(st, f2); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_cpx * OPUS_RESTRICT fp = f2; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;ii,t[N4+i] , fp->r,t[i]); + yi = S_MUL_ADD(fp->r,t[N4+i] ,fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} + +#define OVERRIDE_clt_mdct_backward +void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + const kiss_twiddle_scalar *trig; + + (void)arch; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1); + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev; + for(i=0;ikfft[shift], (kiss_fft_cpx*)(out+(overlap>>1))); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * OPUS_RESTRICT yp0 = out+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp0[1]; + im = yp0[0]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL_ADD(re,t0 , im,t1); + yi = S_MUL_SUB(re,t1 , im,t0); + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp1[1]; + im = yp1[0]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL_ADD(re,t0,im,t1); + yi = S_MUL_SUB(re,t1,im,t0); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1); + *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } +} +#endif /* __MDCT_MIPSR1_H__ */ diff --git a/native/codec/libraries/opus/celt/mips/pitch_mipsr1.h b/native/codec/libraries/opus/celt/mips/pitch_mipsr1.h new file mode 100644 index 0000000..a9500af --- /dev/null +++ b/native/codec/libraries/opus/celt/mips/pitch_mipsr1.h @@ -0,0 +1,161 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.h + @brief Pitch analysis + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PITCH_MIPSR1_H +#define PITCH_MIPSR1_H + +#define OVERRIDE_DUAL_INNER_PROD +static inline void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2, int arch) +{ + int j; + opus_val32 xy01=0; + opus_val32 xy02=0; + + (void)arch; + + asm volatile("MULT $ac1, $0, $0"); + asm volatile("MULT $ac2, $0, $0"); + /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */ + for (j=0;j=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } +} + +#define OVERRIDE_renormalise_vector +void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E = EPSILON; + opus_val16 g; + opus_val32 t; + celt_norm *xptr = X; + int X0, X1; + + (void)arch; + + asm volatile("mult $ac1, $0, $0"); + asm volatile("MTLO %0, $ac1" : :"r" (E)); + /*if(N %4) + printf("error");*/ + for (i=0;i>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i= Fs) + break; + + /* Find where the linear part ends (i.e. where the spacing is more than min_width */ + for (lin=0;lin= res) + break; + + low = (bark_freq[lin]+res/2)/res; + high = nBark-lin; + *nbEBands = low+high; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2)); + + if (eBands==NULL) + return NULL; + + /* Linear spacing (min_width) */ + for (i=0;i0) + offset = eBands[low-1]*res - bark_freq[lin-1]; + /* Spacing follows critical bands */ + for (i=0;i frame_size) + eBands[*nbEBands] = frame_size; + for (i=1;i<*nbEBands-1;i++) + { + if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1]) + { + eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2; + } + } + /* Remove any empty bands. */ + for (i=j=0;i<*nbEBands;i++) + if(eBands[i+1]>eBands[j]) + eBands[++j]=eBands[i+1]; + *nbEBands=j; + + for (i=1;i<*nbEBands;i++) + { + /* Every band must be smaller than the last band. */ + celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]); + /* Each band must be no larger than twice the size of the previous one. */ + celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1])); + } + + return eBands; +} + +static void compute_allocation_table(CELTMode *mode) +{ + int i, j; + unsigned char *allocVectors; + int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + + mode->nbAllocVectors = BITALLOC_SIZE; + allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands)); + if (allocVectors==NULL) + return; + + /* Check for standard mode */ + if (mode->Fs == 400*(opus_int32)mode->shortMdctSize) + { + for (i=0;inbEBands;i++) + allocVectors[i] = band_allocation[i]; + mode->allocVectors = allocVectors; + return; + } + /* If not the standard mode, interpolate */ + /* Compute per-codec-band allocation from per-critical-band matrix */ + for (i=0;inbEBands;j++) + { + int k; + for (k=0;k mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize) + break; + } + if (k>maxBands-1) + allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1]; + else { + opus_int32 a0, a1; + a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1]; + a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize; + allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1] + + a1*band_allocation[i*maxBands+k])/(a0+a1); + } + } + } + + /*printf ("\n"); + for (i=0;inbEBands;j++) + printf ("%d ", allocVectors[i*mode->nbEBands+j]); + printf ("\n"); + } + exit(0);*/ + + mode->allocVectors = allocVectors; +} + +#endif /* CUSTOM_MODES */ + +CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error) +{ + int i; +#ifdef CUSTOM_MODES + CELTMode *mode=NULL; + int res; + opus_val16 *window; + opus_int16 *logN; + int LM; + int arch = opus_select_arch(); + ALLOC_STACK; +#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA) + if (global_stack==NULL) + goto failure; +#endif +#endif + +#ifndef CUSTOM_MODES_ONLY + for (i=0;iFs && + (frame_size<shortMdctSize*static_mode_list[i]->nbShortMdcts) + { + if (error) + *error = OPUS_OK; + return (CELTMode*)static_mode_list[i]; + } + } + } +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef CUSTOM_MODES + if (error) + *error = OPUS_BAD_ARG; + return NULL; +#else + + /* The good thing here is that permutation of the arguments will automatically be invalid */ + + if (Fs < 8000 || Fs > 96000) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + /* Frames of less than 1ms are not supported. */ + if ((opus_int32)frame_size*1000 < Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0) + { + LM = 3; + } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0) + { + LM = 2; + } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0) + { + LM = 1; + } else + { + LM = 0; + } + + /* Shorts longer than 3.3ms are not supported. */ + if ((opus_int32)(frame_size>>LM)*300 > Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + mode = opus_alloc(sizeof(CELTMode)); + if (mode==NULL) + goto failure; + mode->Fs = Fs; + + /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis + is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should + approximate that. */ + if(Fs < 12000) /* 8 kHz */ + { + mode->preemph[0] = QCONST16(0.3500061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(3.6765136719f, 13); + } else if(Fs < 24000) /* 16 kHz */ + { + mode->preemph[0] = QCONST16(0.6000061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(2.2598876953f, 13); + } else if(Fs < 40000) /* 32 kHz */ + { + mode->preemph[0] = QCONST16(0.7799987793f, 15); + mode->preemph[1] = -QCONST16(0.1000061035f, 15); + mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(1.3333740234f, 13); + } else /* 48 kHz */ + { + mode->preemph[0] = QCONST16(0.8500061035f, 15); + mode->preemph[1] = QCONST16(0.0f, 15); + mode->preemph[2] = QCONST16(1.f, SIG_SHIFT); + mode->preemph[3] = QCONST16(1.f, 13); + } + + mode->maxLM = LM; + mode->nbShortMdcts = 1<shortMdctSize = frame_size/mode->nbShortMdcts; + res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize); + + mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands); + if (mode->eBands==NULL) + goto failure; +#if !defined(SMALL_FOOTPRINT) + /* Make sure we don't allocate a band larger than our PVQ table. + 208 should be enough, but let's be paranoid. */ + if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])< + 208) { + goto failure; + } +#endif + + mode->effEBands = mode->nbEBands; + while (mode->eBands[mode->effEBands] > mode->shortMdctSize) + mode->effEBands--; + + /* Overlap must be divisible by 4 */ + mode->overlap = ((mode->shortMdctSize>>2)<<2); + + compute_allocation_table(mode); + if (mode->allocVectors==NULL) + goto failure; + + window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16)); + if (window==NULL) + goto failure; + +#ifndef FIXED_POINT + for (i=0;ioverlap;i++) + window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)); +#else + for (i=0;ioverlap;i++) + window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)))); +#endif + mode->window = window; + + logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16)); + if (logN==NULL) + goto failure; + + for (i=0;inbEBands;i++) + logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES); + mode->logN = logN; + + compute_pulse_cache(mode, mode->maxLM); + + if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts, + mode->maxLM, arch) == 0) + goto failure; + + if (error) + *error = OPUS_OK; + + return mode; +failure: + if (error) + *error = OPUS_ALLOC_FAIL; + if (mode!=NULL) + opus_custom_mode_destroy(mode); + return NULL; +#endif /* !CUSTOM_MODES */ +} + +#ifdef CUSTOM_MODES +void opus_custom_mode_destroy(CELTMode *mode) +{ + int arch = opus_select_arch(); + + if (mode == NULL) + return; +#ifndef CUSTOM_MODES_ONLY + { + int i; + for (i=0;ieBands); + opus_free((unsigned char*)mode->allocVectors); + + opus_free((opus_val16*)mode->window); + opus_free((opus_int16*)mode->logN); + + opus_free((opus_int16*)mode->cache.index); + opus_free((unsigned char*)mode->cache.bits); + opus_free((unsigned char*)mode->cache.caps); + clt_mdct_clear(&mode->mdct, arch); + + opus_free((CELTMode *)mode); +} +#endif diff --git a/native/codec/libraries/opus/celt/modes.h b/native/codec/libraries/opus/celt/modes.h new file mode 100644 index 0000000..be813cc --- /dev/null +++ b/native/codec/libraries/opus/celt/modes.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MODES_H +#define MODES_H + +#include "opus_types.h" +#include "celt.h" +#include "arch.h" +#include "mdct.h" +#include "entenc.h" +#include "entdec.h" + +#define MAX_PERIOD 1024 + +typedef struct { + int size; + const opus_int16 *index; + const unsigned char *bits; + const unsigned char *caps; +} PulseCache; + +/** Mode definition (opaque) + @brief Mode definition + */ +struct OpusCustomMode { + opus_int32 Fs; + int overlap; + + int nbEBands; + int effEBands; + opus_val16 preemph[4]; + const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */ + + int maxLM; + int nbShortMdcts; + int shortMdctSize; + + int nbAllocVectors; /**< Number of lines in the matrix below */ + const unsigned char *allocVectors; /**< Number of bits in each band for several rates */ + const opus_int16 *logN; + + const opus_val16 *window; + mdct_lookup mdct; + PulseCache cache; +}; + + +#endif diff --git a/native/codec/libraries/opus/celt/opus_custom_demo.c b/native/codec/libraries/opus/celt/opus_custom_demo.c new file mode 100644 index 0000000..ae41c0d --- /dev/null +++ b/native/codec/libraries/opus/celt/opus_custom_demo.c @@ -0,0 +1,210 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_custom.h" +#include "arch.h" +#include +#include +#include +#include + +#define MAX_PACKET 1275 + +int main(int argc, char *argv[]) +{ + int err; + char *inFile, *outFile; + FILE *fin, *fout; + OpusCustomMode *mode=NULL; + OpusCustomEncoder *enc; + OpusCustomDecoder *dec; + int len; + opus_int32 frame_size, channels, rate; + int bytes_per_packet; + unsigned char data[MAX_PACKET]; + int complexity; +#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH) + int i; + double rmsd = 0; +#endif + int count = 0; + opus_int32 skip; + opus_int16 *in, *out; + if (argc != 9 && argc != 8 && argc != 7) + { + fprintf (stderr, "Usage: test_opus_custom " + " [ [packet loss rate]] " + " \n"); + return 1; + } + + rate = (opus_int32)atol(argv[1]); + channels = atoi(argv[2]); + frame_size = atoi(argv[3]); + mode = opus_custom_mode_create(rate, frame_size, NULL); + if (mode == NULL) + { + fprintf(stderr, "failed to create a mode\n"); + return 1; + } + + bytes_per_packet = atoi(argv[4]); + if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET) + { + fprintf (stderr, "bytes per packet must be between 0 and %d\n", + MAX_PACKET); + return 1; + } + + inFile = argv[argc-2]; + fin = fopen(inFile, "rb"); + if (!fin) + { + fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); + return 1; + } + outFile = argv[argc-1]; + fout = fopen(outFile, "wb+"); + if (!fout) + { + fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); + fclose(fin); + return 1; + } + + enc = opus_custom_encoder_create(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err)); + fclose(fin); + fclose(fout); + return 1; + } + dec = opus_custom_decoder_create(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err)); + fclose(fin); + fclose(fout); + return 1; + } + opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip)); + + if (argc>7) + { + complexity=atoi(argv[5]); + opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity)); + } + + in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16)); + out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16)); + + while (!feof(fin)) + { + int ret; + err = fread(in, sizeof(short), frame_size*channels, fin); + if (feof(fin)) + break; + len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet); + if (len <= 0) + fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len)); + + /* This is for simulating bit errors */ +#if 0 + int errors = 0; + int eid = 0; + /* This simulates random bit error */ + for (i=0;i 0) + { + rmsd = sqrt(rmsd/(1.0*frame_size*channels*count)); + fprintf (stderr, "Error: encoder doesn't match decoder\n"); + fprintf (stderr, "RMS mismatch is %f\n", rmsd); + return 1; + } else { + fprintf (stderr, "Encoder matches decoder!!\n"); + } +#endif + return 0; +} + diff --git a/native/codec/libraries/opus/celt/os_support.h b/native/codec/libraries/opus/celt/os_support.h new file mode 100644 index 0000000..a217197 --- /dev/null +++ b/native/codec/libraries/opus/celt/os_support.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#ifdef CUSTOM_SUPPORT +# include "custom_support.h" +#endif + +#include "opus_types.h" +#include "opus_defines.h" + +#include +#include +#include + +/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */ +#ifndef OVERRIDE_OPUS_ALLOC +static OPUS_INLINE void *opus_alloc (size_t size) +{ + return malloc(size); +} +#endif + +/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ +#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH +static OPUS_INLINE void *opus_alloc_scratch (size_t size) +{ + /* Scratch space doesn't need to be cleared */ + return opus_alloc(size); +} +#endif + +/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */ +#ifndef OVERRIDE_OPUS_FREE +static OPUS_INLINE void opus_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n elements from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_COPY +#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n elements from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_MOVE +#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n elements of dst to zero */ +#ifndef OVERRIDE_OPUS_CLEAR +#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst)))) +#endif + +/*#ifdef __GNUC__ +#pragma GCC poison printf sprintf +#pragma GCC poison malloc free realloc calloc +#endif*/ + +#endif /* OS_SUPPORT_H */ + diff --git a/native/codec/libraries/opus/celt/pitch.c b/native/codec/libraries/opus/celt/pitch.c new file mode 100644 index 0000000..872582a --- /dev/null +++ b/native/codec/libraries/opus/celt/pitch.c @@ -0,0 +1,537 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.c + @brief Pitch analysis + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pitch.h" +#include "os_support.h" +#include "modes.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "celt_lpc.h" + +static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len, + int max_pitch, int *best_pitch +#ifdef FIXED_POINT + , int yshift, opus_val32 maxcorr +#endif + ) +{ + int i, j; + opus_val32 Syy=1; + opus_val16 best_num[2]; + opus_val32 best_den[2]; +#ifdef FIXED_POINT + int xshift; + + xshift = celt_ilog2(maxcorr)-14; +#endif + + best_num[0] = -1; + best_num[1] = -1; + best_den[0] = 0; + best_den[1] = 0; + best_pitch[0] = 0; + best_pitch[1] = 1; + for (j=0;j0) + { + opus_val16 num; + opus_val32 xcorr16; + xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift)); +#ifndef FIXED_POINT + /* Considering the range of xcorr16, this should avoid both underflows + and overflows (inf) when squaring xcorr16 */ + xcorr16 *= 1e-12f; +#endif + num = MULT16_16_Q15(xcorr16,xcorr16); + if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy)) + { + if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy)) + { + best_num[1] = best_num[0]; + best_den[1] = best_den[0]; + best_pitch[1] = best_pitch[0]; + best_num[0] = num; + best_den[0] = Syy; + best_pitch[0] = i; + } else { + best_num[1] = num; + best_den[1] = Syy; + best_pitch[1] = i; + } + } + } + Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift); + Syy = MAX32(1, Syy); + } +} + +static void celt_fir5(opus_val16 *x, + const opus_val16 *num, + int N) +{ + int i; + opus_val16 num0, num1, num2, num3, num4; + opus_val32 mem0, mem1, mem2, mem3, mem4; + num0=num[0]; + num1=num[1]; + num2=num[2]; + num3=num[3]; + num4=num[4]; + mem0=0; + mem1=0; + mem2=0; + mem3=0; + mem4=0; + for (i=0;i>1;i++) + x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift); + x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift); + if (C==2) + { + for (i=1;i>1;i++) + x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift); + x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift); + } + + _celt_autocorr(x_lp, ac, NULL, 0, + 4, len>>1, arch); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=4;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc, ac, 4); + for (i=0;i<4;i++) + { + tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp); + lpc[i] = MULT16_16_Q15(lpc[i], tmp); + } + /* Add a zero */ + lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT); + lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]); + lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]); + lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]); + lpc2[4] = MULT16_16_Q15(c1,lpc[3]); + celt_fir5(x_lp, lpc2, len>>1); +} + +/* Pure C implementation. */ +#ifdef FIXED_POINT +opus_val32 +#else +void +#endif +celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch) +{ + +#if 0 /* This is a simple version of the pitch correlation that should work + well on DSPs like Blackfin and TI C5x/C6x */ + int i, j; +#ifdef FIXED_POINT + opus_val32 maxcorr=1; +#endif +#if !defined(OVERRIDE_PITCH_XCORR) + (void)arch; +#endif + for (i=0;i0); + celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + for (i=0;i0); + celt_assert(max_pitch>0); + lag = len+max_pitch; + + ALLOC(x_lp4, len>>2, opus_val16); + ALLOC(y_lp4, lag>>2, opus_val16); + ALLOC(xcorr, max_pitch>>1, opus_val32); + + /* Downsample by 2 again */ + for (j=0;j>2;j++) + x_lp4[j] = x_lp[2*j]; + for (j=0;j>2;j++) + y_lp4[j] = y[2*j]; + +#ifdef FIXED_POINT + xmax = celt_maxabs16(x_lp4, len>>2); + ymax = celt_maxabs16(y_lp4, lag>>2); + shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11; + if (shift>0) + { + for (j=0;j>2;j++) + x_lp4[j] = SHR16(x_lp4[j], shift); + for (j=0;j>2;j++) + y_lp4[j] = SHR16(y_lp4[j], shift); + /* Use double the shift for a MAC */ + shift *= 2; + } else { + shift = 0; + } +#endif + + /* Coarse search with 4x decimation */ + +#ifdef FIXED_POINT + maxcorr = +#endif + celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch); + + find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch +#ifdef FIXED_POINT + , 0, maxcorr +#endif + ); + + /* Finer search with 2x decimation */ +#ifdef FIXED_POINT + maxcorr=1; +#endif + for (i=0;i>1;i++) + { + opus_val32 sum; + xcorr[i] = 0; + if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2) + continue; +#ifdef FIXED_POINT + sum = 0; + for (j=0;j>1;j++) + sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift); +#else + sum = celt_inner_prod(x_lp, y+i, len>>1, arch); +#endif + xcorr[i] = MAX32(-1, sum); +#ifdef FIXED_POINT + maxcorr = MAX32(maxcorr, sum); +#endif + } + find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch +#ifdef FIXED_POINT + , shift+1, maxcorr +#endif + ); + + /* Refine by pseudo-interpolation */ + if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1) + { + opus_val32 a, b, c; + a = xcorr[best_pitch[0]-1]; + b = xcorr[best_pitch[0]]; + c = xcorr[best_pitch[0]+1]; + if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a)) + offset = 1; + else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c)) + offset = -1; + else + offset = 0; + } else { + offset = 0; + } + *pitch = 2*best_pitch[0]-offset; + + RESTORE_STACK; +} + +#ifdef FIXED_POINT +static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) +{ + opus_val32 x2y2; + int sx, sy, shift; + opus_val32 g; + opus_val16 den; + if (xy == 0 || xx == 0 || yy == 0) + return 0; + sx = celt_ilog2(xx)-14; + sy = celt_ilog2(yy)-14; + shift = sx + sy; + x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14); + if (shift & 1) { + if (x2y2 < 32768) + { + x2y2 <<= 1; + shift--; + } else { + x2y2 >>= 1; + shift++; + } + } + den = celt_rsqrt_norm(x2y2); + g = MULT16_32_Q15(den, xy); + g = VSHR32(g, (shift>>1)-1); + return EXTRACT16(MIN32(g, Q15ONE)); +} +#else +static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) +{ + return xy/celt_sqrt(1+xx*yy); +} +#endif + +static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; +opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod, + int N, int *T0_, int prev_period, opus_val16 prev_gain, int arch) +{ + int k, i, T, T0; + opus_val16 g, g0; + opus_val16 pg; + opus_val32 xy,xx,yy,xy2; + opus_val32 xcorr[3]; + opus_val32 best_xy, best_yy; + int offset; + int minperiod0; + VARDECL(opus_val32, yy_lookup); + SAVE_STACK; + + minperiod0 = minperiod; + maxperiod /= 2; + minperiod /= 2; + *T0_ /= 2; + prev_period /= 2; + N /= 2; + x += maxperiod; + if (*T0_>=maxperiod) + *T0_=maxperiod-1; + + T = T0 = *T0_; + ALLOC(yy_lookup, maxperiod+1, opus_val32); + dual_inner_prod(x, x, x-T0, N, &xx, &xy, arch); + yy_lookup[0] = xx; + yy=xx; + for (i=1;i<=maxperiod;i++) + { + yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]); + yy_lookup[i] = MAX32(0, yy); + } + yy = yy_lookup[T0]; + best_xy = xy; + best_yy = yy; + g = g0 = compute_pitch_gain(xy, xx, yy); + /* Look for any pitch at T/k */ + for (k=2;k<=15;k++) + { + int T1, T1b; + opus_val16 g1; + opus_val16 cont=0; + opus_val16 thresh; + T1 = celt_udiv(2*T0+k, 2*k); + if (T1 < minperiod) + break; + /* Look for another strong correlation at T1b */ + if (k==2) + { + if (T1+T0>maxperiod) + T1b = T0; + else + T1b = T0+T1; + } else + { + T1b = celt_udiv(2*second_check[k]*T0+k, 2*k); + } + dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2, arch); + xy = HALF32(xy + xy2); + yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]); + g1 = compute_pitch_gain(xy, xx, yy); + if (abs(T1-prev_period)<=1) + cont = prev_gain; + else if (abs(T1-prev_period)<=2 && 5*k*k < T0) + cont = HALF16(prev_gain); + else + cont = 0; + thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont); + /* Bias against very high pitch (very short period) to avoid false-positives + due to short-term correlation */ + if (T1<3*minperiod) + thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont); + else if (T1<2*minperiod) + thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont); + if (g1 > thresh) + { + best_xy = xy; + best_yy = yy; + T = T1; + g = g1; + } + } + best_xy = MAX32(0, best_xy); + if (best_yy <= best_xy) + pg = Q15ONE; + else + pg = SHR32(frac_div32(best_xy,best_yy+1),16); + + for (k=0;k<3;k++) + xcorr[k] = celt_inner_prod(x, x-(T+k-1), N, arch); + if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0])) + offset = 1; + else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2])) + offset = -1; + else + offset = 0; + if (pg > g) + pg = g; + *T0_ = 2*T+offset; + + if (*T0_=3); + y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */ + y_0=*y++; + y_1=*y++; + y_2=*y++; + for (j=0;j +#include "os_support.h" +#include "arch.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "rate.h" + +#ifdef FIXED_POINT +/* Mean energy in each band quantized in Q4 */ +const signed char eMeans[25] = { + 103,100, 92, 85, 81, + 77, 72, 70, 78, 75, + 73, 71, 78, 74, 69, + 72, 70, 74, 76, 71, + 60, 60, 60, 60, 60 +}; +#else +/* Mean energy in each band quantized in Q4 and converted back to float */ +const opus_val16 eMeans[25] = { + 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, + 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, + 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, + 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f, + 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f +}; +#endif +/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */ +#ifdef FIXED_POINT +static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384}; +static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554}; +static const opus_val16 beta_intra = 4915; +#else +static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.}; +static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.}; +static const opus_val16 beta_intra = 4915/32768.; +#endif + +/*Parameters of the Laplace-like probability models used for the coarse energy. + There is one pair of parameters for each frame size, prediction type + (inter/intra), and band number. + The first number of each pair is the probability of 0, and the second is the + decay rate, both in Q8 precision.*/ +static const unsigned char e_prob_model[4][2][42] = { + /*120 sample frames.*/ + { + /*Inter*/ + { + 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, + 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, + 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11 + }, + /*Intra*/ + { + 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, + 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, + 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50 + } + }, + /*240 sample frames.*/ + { + /*Inter*/ + { + 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, + 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, + 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9 + }, + /*Intra*/ + { + 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, + 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, + 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45 + } + }, + /*480 sample frames.*/ + { + /*Inter*/ + { + 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, + 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, + 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10 + }, + /*Intra*/ + { + 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, + 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, + 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42 + } + }, + /*960 sample frames.*/ + { + /*Inter*/ + { + 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, + 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, + 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15 + }, + /*Intra*/ + { + 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, + 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, + 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40 + } + } +}; + +static const unsigned char small_energy_icdf[3]={2,1,0}; + +static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C) +{ + int c, i; + opus_val32 dist = 0; + c=0; do { + for (i=start;inbEBands]; + oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); +#ifdef FIXED_POINT + f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7); + decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT), + SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay))); +#else + f = x-coef*oldE-prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (int)floor(.5f+f); + decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay; +#endif + /* Prevent the energy from going down too quickly (e.g. for bands + that have just one bin) */ + if (qi < 0 && x < decay_bound) + { + qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT); + if (qi > 0) + qi = 0; + } + qi0 = qi; + /* If we don't have enough bits to encode all the energy, just assume + something safe. */ + tell = ec_tell(enc); + bits_left = budget-tell-3*C*(end-i); + if (i!=start && bits_left < 30) + { + if (bits_left < 24) + qi = IMIN(1, qi); + if (bits_left < 16) + qi = IMAX(-1, qi); + } + if (lfe && i>=2) + qi = IMIN(qi, 0); + if (budget-tell >= 15) + { + int pi; + pi = 2*IMIN(i,20); + ec_laplace_encode(enc, &qi, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell >= 2) + { + qi = IMAX(-1, IMIN(qi, 1)); + ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2); + } + else if(budget-tell >= 1) + { + qi = IMIN(0, qi); + ec_enc_bit_logp(enc, -qi, 1); + } + else + qi = -1; + error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT); + badness += abs(qi0-qi); + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } + return lfe ? 0 : badness; +} + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes, + int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate, int lfe) +{ + int intra; + opus_val16 max_decay; + VARDECL(opus_val16, oldEBands_intra); + VARDECL(opus_val16, error_intra); + ec_enc enc_start_state; + opus_uint32 tell; + int badness1=0; + opus_int32 intra_bias; + opus_val32 new_distortion; + SAVE_STACK; + + intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C); + intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512)); + new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C); + + tell = ec_tell(enc); + if (tell+3 > budget) + two_pass = intra = 0; + + max_decay = QCONST16(16.f,DB_SHIFT); + if (end-start>10) + { +#ifdef FIXED_POINT + max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3)); +#else + max_decay = MIN32(max_decay, .125f*nbAvailableBytes); +#endif + } + if (lfe) + max_decay = QCONST16(3.f,DB_SHIFT); + enc_start_state = *enc; + + ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16); + ALLOC(error_intra, C*m->nbEBands, opus_val16); + OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands); + + if (two_pass || intra) + { + badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget, + tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe); + } + + if (!intra) + { + unsigned char *intra_buf; + ec_enc enc_intra_state; + opus_int32 tell_intra; + opus_uint32 nstart_bytes; + opus_uint32 nintra_bytes; + opus_uint32 save_bytes; + int badness2; + VARDECL(unsigned char, intra_bits); + + tell_intra = ec_tell_frac(enc); + + enc_intra_state = *enc; + + nstart_bytes = ec_range_bytes(&enc_start_state); + nintra_bytes = ec_range_bytes(&enc_intra_state); + intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes; + save_bytes = nintra_bytes-nstart_bytes; + if (save_bytes == 0) + save_bytes = ALLOC_NONE; + ALLOC(intra_bits, save_bytes, unsigned char); + /* Copy bits from intra bit-stream */ + OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes); + + *enc = enc_start_state; + + badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget, + tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe); + + if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra))) + { + *enc = enc_intra_state; + /* Copy intra bits to bit-stream */ + OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes); + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + intra = 1; + } + } else { + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + } + + if (intra) + *delayedIntra = new_distortion; + else + *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra), + new_distortion); + + RESTORE_STACK; +} + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C) +{ + int i, c; + + /* Encode finer resolution */ + for (i=start;inbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]); +#else + q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac); +#endif + if (q2 > frac-1) + q2 = frac-1; + if (q2<0) + q2 = 0; + ec_enc_bits(enc, q2, fine_quant[i]); +#ifdef FIXED_POINT + offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT)); +#else + offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f; +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + /*printf ("%f ", error[i] - offset);*/ + } while (++c < C); + } +} + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = error[i+c*m->nbEBands]<0 ? 0 : 1; + ec_enc_bits(enc, q2, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + bits_left--; + } while (++c < C); + } + } +} + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM) +{ + const unsigned char *prob_model = e_prob_model[LM][intra]; + int i, c; + opus_val32 prev[2] = {0, 0}; + opus_val16 coef; + opus_val16 beta; + opus_int32 budget; + opus_int32 tell; + + if (intra) + { + coef = 0; + beta = beta_intra; + } else { + beta = beta_coef[LM]; + coef = pred_coef[LM]; + } + + budget = dec->storage*8; + + /* Decode at a fixed coarse resolution */ + for (i=start;i=15) + { + int pi; + pi = 2*IMIN(i,20); + qi = ec_laplace_decode(dec, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell>=2) + { + qi = ec_dec_icdf(dec, small_energy_icdf, 2); + qi = (qi>>1)^-(qi&1); + } + else if(budget-tell>=1) + { + qi = -ec_dec_bit_logp(dec, 1); + } + else + qi = -1; + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); + tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } +} + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C) +{ + int i, c; + /* Decode finer resolution */ + for (i=start;inbEBands] += offset; + } while (++c < C); + } +} + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = ec_dec_bits(dec, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C) +{ + int c, i; + c=0; + do { + for (i=0;inbEBands] = + celt_log2(bandE[i+c*m->nbEBands]) + - SHL16((opus_val16)eMeans[i],6); +#ifdef FIXED_POINT + /* Compensate for bandE[] being Q12 but celt_log2() taking a Q14 input. */ + bandLogE[i+c*m->nbEBands] += QCONST16(2.f, DB_SHIFT); +#endif + } + for (i=effEnd;inbEBands+i] = -QCONST16(14.f,DB_SHIFT); + } while (++c < C); +} diff --git a/native/codec/libraries/opus/celt/quant_bands.h b/native/codec/libraries/opus/celt/quant_bands.h new file mode 100644 index 0000000..0490bca --- /dev/null +++ b/native/codec/libraries/opus/celt/quant_bands.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef QUANT_BANDS +#define QUANT_BANDS + +#include "arch.h" +#include "modes.h" +#include "entenc.h" +#include "entdec.h" +#include "mathops.h" + +#ifdef FIXED_POINT +extern const signed char eMeans[25]; +#else +extern const opus_val16 eMeans[25]; +#endif + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C); + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, const opus_val16 *oldEBands, int C); + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, + int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra, + int two_pass, int loss_rate, int lfe); + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C); + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C); + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM); + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C); + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C); + +#endif /* QUANT_BANDS */ diff --git a/native/codec/libraries/opus/celt/rate.c b/native/codec/libraries/opus/celt/rate.c new file mode 100644 index 0000000..465e1ba --- /dev/null +++ b/native/codec/libraries/opus/celt/rate.c @@ -0,0 +1,644 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "modes.h" +#include "cwrs.h" +#include "arch.h" +#include "os_support.h" + +#include "entcode.h" +#include "rate.h" + +static const unsigned char LOG2_FRAC_TABLE[24]={ + 0, + 8,13, + 16,19,21,23, + 24,26,27,28,29,30,31,32, + 32,33,34,34,35,36,36,37,37 +}; + +#ifdef CUSTOM_MODES + +/*Determines if V(N,K) fits in a 32-bit unsigned integer. + N and K are themselves limited to 15 bits.*/ +static int fits_in32(int _n, int _k) +{ + static const opus_int16 maxN[15] = { + 32767, 32767, 32767, 1476, 283, 109, 60, 40, + 29, 24, 20, 18, 16, 14, 13}; + static const opus_int16 maxK[15] = { + 32767, 32767, 32767, 32767, 1172, 238, 95, 53, + 36, 27, 22, 18, 16, 15, 13}; + if (_n>=14) + { + if (_k>=14) + return 0; + else + return _n <= maxN[_k]; + } else { + return _k <= maxK[_n]; + } +} + +void compute_pulse_cache(CELTMode *m, int LM) +{ + int C; + int i; + int j; + int curr=0; + int nbEntries=0; + int entryN[100], entryK[100], entryI[100]; + const opus_int16 *eBands = m->eBands; + PulseCache *cache = &m->cache; + opus_int16 *cindex; + unsigned char *bits; + unsigned char *cap; + + cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2)); + cache->index = cindex; + + /* Scan for all unique band sizes */ + for (i=0;i<=LM+1;i++) + { + for (j=0;jnbEBands;j++) + { + int k; + int N = (eBands[j+1]-eBands[j])<>1; + cindex[i*m->nbEBands+j] = -1; + /* Find other bands that have the same size */ + for (k=0;k<=i;k++) + { + int n; + for (n=0;nnbEBands && (k!=i || n>1) + { + cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n]; + break; + } + } + } + if (cache->index[i*m->nbEBands+j] == -1 && N!=0) + { + int K; + entryN[nbEntries] = N; + K = 0; + while (fits_in32(N,get_pulses(K+1)) && KnbEBands+j] = curr; + entryI[nbEntries] = curr; + + curr += K+1; + nbEntries++; + } + } + } + bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr); + cache->bits = bits; + cache->size = curr; + /* Compute the cache for all unique sizes */ + for (i=0;icaps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands); + for (i=0;i<=LM;i++) + { + for (C=1;C<=2;C++) + { + for (j=0;jnbEBands;j++) + { + int N0; + int max_bits; + N0 = m->eBands[j+1]-m->eBands[j]; + /* N=1 bands only have a sign bit and fine bits. */ + if (N0<1 are even, including custom modes.*/ + if (N0 > 2) + { + N0>>=1; + LM0--; + } + /* N0=1 bands can't be split down to N<2. */ + else if (N0 <= 1) + { + LM0=IMIN(i,1); + N0<<=LM0; + } + /* Compute the cost for the lowest-level PVQ of a fully split + band. */ + pcache = bits + cindex[(LM0+1)*m->nbEBands+j]; + max_bits = pcache[pcache[0]]+1; + /* Add in the cost of coding regular splits. */ + N = N0; + for(k=0;klogN[j]+((LM0+k)<>1)-QTHETA_OFFSET; + /* The number of qtheta bits we'll allocate if the remainder + is to be max_bits. + The average measured cost for theta is 0.89701 times qb, + approximated here as 459/512. */ + num=459*(opus_int32)((2*N-1)*offset+max_bits); + den=((opus_int32)(2*N-1)<<9)-459; + qb = IMIN((num+(den>>1))/den, 57); + celt_assert(qb >= 0); + max_bits += qb; + N <<= 1; + } + /* Add in the cost of a stereo split, if necessary. */ + if (C==2) + { + max_bits <<= 1; + offset = ((m->logN[j]+(i<>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET); + ndof = 2*N-1-(N==2); + /* The average measured cost for theta with the step PDF is + 0.95164 times qb, approximated here as 487/512. */ + num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset); + den = ((opus_int32)ndof<<9)-(N==2?512:487); + qb = IMIN((num+(den>>1))/den, (N==2?64:61)); + celt_assert(qb >= 0); + max_bits += qb; + } + /* Add the fine bits we'll use. */ + /* Compensate for the extra DoF in stereo */ + ndof = C*N + ((C==2 && N>2) ? 1 : 0); + /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = ((m->logN[j] + (i<>1)-FINE_OFFSET; + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += 1<>2; + /* The number of fine bits we'll allocate if the remainder is + to be max_bits. */ + num = max_bits+ndof*offset; + den = (ndof-1)<>1))/den, MAX_FINE_BITS); + celt_assert(qb >= 0); + max_bits += C*qb<eBands[j+1]-m->eBands[j])<= 0); + celt_assert(max_bits < 256); + *cap++ = (unsigned char)max_bits; + } + } + } +} + +#endif /* CUSTOM_MODES */ + +#define ALLOC_STEPS 6 + +static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start, + const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance, + int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits, + int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth) +{ + opus_int32 psum; + int lo, hi; + int i, j; + int logM; + int stereo; + int codedBands=-1; + int alloc_floor; + opus_int32 left, percoeff; + int done; + opus_int32 balance; + SAVE_STACK; + + alloc_floor = C<1; + + logM = LM<>1; + psum = 0; + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS); + if (tmp >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(tmp, cap[j]); + } else { + if (tmp >= alloc_floor) + psum += alloc_floor; + } + } + if (psum > total) + hi = mid; + else + lo = mid; + } + psum = 0; + /*printf ("interp bisection gave %d\n", lo);*/ + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + ((opus_int32)lo*bits2[j]>>ALLOC_STEPS); + if (tmp < thresh[j] && !done) + { + if (tmp >= alloc_floor) + tmp = alloc_floor; + else + tmp = 0; + } else + done = 1; + /* Don't allocate more than we can actually use */ + tmp = IMIN(tmp, cap[j]); + bits[j] = tmp; + psum += tmp; + } + + /* Decide which bands to skip, working backwards from the end. */ + for (codedBands=end;;codedBands--) + { + int band_width; + int band_bits; + int rem; + j = codedBands-1; + /* Never skip the first band, nor a band that has been boosted by + dynalloc. + In the first case, we'd be coding a bit to signal we're going to waste + all the other bits. + In the second case, we'd be coding a bit to redistribute all the bits + we just signaled should be cocentrated in this band. */ + if (j<=skip_start) + { + /* Give the bit we reserved to end skipping back. */ + total += skip_rsv; + break; + } + /*Figure out how many left-over bits we would be adding to this band. + This can include bits we've stolen back from higher, skipped bands.*/ + left = total-psum; + percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0); + band_width = m->eBands[codedBands]-m->eBands[j]; + band_bits = (int)(bits[j] + percoeff*band_width + rem); + /*Only code a skip decision if we're above the threshold for this band. + Otherwise it is force-skipped. + This ensures that we have enough bits to code the skip flag.*/ + if (band_bits >= IMAX(thresh[j], alloc_floor+(1< 17) + depth_threshold = j (depth_threshold*band_width<>4 && j<=signalBandwidth)) +#endif + { + ec_enc_bit_logp(ec, 1, 1); + break; + } + ec_enc_bit_logp(ec, 0, 1); + } else if (ec_dec_bit_logp(ec, 1)) { + break; + } + /*We used a bit to skip this band.*/ + psum += 1< 0) + intensity_rsv = LOG2_FRAC_TABLE[j-start]; + psum += intensity_rsv; + if (band_bits >= alloc_floor) + { + /*If we have enough for a fine energy bit per channel, use it.*/ + psum += alloc_floor; + bits[j] = alloc_floor; + } else { + /*Otherwise this band gets nothing at all.*/ + bits[j] = 0; + } + } + + celt_assert(codedBands > start); + /* Code the intensity and dual stereo parameters. */ + if (intensity_rsv > 0) + { + if (encode) + { + *intensity = IMIN(*intensity, codedBands); + ec_enc_uint(ec, *intensity-start, codedBands+1-start); + } + else + *intensity = start+ec_dec_uint(ec, codedBands+1-start); + } + else + *intensity = 0; + if (*intensity <= start) + { + total += dual_stereo_rsv; + dual_stereo_rsv = 0; + } + if (dual_stereo_rsv > 0) + { + if (encode) + ec_enc_bit_logp(ec, *dual_stereo, 1); + else + *dual_stereo = ec_dec_bit_logp(ec, 1); + } + else + *dual_stereo = 0; + + /* Allocate the remaining bits */ + left = total-psum; + percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + for (j=start;jeBands[j+1]-m->eBands[j])); + for (j=start;jeBands[j+1]-m->eBands[j]); + bits[j] += tmp; + left -= tmp; + } + /*for (j=0;j= 0); + N0 = m->eBands[j+1]-m->eBands[j]; + N=N0<1) + { + excess = MAX32(bit-cap[j],0); + bits[j] = bit-excess; + + /* Compensate for the extra DoF in stereo */ + den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0)); + + NClogN = den*(m->logN[j] + logM); + + /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = (NClogN>>1)-den*FINE_OFFSET; + + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += den<>2; + + /* Changing the offset for allocating the second and third + fine energy bit */ + if (bits[j] + offset < den*2<>2; + else if (bits[j] + offset < den*3<>3; + + /* Divide with rounding */ + ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1)))); + ebits[j] = celt_udiv(ebits[j], den)>>BITRES; + + /* Make sure not to bust */ + if (C*ebits[j] > (bits[j]>>BITRES)) + ebits[j] = bits[j] >> stereo >> BITRES; + + /* More than that is useless because that's about as far as PVQ can go */ + ebits[j] = IMIN(ebits[j], MAX_FINE_BITS); + + /* If we rounded down or capped this band, make it a candidate for the + final fine energy pass */ + fine_priority[j] = ebits[j]*(den<= bits[j]+offset; + + /* Remove the allocated fine bits; the rest are assigned to PVQ */ + bits[j] -= C*ebits[j]< 0) + { + int extra_fine; + int extra_bits; + extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]); + ebits[j] += extra_fine; + extra_bits = extra_fine*C<= excess-balance; + excess -= extra_bits; + } + balance = excess; + + celt_assert(bits[j] >= 0); + celt_assert(ebits[j] >= 0); + } + /* Save any remaining bits over the cap for the rebalancing in + quant_all_bands(). */ + *_balance = balance; + + /* The skipped bands use all their bits for fine energy. */ + for (;j> stereo >> BITRES; + celt_assert(C*ebits[j]<nbEBands; + skip_start = start; + /* Reserve a bit to signal the end of manually skipped bands. */ + skip_rsv = total >= 1<total) + intensity_rsv = 0; + else + { + total -= intensity_rsv; + dual_stereo_rsv = total>=1<eBands[j+1]-m->eBands[j])<>4); + /* Tilt of the allocation curve */ + trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1) + *(1<<(LM+BITRES))>>6; + /* Giving less resolution to single-coefficient bands because they get + more benefit from having one coarse value per coefficient*/ + if ((m->eBands[j+1]-m->eBands[j])<nbAllocVectors - 1; + do + { + int done = 0; + int psum = 0; + int mid = (lo+hi) >> 1; + for (j=end;j-->start;) + { + int bitsj; + int N = m->eBands[j+1]-m->eBands[j]; + bitsj = C*N*m->allocVectors[mid*len+j]<>2; + if (bitsj > 0) + bitsj = IMAX(0, bitsj + trim_offset[j]); + bitsj += offsets[j]; + if (bitsj >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(bitsj, cap[j]); + } else { + if (bitsj >= C< total) + hi = mid - 1; + else + lo = mid + 1; + /*printf ("lo = %d, hi = %d\n", lo, hi);*/ + } + while (lo <= hi); + hi = lo--; + /*printf ("interp between %d and %d\n", lo, hi);*/ + for (j=start;jeBands[j+1]-m->eBands[j]; + bits1j = C*N*m->allocVectors[lo*len+j]<>2; + bits2j = hi>=m->nbAllocVectors ? + cap[j] : C*N*m->allocVectors[hi*len+j]<>2; + if (bits1j > 0) + bits1j = IMAX(0, bits1j + trim_offset[j]); + if (bits2j > 0) + bits2j = IMAX(0, bits2j + trim_offset[j]); + if (lo > 0) + bits1j += offsets[j]; + bits2j += offsets[j]; + if (offsets[j]>0) + skip_start = j; + bits2j = IMAX(0,bits2j-bits1j); + bits1[j] = bits1j; + bits2[j] = bits2j; + } + codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap, + total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv, + pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth); + RESTORE_STACK; + return codedBands; +} + diff --git a/native/codec/libraries/opus/celt/rate.h b/native/codec/libraries/opus/celt/rate.h new file mode 100644 index 0000000..fad5e41 --- /dev/null +++ b/native/codec/libraries/opus/celt/rate.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RATE_H +#define RATE_H + +#define MAX_PSEUDO 40 +#define LOG_MAX_PSEUDO 6 + +#define CELT_MAX_PULSES 128 + +#define MAX_FINE_BITS 8 + +#define FINE_OFFSET 21 +#define QTHETA_OFFSET 4 +#define QTHETA_OFFSET_TWOPHASE 16 + +#include "cwrs.h" +#include "modes.h" + +void compute_pulse_cache(CELTMode *m, int LM); + +static OPUS_INLINE int get_pulses(int i) +{ + return i<8 ? i : (8 + (i&7)) << ((i>>3)-1); +} + +static OPUS_INLINE int bits2pulses(const CELTMode *m, int band, int LM, int bits) +{ + int i; + int lo, hi; + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + + lo = 0; + hi = cache[0]; + bits--; + for (i=0;i>1; + /* OPT: Make sure this is implemented with a conditional move */ + if ((int)cache[mid] >= bits) + hi = mid; + else + lo = mid; + } + if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits) + return lo; + else + return hi; +} + +static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int pulses) +{ + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + return pulses == 0 ? 0 : cache[pulses]+1; +} + +/** Compute the pulse allocation, i.e. how many pulses will go in each + * band. + @param m mode + @param offsets Requested increase or decrease in the number of bits for + each band + @param total Number of bands + @param pulses Number of pulses per band (returned) + @return Total number of bits allocated +*/ +int clt_compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo, + opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth); + +#endif diff --git a/native/codec/libraries/opus/celt/stack_alloc.h b/native/codec/libraries/opus/celt/stack_alloc.h new file mode 100644 index 0000000..2b51c8d --- /dev/null +++ b/native/codec/libraries/opus/celt/stack_alloc.h @@ -0,0 +1,184 @@ +/* Copyright (C) 2002-2003 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#include "opus_types.h" +#include "opus_defines.h" + +#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK)) +#error "Opus requires one of VAR_ARRAYS, USE_ALLOCA, or NONTHREADSAFE_PSEUDOSTACK be defined to select the temporary allocation mode." +#endif + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#if defined(VAR_ARRAYS) + +#define VARDECL(type, var) +#define ALLOC(var, size, type) type var[size] +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK +/* C99 does not allow VLAs of size zero */ +#define ALLOC_NONE 1 + +#elif defined(USE_ALLOCA) + +#define VARDECL(type, var) type *var + +# ifdef WIN32 +# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size))) +# else +# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size))) +# endif + +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK +#define ALLOC_NONE 0 + +#else + +#ifdef CELT_C +char *scratch_ptr=0; +char *global_stack=0; +#else +extern char *global_stack; +extern char *scratch_ptr; +#endif /* CELT_C */ + +#ifdef ENABLE_VALGRIND + +#include + +#ifdef CELT_C +char *global_stack_top=0; +#else +extern char *global_stack_top; +#endif /* CELT_C */ + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char)))) +#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)) +#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack; + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char)))) +#if 0 /* Set this to 1 to instrument pseudostack usage */ +#define RESTORE_STACK (printf("%ld %s:%d\n", global_stack-scratch_ptr, __FILE__, __LINE__),global_stack = _saved_stack) +#else +#define RESTORE_STACK (global_stack = _saved_stack) +#endif +#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? (scratch_ptr=opus_alloc_scratch(GLOBAL_STACK_SIZE)) : global_stack); _saved_stack = global_stack; + +#endif /* ENABLE_VALGRIND */ + +#include "os_support.h" +#define VARDECL(type, var) type *var +#define ALLOC(var, size, type) var = PUSH(global_stack, size, type) +#define SAVE_STACK char *_saved_stack = global_stack; +#define ALLOC_NONE 0 + +#endif /* VAR_ARRAYS */ + + +#ifdef ENABLE_VALGRIND + +#include +#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr)) +#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value) +#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr)) +#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value) +#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0) +#define OPUS_FPRINTF fprintf + +#else + +static OPUS_INLINE int _opus_false(void) {return 0;} +#define OPUS_CHECK_ARRAY(ptr, len) _opus_false() +#define OPUS_CHECK_VALUE(value) _opus_false() +#define OPUS_PRINT_INT(value) do{}while(0) +#define OPUS_FPRINTF (void) + +#endif + + +#endif /* STACK_ALLOC_H */ diff --git a/native/codec/libraries/opus/celt/static_modes_fixed.h b/native/codec/libraries/opus/celt/static_modes_fixed.h new file mode 100644 index 0000000..8717d62 --- /dev/null +++ b/native/codec/libraries/opus/celt/static_modes_fixed.h @@ -0,0 +1,892 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifdef HAVE_ARM_NE10 +#define OVERRIDE_FFT 1 +#include "static_modes_fixed_arm_ne10.h" +#endif + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +2, 20, 55, 108, 178, +266, 372, 494, 635, 792, +966, 1157, 1365, 1590, 1831, +2089, 2362, 2651, 2956, 3276, +3611, 3961, 4325, 4703, 5094, +5499, 5916, 6346, 6788, 7241, +7705, 8179, 8663, 9156, 9657, +10167, 10684, 11207, 11736, 12271, +12810, 13353, 13899, 14447, 14997, +15547, 16098, 16648, 17197, 17744, +18287, 18827, 19363, 19893, 20418, +20936, 21447, 21950, 22445, 22931, +23407, 23874, 24330, 24774, 25208, +25629, 26039, 26435, 26819, 27190, +27548, 27893, 28224, 28541, 28845, +29135, 29411, 29674, 29924, 30160, +30384, 30594, 30792, 30977, 31151, +31313, 31463, 31602, 31731, 31849, +31958, 32057, 32148, 32229, 32303, +32370, 32429, 32481, 32528, 32568, +32604, 32634, 32661, 32683, 32701, +32717, 32729, 32740, 32748, 32754, +32758, 32762, 32764, 32766, 32767, +32767, 32767, 32767, 32767, 32767, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{32767, 0}, {32766, -429}, +{32757, -858}, {32743, -1287}, +{32724, -1715}, {32698, -2143}, +{32667, -2570}, {32631, -2998}, +{32588, -3425}, {32541, -3851}, +{32488, -4277}, {32429, -4701}, +{32364, -5125}, {32295, -5548}, +{32219, -5971}, {32138, -6393}, +{32051, -6813}, {31960, -7231}, +{31863, -7650}, {31760, -8067}, +{31652, -8481}, {31539, -8895}, +{31419, -9306}, {31294, -9716}, +{31165, -10126}, {31030, -10532}, +{30889, -10937}, {30743, -11340}, +{30592, -11741}, {30436, -12141}, +{30274, -12540}, {30107, -12935}, +{29936, -13328}, {29758, -13718}, +{29577, -14107}, {29390, -14493}, +{29197, -14875}, {29000, -15257}, +{28797, -15635}, {28590, -16010}, +{28379, -16384}, {28162, -16753}, +{27940, -17119}, {27714, -17484}, +{27482, -17845}, {27246, -18205}, +{27006, -18560}, {26760, -18911}, +{26510, -19260}, {26257, -19606}, +{25997, -19947}, {25734, -20286}, +{25466, -20621}, {25194, -20952}, +{24918, -21281}, {24637, -21605}, +{24353, -21926}, {24063, -22242}, +{23770, -22555}, {23473, -22865}, +{23171, -23171}, {22866, -23472}, +{22557, -23769}, {22244, -24063}, +{21927, -24352}, {21606, -24636}, +{21282, -24917}, {20954, -25194}, +{20622, -25465}, {20288, -25733}, +{19949, -25997}, {19607, -26255}, +{19261, -26509}, {18914, -26760}, +{18561, -27004}, {18205, -27246}, +{17846, -27481}, {17485, -27713}, +{17122, -27940}, {16755, -28162}, +{16385, -28378}, {16012, -28590}, +{15636, -28797}, {15258, -28999}, +{14878, -29197}, {14494, -29389}, +{14108, -29576}, {13720, -29757}, +{13329, -29934}, {12937, -30107}, +{12540, -30274}, {12142, -30435}, +{11744, -30592}, {11342, -30743}, +{10939, -30889}, {10534, -31030}, +{10127, -31164}, {9718, -31294}, +{9307, -31418}, {8895, -31537}, +{8482, -31652}, {8067, -31759}, +{7650, -31862}, {7233, -31960}, +{6815, -32051}, {6393, -32138}, +{5973, -32219}, {5549, -32294}, +{5127, -32364}, {4703, -32429}, +{4278, -32487}, {3852, -32541}, +{3426, -32588}, {2999, -32630}, +{2572, -32667}, {2144, -32698}, +{1716, -32724}, {1287, -32742}, +{860, -32757}, {430, -32766}, +{0, -32767}, {-429, -32766}, +{-858, -32757}, {-1287, -32743}, +{-1715, -32724}, {-2143, -32698}, +{-2570, -32667}, {-2998, -32631}, +{-3425, -32588}, {-3851, -32541}, +{-4277, -32488}, {-4701, -32429}, +{-5125, -32364}, {-5548, -32295}, +{-5971, -32219}, {-6393, -32138}, +{-6813, -32051}, {-7231, -31960}, +{-7650, -31863}, {-8067, -31760}, +{-8481, -31652}, {-8895, -31539}, +{-9306, -31419}, {-9716, -31294}, +{-10126, -31165}, {-10532, -31030}, +{-10937, -30889}, {-11340, -30743}, +{-11741, -30592}, {-12141, -30436}, +{-12540, -30274}, {-12935, -30107}, +{-13328, -29936}, {-13718, -29758}, +{-14107, -29577}, {-14493, -29390}, +{-14875, -29197}, {-15257, -29000}, +{-15635, -28797}, {-16010, -28590}, +{-16384, -28379}, {-16753, -28162}, +{-17119, -27940}, {-17484, -27714}, +{-17845, -27482}, {-18205, -27246}, +{-18560, -27006}, {-18911, -26760}, +{-19260, -26510}, {-19606, -26257}, +{-19947, -25997}, {-20286, -25734}, +{-20621, -25466}, {-20952, -25194}, +{-21281, -24918}, {-21605, -24637}, +{-21926, -24353}, {-22242, -24063}, +{-22555, -23770}, {-22865, -23473}, +{-23171, -23171}, {-23472, -22866}, +{-23769, -22557}, {-24063, -22244}, +{-24352, -21927}, {-24636, -21606}, +{-24917, -21282}, {-25194, -20954}, +{-25465, -20622}, {-25733, -20288}, +{-25997, -19949}, {-26255, -19607}, +{-26509, -19261}, {-26760, -18914}, +{-27004, -18561}, {-27246, -18205}, +{-27481, -17846}, {-27713, -17485}, +{-27940, -17122}, {-28162, -16755}, +{-28378, -16385}, {-28590, -16012}, +{-28797, -15636}, {-28999, -15258}, +{-29197, -14878}, {-29389, -14494}, +{-29576, -14108}, {-29757, -13720}, +{-29934, -13329}, {-30107, -12937}, +{-30274, -12540}, {-30435, -12142}, +{-30592, -11744}, {-30743, -11342}, +{-30889, -10939}, {-31030, -10534}, +{-31164, -10127}, {-31294, -9718}, +{-31418, -9307}, {-31537, -8895}, +{-31652, -8482}, {-31759, -8067}, +{-31862, -7650}, {-31960, -7233}, +{-32051, -6815}, {-32138, -6393}, +{-32219, -5973}, {-32294, -5549}, +{-32364, -5127}, {-32429, -4703}, +{-32487, -4278}, {-32541, -3852}, +{-32588, -3426}, {-32630, -2999}, +{-32667, -2572}, {-32698, -2144}, +{-32724, -1716}, {-32742, -1287}, +{-32757, -860}, {-32766, -430}, +{-32767, 0}, {-32766, 429}, +{-32757, 858}, {-32743, 1287}, +{-32724, 1715}, {-32698, 2143}, +{-32667, 2570}, {-32631, 2998}, +{-32588, 3425}, {-32541, 3851}, +{-32488, 4277}, {-32429, 4701}, +{-32364, 5125}, {-32295, 5548}, +{-32219, 5971}, {-32138, 6393}, +{-32051, 6813}, {-31960, 7231}, +{-31863, 7650}, {-31760, 8067}, +{-31652, 8481}, {-31539, 8895}, +{-31419, 9306}, {-31294, 9716}, +{-31165, 10126}, {-31030, 10532}, +{-30889, 10937}, {-30743, 11340}, +{-30592, 11741}, {-30436, 12141}, +{-30274, 12540}, {-30107, 12935}, +{-29936, 13328}, {-29758, 13718}, +{-29577, 14107}, {-29390, 14493}, +{-29197, 14875}, {-29000, 15257}, +{-28797, 15635}, {-28590, 16010}, +{-28379, 16384}, {-28162, 16753}, +{-27940, 17119}, {-27714, 17484}, +{-27482, 17845}, {-27246, 18205}, +{-27006, 18560}, {-26760, 18911}, +{-26510, 19260}, {-26257, 19606}, +{-25997, 19947}, {-25734, 20286}, +{-25466, 20621}, {-25194, 20952}, +{-24918, 21281}, {-24637, 21605}, +{-24353, 21926}, {-24063, 22242}, +{-23770, 22555}, {-23473, 22865}, +{-23171, 23171}, {-22866, 23472}, +{-22557, 23769}, {-22244, 24063}, +{-21927, 24352}, {-21606, 24636}, +{-21282, 24917}, {-20954, 25194}, +{-20622, 25465}, {-20288, 25733}, +{-19949, 25997}, {-19607, 26255}, +{-19261, 26509}, {-18914, 26760}, +{-18561, 27004}, {-18205, 27246}, +{-17846, 27481}, {-17485, 27713}, +{-17122, 27940}, {-16755, 28162}, +{-16385, 28378}, {-16012, 28590}, +{-15636, 28797}, {-15258, 28999}, +{-14878, 29197}, {-14494, 29389}, +{-14108, 29576}, {-13720, 29757}, +{-13329, 29934}, {-12937, 30107}, +{-12540, 30274}, {-12142, 30435}, +{-11744, 30592}, {-11342, 30743}, +{-10939, 30889}, {-10534, 31030}, +{-10127, 31164}, {-9718, 31294}, +{-9307, 31418}, {-8895, 31537}, +{-8482, 31652}, {-8067, 31759}, +{-7650, 31862}, {-7233, 31960}, +{-6815, 32051}, {-6393, 32138}, +{-5973, 32219}, {-5549, 32294}, +{-5127, 32364}, {-4703, 32429}, +{-4278, 32487}, {-3852, 32541}, +{-3426, 32588}, {-2999, 32630}, +{-2572, 32667}, {-2144, 32698}, +{-1716, 32724}, {-1287, 32742}, +{-860, 32757}, {-430, 32766}, +{0, 32767}, {429, 32766}, +{858, 32757}, {1287, 32743}, +{1715, 32724}, {2143, 32698}, +{2570, 32667}, {2998, 32631}, +{3425, 32588}, {3851, 32541}, +{4277, 32488}, {4701, 32429}, +{5125, 32364}, {5548, 32295}, +{5971, 32219}, {6393, 32138}, +{6813, 32051}, {7231, 31960}, +{7650, 31863}, {8067, 31760}, +{8481, 31652}, {8895, 31539}, +{9306, 31419}, {9716, 31294}, +{10126, 31165}, {10532, 31030}, +{10937, 30889}, {11340, 30743}, +{11741, 30592}, {12141, 30436}, +{12540, 30274}, {12935, 30107}, +{13328, 29936}, {13718, 29758}, +{14107, 29577}, {14493, 29390}, +{14875, 29197}, {15257, 29000}, +{15635, 28797}, {16010, 28590}, +{16384, 28379}, {16753, 28162}, +{17119, 27940}, {17484, 27714}, +{17845, 27482}, {18205, 27246}, +{18560, 27006}, {18911, 26760}, +{19260, 26510}, {19606, 26257}, +{19947, 25997}, {20286, 25734}, +{20621, 25466}, {20952, 25194}, +{21281, 24918}, {21605, 24637}, +{21926, 24353}, {22242, 24063}, +{22555, 23770}, {22865, 23473}, +{23171, 23171}, {23472, 22866}, +{23769, 22557}, {24063, 22244}, +{24352, 21927}, {24636, 21606}, +{24917, 21282}, {25194, 20954}, +{25465, 20622}, {25733, 20288}, +{25997, 19949}, {26255, 19607}, +{26509, 19261}, {26760, 18914}, +{27004, 18561}, {27246, 18205}, +{27481, 17846}, {27713, 17485}, +{27940, 17122}, {28162, 16755}, +{28378, 16385}, {28590, 16012}, +{28797, 15636}, {28999, 15258}, +{29197, 14878}, {29389, 14494}, +{29576, 14108}, {29757, 13720}, +{29934, 13329}, {30107, 12937}, +{30274, 12540}, {30435, 12142}, +{30592, 11744}, {30743, 11342}, +{30889, 10939}, {31030, 10534}, +{31164, 10127}, {31294, 9718}, +{31418, 9307}, {31537, 8895}, +{31652, 8482}, {31759, 8067}, +{31862, 7650}, {31960, 7233}, +{32051, 6815}, {32138, 6393}, +{32219, 5973}, {32294, 5549}, +{32364, 5127}, {32429, 4703}, +{32487, 4278}, {32541, 3852}, +{32588, 3426}, {32630, 2999}, +{32667, 2572}, {32698, 2144}, +{32724, 1716}, {32742, 1287}, +{32757, 860}, {32766, 430}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, +8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, +16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464, +24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, +4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, +12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, +20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, +28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, +1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, +9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, +17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465, +25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, +5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, +13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, +21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, +29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, +2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, +10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, +18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466, +26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, +6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, +14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, +22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, +30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, +3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, +11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, +19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467, +27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, +7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, +15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, +23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, +31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, +4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, +8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232, +12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, +1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, +5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, +9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, +13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, +2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, +6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, +10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234, +14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, +3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, +7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, +11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, +15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, +4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, +1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113, +5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, +2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, +6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, +3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, +7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, +1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, +2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, +3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +17476, /* scale */ +8, /* scale_shift */ +-1, /* shift */ +{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_480, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +17476, /* scale */ +7, /* scale_shift */ +1, /* shift */ +{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_240, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +17476, /* scale */ +6, /* scale_shift */ +2, /* shift */ +{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_120, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +17476, /* scale */ +5, /* scale_shift */ +3, /* shift */ +{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_60, +#else +NULL, +#endif +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[1800] = { +32767, 32767, 32767, 32766, 32765, +32763, 32761, 32759, 32756, 32753, +32750, 32746, 32742, 32738, 32733, +32728, 32722, 32717, 32710, 32704, +32697, 32690, 32682, 32674, 32666, +32657, 32648, 32639, 32629, 32619, +32609, 32598, 32587, 32576, 32564, +32552, 32539, 32526, 32513, 32500, +32486, 32472, 32457, 32442, 32427, +32411, 32395, 32379, 32362, 32345, +32328, 32310, 32292, 32274, 32255, +32236, 32217, 32197, 32177, 32157, +32136, 32115, 32093, 32071, 32049, +32027, 32004, 31981, 31957, 31933, +31909, 31884, 31859, 31834, 31809, +31783, 31756, 31730, 31703, 31676, +31648, 31620, 31592, 31563, 31534, +31505, 31475, 31445, 31415, 31384, +31353, 31322, 31290, 31258, 31226, +31193, 31160, 31127, 31093, 31059, +31025, 30990, 30955, 30920, 30884, +30848, 30812, 30775, 30738, 30701, +30663, 30625, 30587, 30548, 30509, +30470, 30430, 30390, 30350, 30309, +30269, 30227, 30186, 30144, 30102, +30059, 30016, 29973, 29930, 29886, +29842, 29797, 29752, 29707, 29662, +29616, 29570, 29524, 29477, 29430, +29383, 29335, 29287, 29239, 29190, +29142, 29092, 29043, 28993, 28943, +28892, 28842, 28791, 28739, 28688, +28636, 28583, 28531, 28478, 28425, +28371, 28317, 28263, 28209, 28154, +28099, 28044, 27988, 27932, 27876, +27820, 27763, 27706, 27648, 27591, +27533, 27474, 27416, 27357, 27298, +27238, 27178, 27118, 27058, 26997, +26936, 26875, 26814, 26752, 26690, +26628, 26565, 26502, 26439, 26375, +26312, 26247, 26183, 26119, 26054, +25988, 25923, 25857, 25791, 25725, +25658, 25592, 25524, 25457, 25389, +25322, 25253, 25185, 25116, 25047, +24978, 24908, 24838, 24768, 24698, +24627, 24557, 24485, 24414, 24342, +24270, 24198, 24126, 24053, 23980, +23907, 23834, 23760, 23686, 23612, +23537, 23462, 23387, 23312, 23237, +23161, 23085, 23009, 22932, 22856, +22779, 22701, 22624, 22546, 22468, +22390, 22312, 22233, 22154, 22075, +21996, 21916, 21836, 21756, 21676, +21595, 21515, 21434, 21352, 21271, +21189, 21107, 21025, 20943, 20860, +20777, 20694, 20611, 20528, 20444, +20360, 20276, 20192, 20107, 20022, +19937, 19852, 19767, 19681, 19595, +19509, 19423, 19336, 19250, 19163, +19076, 18988, 18901, 18813, 18725, +18637, 18549, 18460, 18372, 18283, +18194, 18104, 18015, 17925, 17835, +17745, 17655, 17565, 17474, 17383, +17292, 17201, 17110, 17018, 16927, +16835, 16743, 16650, 16558, 16465, +16372, 16279, 16186, 16093, 15999, +15906, 15812, 15718, 15624, 15529, +15435, 15340, 15245, 15150, 15055, +14960, 14864, 14769, 14673, 14577, +14481, 14385, 14288, 14192, 14095, +13998, 13901, 13804, 13706, 13609, +13511, 13414, 13316, 13218, 13119, +13021, 12923, 12824, 12725, 12626, +12527, 12428, 12329, 12230, 12130, +12030, 11930, 11831, 11730, 11630, +11530, 11430, 11329, 11228, 11128, +11027, 10926, 10824, 10723, 10622, +10520, 10419, 10317, 10215, 10113, +10011, 9909, 9807, 9704, 9602, +9499, 9397, 9294, 9191, 9088, +8985, 8882, 8778, 8675, 8572, +8468, 8364, 8261, 8157, 8053, +7949, 7845, 7741, 7637, 7532, +7428, 7323, 7219, 7114, 7009, +6905, 6800, 6695, 6590, 6485, +6380, 6274, 6169, 6064, 5958, +5853, 5747, 5642, 5536, 5430, +5325, 5219, 5113, 5007, 4901, +4795, 4689, 4583, 4476, 4370, +4264, 4157, 4051, 3945, 3838, +3732, 3625, 3518, 3412, 3305, +3198, 3092, 2985, 2878, 2771, +2664, 2558, 2451, 2344, 2237, +2130, 2023, 1916, 1809, 1702, +1594, 1487, 1380, 1273, 1166, +1059, 952, 844, 737, 630, +523, 416, 308, 201, 94, +-13, -121, -228, -335, -442, +-550, -657, -764, -871, -978, +-1086, -1193, -1300, -1407, -1514, +-1621, -1728, -1835, -1942, -2049, +-2157, -2263, -2370, -2477, -2584, +-2691, -2798, -2905, -3012, -3118, +-3225, -3332, -3439, -3545, -3652, +-3758, -3865, -3971, -4078, -4184, +-4290, -4397, -4503, -4609, -4715, +-4821, -4927, -5033, -5139, -5245, +-5351, -5457, -5562, -5668, -5774, +-5879, -5985, -6090, -6195, -6301, +-6406, -6511, -6616, -6721, -6826, +-6931, -7036, -7140, -7245, -7349, +-7454, -7558, -7663, -7767, -7871, +-7975, -8079, -8183, -8287, -8390, +-8494, -8597, -8701, -8804, -8907, +-9011, -9114, -9217, -9319, -9422, +-9525, -9627, -9730, -9832, -9934, +-10037, -10139, -10241, -10342, -10444, +-10546, -10647, -10748, -10850, -10951, +-11052, -11153, -11253, -11354, -11455, +-11555, -11655, -11756, -11856, -11955, +-12055, -12155, -12254, -12354, -12453, +-12552, -12651, -12750, -12849, -12947, +-13046, -13144, -13242, -13340, -13438, +-13536, -13633, -13731, -13828, -13925, +-14022, -14119, -14216, -14312, -14409, +-14505, -14601, -14697, -14793, -14888, +-14984, -15079, -15174, -15269, -15364, +-15459, -15553, -15647, -15741, -15835, +-15929, -16023, -16116, -16210, -16303, +-16396, -16488, -16581, -16673, -16766, +-16858, -16949, -17041, -17133, -17224, +-17315, -17406, -17497, -17587, -17678, +-17768, -17858, -17948, -18037, -18127, +-18216, -18305, -18394, -18483, -18571, +-18659, -18747, -18835, -18923, -19010, +-19098, -19185, -19271, -19358, -19444, +-19531, -19617, -19702, -19788, -19873, +-19959, -20043, -20128, -20213, -20297, +-20381, -20465, -20549, -20632, -20715, +-20798, -20881, -20963, -21046, -21128, +-21210, -21291, -21373, -21454, -21535, +-21616, -21696, -21776, -21856, -21936, +-22016, -22095, -22174, -22253, -22331, +-22410, -22488, -22566, -22643, -22721, +-22798, -22875, -22951, -23028, -23104, +-23180, -23256, -23331, -23406, -23481, +-23556, -23630, -23704, -23778, -23852, +-23925, -23998, -24071, -24144, -24216, +-24288, -24360, -24432, -24503, -24574, +-24645, -24716, -24786, -24856, -24926, +-24995, -25064, -25133, -25202, -25270, +-25339, -25406, -25474, -25541, -25608, +-25675, -25742, -25808, -25874, -25939, +-26005, -26070, -26135, -26199, -26264, +-26327, -26391, -26455, -26518, -26581, +-26643, -26705, -26767, -26829, -26891, +-26952, -27013, -27073, -27133, -27193, +-27253, -27312, -27372, -27430, -27489, +-27547, -27605, -27663, -27720, -27777, +-27834, -27890, -27946, -28002, -28058, +-28113, -28168, -28223, -28277, -28331, +-28385, -28438, -28491, -28544, -28596, +-28649, -28701, -28752, -28803, -28854, +-28905, -28955, -29006, -29055, -29105, +-29154, -29203, -29251, -29299, -29347, +-29395, -29442, -29489, -29535, -29582, +-29628, -29673, -29719, -29764, -29808, +-29853, -29897, -29941, -29984, -30027, +-30070, -30112, -30154, -30196, -30238, +-30279, -30320, -30360, -30400, -30440, +-30480, -30519, -30558, -30596, -30635, +-30672, -30710, -30747, -30784, -30821, +-30857, -30893, -30929, -30964, -30999, +-31033, -31068, -31102, -31135, -31168, +-31201, -31234, -31266, -31298, -31330, +-31361, -31392, -31422, -31453, -31483, +-31512, -31541, -31570, -31599, -31627, +-31655, -31682, -31710, -31737, -31763, +-31789, -31815, -31841, -31866, -31891, +-31915, -31939, -31963, -31986, -32010, +-32032, -32055, -32077, -32099, -32120, +-32141, -32162, -32182, -32202, -32222, +-32241, -32260, -32279, -32297, -32315, +-32333, -32350, -32367, -32383, -32399, +-32415, -32431, -32446, -32461, -32475, +-32489, -32503, -32517, -32530, -32542, +-32555, -32567, -32579, -32590, -32601, +-32612, -32622, -32632, -32641, -32651, +-32659, -32668, -32676, -32684, -32692, +-32699, -32706, -32712, -32718, -32724, +-32729, -32734, -32739, -32743, -32747, +-32751, -32754, -32757, -32760, -32762, +-32764, -32765, -32767, -32767, -32767, +32767, 32767, 32765, 32761, 32756, +32750, 32742, 32732, 32722, 32710, +32696, 32681, 32665, 32647, 32628, +32608, 32586, 32562, 32538, 32512, +32484, 32455, 32425, 32393, 32360, +32326, 32290, 32253, 32214, 32174, +32133, 32090, 32046, 32001, 31954, +31906, 31856, 31805, 31753, 31700, +31645, 31588, 31530, 31471, 31411, +31349, 31286, 31222, 31156, 31089, +31020, 30951, 30880, 30807, 30733, +30658, 30582, 30504, 30425, 30345, +30263, 30181, 30096, 30011, 29924, +29836, 29747, 29656, 29564, 29471, +29377, 29281, 29184, 29086, 28987, +28886, 28784, 28681, 28577, 28471, +28365, 28257, 28147, 28037, 27925, +27812, 27698, 27583, 27467, 27349, +27231, 27111, 26990, 26868, 26744, +26620, 26494, 26367, 26239, 26110, +25980, 25849, 25717, 25583, 25449, +25313, 25176, 25038, 24900, 24760, +24619, 24477, 24333, 24189, 24044, +23898, 23751, 23602, 23453, 23303, +23152, 22999, 22846, 22692, 22537, +22380, 22223, 22065, 21906, 21746, +21585, 21423, 21261, 21097, 20933, +20767, 20601, 20434, 20265, 20096, +19927, 19756, 19584, 19412, 19239, +19065, 18890, 18714, 18538, 18361, +18183, 18004, 17824, 17644, 17463, +17281, 17098, 16915, 16731, 16546, +16361, 16175, 15988, 15800, 15612, +15423, 15234, 15043, 14852, 14661, +14469, 14276, 14083, 13889, 13694, +13499, 13303, 13107, 12910, 12713, +12515, 12317, 12118, 11918, 11718, +11517, 11316, 11115, 10913, 10710, +10508, 10304, 10100, 9896, 9691, +9486, 9281, 9075, 8869, 8662, +8455, 8248, 8040, 7832, 7623, +7415, 7206, 6996, 6787, 6577, +6366, 6156, 5945, 5734, 5523, +5311, 5100, 4888, 4675, 4463, +4251, 4038, 3825, 3612, 3399, +3185, 2972, 2758, 2544, 2330, +2116, 1902, 1688, 1474, 1260, +1045, 831, 617, 402, 188, +-27, -241, -456, -670, -885, +-1099, -1313, -1528, -1742, -1956, +-2170, -2384, -2598, -2811, -3025, +-3239, -3452, -3665, -3878, -4091, +-4304, -4516, -4728, -4941, -5153, +-5364, -5576, -5787, -5998, -6209, +-6419, -6629, -6839, -7049, -7258, +-7467, -7676, -7884, -8092, -8300, +-8507, -8714, -8920, -9127, -9332, +-9538, -9743, -9947, -10151, -10355, +-10558, -10761, -10963, -11165, -11367, +-11568, -11768, -11968, -12167, -12366, +-12565, -12762, -12960, -13156, -13352, +-13548, -13743, -13937, -14131, -14324, +-14517, -14709, -14900, -15091, -15281, +-15470, -15659, -15847, -16035, -16221, +-16407, -16593, -16777, -16961, -17144, +-17326, -17508, -17689, -17869, -18049, +-18227, -18405, -18582, -18758, -18934, +-19108, -19282, -19455, -19627, -19799, +-19969, -20139, -20308, -20475, -20642, +-20809, -20974, -21138, -21301, -21464, +-21626, -21786, -21946, -22105, -22263, +-22420, -22575, -22730, -22884, -23037, +-23189, -23340, -23490, -23640, -23788, +-23935, -24080, -24225, -24369, -24512, +-24654, -24795, -24934, -25073, -25211, +-25347, -25482, -25617, -25750, -25882, +-26013, -26143, -26272, -26399, -26526, +-26651, -26775, -26898, -27020, -27141, +-27260, -27379, -27496, -27612, -27727, +-27841, -27953, -28065, -28175, -28284, +-28391, -28498, -28603, -28707, -28810, +-28911, -29012, -29111, -29209, -29305, +-29401, -29495, -29587, -29679, -29769, +-29858, -29946, -30032, -30118, -30201, +-30284, -30365, -30445, -30524, -30601, +-30677, -30752, -30825, -30897, -30968, +-31038, -31106, -31172, -31238, -31302, +-31365, -31426, -31486, -31545, -31602, +-31658, -31713, -31766, -31818, -31869, +-31918, -31966, -32012, -32058, -32101, +-32144, -32185, -32224, -32262, -32299, +-32335, -32369, -32401, -32433, -32463, +-32491, -32518, -32544, -32568, -32591, +-32613, -32633, -32652, -32669, -32685, +-32700, -32713, -32724, -32735, -32744, +-32751, -32757, -32762, -32766, -32767, +32767, 32764, 32755, 32741, 32720, +32694, 32663, 32626, 32583, 32535, +32481, 32421, 32356, 32286, 32209, +32128, 32041, 31948, 31850, 31747, +31638, 31523, 31403, 31278, 31148, +31012, 30871, 30724, 30572, 30415, +30253, 30086, 29913, 29736, 29553, +29365, 29172, 28974, 28771, 28564, +28351, 28134, 27911, 27684, 27452, +27216, 26975, 26729, 26478, 26223, +25964, 25700, 25432, 25159, 24882, +24601, 24315, 24026, 23732, 23434, +23133, 22827, 22517, 22204, 21886, +21565, 21240, 20912, 20580, 20244, +19905, 19563, 19217, 18868, 18516, +18160, 17802, 17440, 17075, 16708, +16338, 15964, 15588, 15210, 14829, +14445, 14059, 13670, 13279, 12886, +12490, 12093, 11693, 11291, 10888, +10482, 10075, 9666, 9255, 8843, +8429, 8014, 7597, 7180, 6760, +6340, 5919, 5496, 5073, 4649, +4224, 3798, 3372, 2945, 2517, +2090, 1661, 1233, 804, 375, +-54, -483, -911, -1340, -1768, +-2197, -2624, -3052, -3479, -3905, +-4330, -4755, -5179, -5602, -6024, +-6445, -6865, -7284, -7702, -8118, +-8533, -8946, -9358, -9768, -10177, +-10584, -10989, -11392, -11793, -12192, +-12589, -12984, -13377, -13767, -14155, +-14541, -14924, -15305, -15683, -16058, +-16430, -16800, -17167, -17531, -17892, +-18249, -18604, -18956, -19304, -19649, +-19990, -20329, -20663, -20994, -21322, +-21646, -21966, -22282, -22595, -22904, +-23208, -23509, -23806, -24099, -24387, +-24672, -24952, -25228, -25499, -25766, +-26029, -26288, -26541, -26791, -27035, +-27275, -27511, -27741, -27967, -28188, +-28405, -28616, -28823, -29024, -29221, +-29412, -29599, -29780, -29957, -30128, +-30294, -30455, -30611, -30761, -30906, +-31046, -31181, -31310, -31434, -31552, +-31665, -31773, -31875, -31972, -32063, +-32149, -32229, -32304, -32373, -32437, +-32495, -32547, -32594, -32635, -32671, +-32701, -32726, -32745, -32758, -32766, +32767, 32754, 32717, 32658, 32577, +32473, 32348, 32200, 32029, 31837, +31624, 31388, 31131, 30853, 30553, +30232, 29891, 29530, 29148, 28746, +28324, 27883, 27423, 26944, 26447, +25931, 25398, 24847, 24279, 23695, +23095, 22478, 21846, 21199, 20538, +19863, 19174, 18472, 17757, 17030, +16291, 15541, 14781, 14010, 13230, +12441, 11643, 10837, 10024, 9204, +8377, 7545, 6708, 5866, 5020, +4171, 3319, 2464, 1608, 751, +-107, -965, -1822, -2678, -3532, +-4383, -5232, -6077, -6918, -7754, +-8585, -9409, -10228, -11039, -11843, +-12639, -13426, -14204, -14972, -15730, +-16477, -17213, -17937, -18648, -19347, +-20033, -20705, -21363, -22006, -22634, +-23246, -23843, -24423, -24986, -25533, +-26062, -26573, -27066, -27540, -27995, +-28431, -28848, -29245, -29622, -29979, +-30315, -30630, -30924, -31197, -31449, +-31679, -31887, -32074, -32239, -32381, +-32501, -32600, -32675, -32729, -32759, +}; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{27853, 0, 4096, 8192, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/native/codec/libraries/opus/celt/static_modes_fixed_arm_ne10.h b/native/codec/libraries/opus/celt/static_modes_fixed_arm_ne10.h new file mode 100644 index 0000000..7623092 --- /dev/null +++ b/native/codec/libraries/opus/celt/static_modes_fixed_arm_ne10.h @@ -0,0 +1,388 @@ +/* The contents of this file was automatically generated by + * dump_mode_arm_ne10.c with arguments: 48000 960 + * It contains static definitions for some pre-defined modes. */ +#include + +#ifndef NE10_FFT_PARAMS48000_960 +#define NE10_FFT_PARAMS48000_960 +static const ne10_int32_t ne10_factors_480[64] = { +4, 40, 4, 30, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_240[64] = { +3, 20, 4, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_120[64] = { +3, 10, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_60[64] = { +2, 5, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_fft_cpx_int32_t ne10_twiddles_480[480] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955}, +{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330}, +{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738}, +{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141}, +{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240}, +{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960}, +{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282}, +{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339}, +{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564}, +{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839}, +{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918}, +{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188}, +{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252}, +{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059}, +{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542}, +{2147483647,0}, {2147299667,-28109693}, {2146747758,-56214570}, +{2145828015,-84309815}, {2144540595,-112390613}, {2142885719,-140452154}, +{2140863671,-168489630}, {2138474797,-196498235}, {2135719506,-224473172}, +{2132598271,-252409646}, {2129111626,-280302871}, {2125260168,-308148068}, +{2121044558,-335940465}, {2116465518,-363675300}, {2111523833,-391347822}, +{2106220349,-418953288}, {2100555974,-446486968}, {2094531681,-473944146}, +{2088148500,-501320115}, {2081407525,-528610186}, {2074309912,-555809682}, +{2066856885,-582913912}, {2059049696,-609918325}, {2050889698,-636818231}, +{2042378310,-663608960}, {2033516972,-690285983}, {2024307180,-716844791}, +{2014750533,-743280770}, {2004848691,-769589332}, {1994603329,-795766029}, +{1984016179,-821806435}, {1973089077,-847706028}, {1961823921,-873460313}, +{1950222618,-899064934}, {1938287127,-924515564}, {1926019520,-949807783}, +{1913421927,-974937199}, {1900496481,-999899565}, {1887245364,-1024690661}, +{1873670877,-1049306180}, {1859775377,-1073741851}, {1845561215,-1097993541}, +{1831030826,-1122057097}, {1816186632,-1145928502}, {1801031311,-1169603450}, +{1785567394,-1193077993}, {1769797456,-1216348214}, {1753724345,-1239409914}, +{1737350743,-1262259248}, {1720679456,-1284892300}, {1703713340,-1307305194}, +{1686455222,-1329494189}, {1668908218,-1351455280}, {1651075255,-1373184807}, +{1632959307,-1394679144}, {1614563642,-1415934412}, {1595891331,-1436947067}, +{1576945572,-1457713510}, {1557729613,-1478230181}, {1538246655,-1498493658}, +{1518500216,-1518500282}, {1498493590,-1538246721}, {1478230113,-1557729677}, +{1457713441,-1576945636}, {1436946998,-1595891394}, {1415934341,-1614563704}, +{1394679073,-1632959368}, {1373184735,-1651075315}, {1351455207,-1668908277}, +{1329494115,-1686455280}, {1307305120,-1703713397}, {1284892225,-1720679512}, +{1262259172,-1737350799}, {1239409837,-1753724400}, {1216348136,-1769797510}, +{1193077915,-1785567446}, {1169603371,-1801031362}, {1145928423,-1816186682}, +{1122057017,-1831030875}, {1097993571,-1845561197}, {1073741769,-1859775424}, +{1049305987,-1873670985}, {1024690635,-1887245378}, {999899482,-1900496524}, +{974937230,-1913421912}, {949807699,-1926019561}, {924515422,-1938287195}, +{899064965,-1950222603}, {873460227,-1961823959}, {847705824,-1973089164}, +{821806407,-1984016190}, {795765941,-1994603364}, {769589125,-2004848771}, +{743280682,-2014750566}, {716844642,-2024307233}, {690286016,-2033516961}, +{663608871,-2042378339}, {636818019,-2050889764}, {609918296,-2059049705}, +{582913822,-2066856911}, {555809715,-2074309903}, {528610126,-2081407540}, +{501319962,-2088148536}, {473944148,-2094531680}, {446486876,-2100555994}, +{418953102,-2106220386}, {391347792,-2111523838}, {363675176,-2116465540}, +{335940246,-2121044593}, {308148006,-2125260177}, {280302715,-2129111646}, +{252409648,-2132598271}, {224473078,-2135719516}, {196498046,-2138474814}, +{168489600,-2140863674}, {140452029,-2142885728}, {112390647,-2144540593}, +{84309753,-2145828017}, {56214412,-2146747762}, {28109695,-2147299667}, +{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613}, +{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871}, +{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968}, +{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325}, +{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332}, +{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564}, +{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851}, +{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214}, +{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280}, +{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181}, +{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394}, +{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397}, +{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362}, +{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378}, +{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959}, +{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233}, +{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903}, +{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838}, +{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516}, +{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762}, +{-94,-2147483647}, {-56214600,-2146747757}, {-112390835,-2144540584}, +{-168489787,-2140863659}, {-224473265,-2135719496}, {-280302901,-2129111622}, +{-335940431,-2121044564}, {-391347977,-2111523804}, {-446487060,-2100555955}, +{-501320144,-2088148493}, {-555809896,-2074309855}, {-609918476,-2059049651}, +{-663609049,-2042378281}, {-716844819,-2024307170}, {-769589300,-2004848703}, +{-821806581,-1984016118}, {-873460398,-1961823883}, {-924515591,-1938287114}, +{-974937397,-1913421827}, {-1024690575,-1887245411}, {-1073741932,-1859775330}, +{-1122057395,-1831030643}, {-1169603421,-1801031330}, {-1216348291,-1769797403}, +{-1262259116,-1737350839}, {-1307305268,-1703713283}, {-1351455453,-1668908078}, +{-1394679021,-1632959413}, {-1436947137,-1595891268}, {-1478230435,-1557729372}, +{-1518500258,-1518500240}, {-1557729742,-1478230045}, {-1595891628,-1436946738}, +{-1632959429,-1394679001}, {-1668908417,-1351455035}, {-1703713298,-1307305248}, +{-1737350854,-1262259096}, {-1769797708,-1216347848}, {-1801031344,-1169603400}, +{-1831030924,-1122056937}, {-1859775343,-1073741910}, {-1887245423,-1024690552}, +{-1913422071,-974936918}, {-1938287125,-924515568}, {-1961823997,-873460141}, +{-1984016324,-821806084}, {-2004848713,-769589276}, {-2024307264,-716844553}, +{-2042378447,-663608538}, {-2059049731,-609918206}, {-2074309994,-555809377}, +{-2088148499,-501320119}, {-2100556013,-446486785}, {-2111523902,-391347448}, +{-2121044568,-335940406}, {-2129111659,-280302621}, {-2135719499,-224473240}, +{-2140863681,-168489506}, {-2144540612,-112390298}, {-2146747758,-56214574}, +{2147483647,0}, {2145828015,-84309815}, {2140863671,-168489630}, +{2132598271,-252409646}, {2121044558,-335940465}, {2106220349,-418953288}, +{2088148500,-501320115}, {2066856885,-582913912}, {2042378310,-663608960}, +{2014750533,-743280770}, {1984016179,-821806435}, {1950222618,-899064934}, +{1913421927,-974937199}, {1873670877,-1049306180}, {1831030826,-1122057097}, +{1785567394,-1193077993}, {1737350743,-1262259248}, {1686455222,-1329494189}, +{1632959307,-1394679144}, {1576945572,-1457713510}, {1518500216,-1518500282}, +{1457713441,-1576945636}, {1394679073,-1632959368}, {1329494115,-1686455280}, +{1262259172,-1737350799}, {1193077915,-1785567446}, {1122057017,-1831030875}, +{1049305987,-1873670985}, {974937230,-1913421912}, {899064965,-1950222603}, +{821806407,-1984016190}, {743280682,-2014750566}, {663608871,-2042378339}, +{582913822,-2066856911}, {501319962,-2088148536}, {418953102,-2106220386}, +{335940246,-2121044593}, {252409648,-2132598271}, {168489600,-2140863674}, +{84309753,-2145828017}, {-94,-2147483647}, {-84309940,-2145828010}, +{-168489787,-2140863659}, {-252409834,-2132598249}, {-335940431,-2121044564}, +{-418953286,-2106220349}, {-501320144,-2088148493}, {-582914003,-2066856860}, +{-663609049,-2042378281}, {-743280858,-2014750501}, {-821806581,-1984016118}, +{-899065136,-1950222525}, {-974937397,-1913421827}, {-1049306374,-1873670768}, +{-1122057395,-1831030643}, {-1193078284,-1785567199}, {-1262259116,-1737350839}, +{-1329494061,-1686455323}, {-1394679021,-1632959413}, {-1457713485,-1576945595}, +{-1518500258,-1518500240}, {-1576945613,-1457713466}, {-1632959429,-1394679001}, +{-1686455338,-1329494041}, {-1737350854,-1262259096}, {-1785567498,-1193077837}, +{-1831030924,-1122056937}, {-1873671031,-1049305905}, {-1913422071,-974936918}, +{-1950222750,-899064648}, {-1984016324,-821806084}, {-2014750687,-743280354}, +{-2042378447,-663608538}, {-2066856867,-582913978}, {-2088148499,-501320119}, +{-2106220354,-418953261}, {-2121044568,-335940406}, {-2132598282,-252409555}, +{-2140863681,-168489506}, {-2145828021,-84309659}, {-2147483647,188}, +{-2145828006,84310034}, {-2140863651,168489881}, {-2132598237,252409928}, +{-2121044509,335940777}, {-2106220281,418953629}, {-2088148411,501320484}, +{-2066856765,582914339}, {-2042378331,663608895}, {-2014750557,743280706}, +{-1984016181,821806431}, {-1950222593,899064989}, {-1913421900,974937252}, +{-1873670848,1049306232}, {-1831030728,1122057257}, {-1785567289,1193078149}, +{-1737350633,1262259400}, {-1686455106,1329494336}, {-1632959185,1394679287}, +{-1576945358,1457713742}, {-1518499993,1518500506}, {-1457713209,1576945850}, +{-1394678735,1632959656}, {-1329493766,1686455555}, {-1262258813,1737351059}, +{-1193077546,1785567692}, {-1122056638,1831031107}, {-1049305599,1873671202}, +{-974936606,1913422229}, {-899064330,1950222896}, {-821805761,1984016458}, +{-743280025,2014750808}, {-663609179,2042378239}, {-582914134,2066856823}, +{-501320277,2088148461}, {-418953420,2106220322}, {-335940566,2121044542}, +{-252409716,2132598263}, {-168489668,2140863668}, {-84309821,2145828015}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_240[240] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248}, +{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647}, +{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096}, +{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895}, +{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239}, +{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613}, +{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871}, +{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968}, +{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325}, +{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332}, +{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564}, +{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851}, +{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214}, +{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280}, +{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181}, +{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394}, +{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397}, +{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362}, +{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378}, +{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959}, +{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233}, +{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903}, +{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838}, +{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516}, +{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{-94,-2147483647}, {-112390835,-2144540584}, {-224473265,-2135719496}, +{-335940431,-2121044564}, {-446487060,-2100555955}, {-555809896,-2074309855}, +{-663609049,-2042378281}, {-769589300,-2004848703}, {-873460398,-1961823883}, +{-974937397,-1913421827}, {-1073741932,-1859775330}, {-1169603421,-1801031330}, +{-1262259116,-1737350839}, {-1351455453,-1668908078}, {-1436947137,-1595891268}, +{-1518500258,-1518500240}, {-1595891628,-1436946738}, {-1668908417,-1351455035}, +{-1737350854,-1262259096}, {-1801031344,-1169603400}, {-1859775343,-1073741910}, +{-1913422071,-974936918}, {-1961823997,-873460141}, {-2004848713,-769589276}, +{-2042378447,-663608538}, {-2074309994,-555809377}, {-2100556013,-446486785}, +{-2121044568,-335940406}, {-2135719499,-224473240}, {-2144540612,-112390298}, +{2147483647,0}, {2140863671,-168489630}, {2121044558,-335940465}, +{2088148500,-501320115}, {2042378310,-663608960}, {1984016179,-821806435}, +{1913421927,-974937199}, {1831030826,-1122057097}, {1737350743,-1262259248}, +{1632959307,-1394679144}, {1518500216,-1518500282}, {1394679073,-1632959368}, +{1262259172,-1737350799}, {1122057017,-1831030875}, {974937230,-1913421912}, +{821806407,-1984016190}, {663608871,-2042378339}, {501319962,-2088148536}, +{335940246,-2121044593}, {168489600,-2140863674}, {-94,-2147483647}, +{-168489787,-2140863659}, {-335940431,-2121044564}, {-501320144,-2088148493}, +{-663609049,-2042378281}, {-821806581,-1984016118}, {-974937397,-1913421827}, +{-1122057395,-1831030643}, {-1262259116,-1737350839}, {-1394679021,-1632959413}, +{-1518500258,-1518500240}, {-1632959429,-1394679001}, {-1737350854,-1262259096}, +{-1831030924,-1122056937}, {-1913422071,-974936918}, {-1984016324,-821806084}, +{-2042378447,-663608538}, {-2088148499,-501320119}, {-2121044568,-335940406}, +{-2140863681,-168489506}, {-2147483647,188}, {-2140863651,168489881}, +{-2121044509,335940777}, {-2088148411,501320484}, {-2042378331,663608895}, +{-1984016181,821806431}, {-1913421900,974937252}, {-1831030728,1122057257}, +{-1737350633,1262259400}, {-1632959185,1394679287}, {-1518499993,1518500506}, +{-1394678735,1632959656}, {-1262258813,1737351059}, {-1122056638,1831031107}, +{-974936606,1913422229}, {-821805761,1984016458}, {-663609179,2042378239}, +{-501320277,2088148461}, {-335940566,2121044542}, {-168489668,2140863668}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_120[120] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955}, +{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330}, +{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738}, +{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141}, +{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240}, +{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960}, +{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282}, +{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339}, +{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564}, +{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839}, +{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918}, +{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188}, +{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252}, +{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059}, +{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_60[60] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248}, +{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647}, +{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096}, +{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895}, +{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239}, +}; +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_480 = { +120, +(ne10_int32_t *)ne10_factors_480, +(ne10_fft_cpx_int32_t *)ne10_twiddles_480, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_480[120], +}; +static const arch_fft_state cfg_arch_480 = { +1, +(void *)&ne10_fft_state_int32_t_480, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_240 = { +60, +(ne10_int32_t *)ne10_factors_240, +(ne10_fft_cpx_int32_t *)ne10_twiddles_240, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_240[60], +}; +static const arch_fft_state cfg_arch_240 = { +1, +(void *)&ne10_fft_state_int32_t_240, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_120 = { +30, +(ne10_int32_t *)ne10_factors_120, +(ne10_fft_cpx_int32_t *)ne10_twiddles_120, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_120[30], +}; +static const arch_fft_state cfg_arch_120 = { +1, +(void *)&ne10_fft_state_int32_t_120, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_60 = { +15, +(ne10_int32_t *)ne10_factors_60, +(ne10_fft_cpx_int32_t *)ne10_twiddles_60, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_60[15], +}; +static const arch_fft_state cfg_arch_60 = { +1, +(void *)&ne10_fft_state_int32_t_60, +}; + +#endif /* end NE10_FFT_PARAMS48000_960 */ diff --git a/native/codec/libraries/opus/celt/static_modes_float.h b/native/codec/libraries/opus/celt/static_modes_float.h new file mode 100644 index 0000000..e102a38 --- /dev/null +++ b/native/codec/libraries/opus/celt/static_modes_float.h @@ -0,0 +1,888 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifdef HAVE_ARM_NE10 +#define OVERRIDE_FFT 1 +#include "static_modes_float_arm_ne10.h" +#endif + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f, +0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f, +0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f, +0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f, +0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f, +0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f, +0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f, +0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f, +0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f, +0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f, +0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f, +0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f, +0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f, +0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f, +0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f, +0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f, +0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f, +0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f, +0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f, +0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f, +0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f, +0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f, +0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f, +0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f}, +{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f}, +{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f}, +{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f}, +{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f}, +{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f}, +{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f}, +{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f}, +{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f}, +{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f}, +{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f}, +{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f}, +{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f}, +{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f}, +{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f}, +{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f}, +{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f}, +{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f}, +{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f}, +{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f}, +{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f}, +{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f}, +{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f}, +{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f}, +{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f}, +{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f}, +{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f}, +{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f}, +{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f}, +{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f}, +{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f}, +{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f}, +{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f}, +{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f}, +{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f}, +{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f}, +{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f}, +{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f}, +{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f}, +{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f}, +{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f}, +{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f}, +{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f}, +{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f}, +{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f}, +{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f}, +{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f}, +{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f}, +{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f}, +{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f}, +{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f}, +{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f}, +{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f}, +{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f}, +{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f}, +{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f}, +{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f}, +{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f}, +{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f}, +{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f}, +{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f}, +{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f}, +{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f}, +{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f}, +{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f}, +{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f}, +{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f}, +{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f}, +{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f}, +{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f}, +{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f}, +{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f}, +{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f}, +{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f}, +{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f}, +{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f}, +{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f}, +{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f}, +{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f}, +{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f}, +{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f}, +{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f}, +{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f}, +{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f}, +{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f}, +{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f}, +{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f}, +{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f}, +{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f}, +{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f}, +{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f}, +{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f}, +{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f}, +{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f}, +{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f}, +{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f}, +{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f}, +{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f}, +{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f}, +{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f}, +{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f}, +{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f}, +{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f}, +{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f}, +{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f}, +{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f}, +{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f}, +{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f}, +{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f}, +{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f}, +{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f}, +{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f}, +{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f}, +{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f}, +{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f}, +{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f}, +{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f}, +{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f}, +{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f}, +{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f}, +{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f}, +{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f}, +{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f}, +{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f}, +{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f}, +{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f}, +{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f}, +{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f}, +{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f}, +{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f}, +{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f}, +{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f}, +{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f}, +{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f}, +{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f}, +{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f}, +{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f}, +{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f}, +{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f}, +{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f}, +{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f}, +{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f}, +{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f}, +{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f}, +{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f}, +{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f}, +{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f}, +{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f}, +{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f}, +{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f}, +{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f}, +{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f}, +{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f}, +{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f}, +{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f}, +{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f}, +{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f}, +{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f}, +{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f}, +{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f}, +{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f}, +{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f}, +{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f}, +{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f}, +{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f}, +{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f}, +{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f}, +{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f}, +{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f}, +{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f}, +{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f}, +{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f}, +{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f}, +{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f}, +{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f}, +{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f}, +{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f}, +{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f}, +{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f}, +{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f}, +{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f}, +{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f}, +{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f}, +{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f}, +{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f}, +{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f}, +{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f}, +{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f}, +{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f}, +{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f}, +{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f}, +{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f}, +{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f}, +{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f}, +{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f}, +{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f}, +{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f}, +{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f}, +{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f}, +{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f}, +{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f}, +{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f}, +{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f}, +{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f}, +{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f}, +{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f}, +{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f}, +{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f}, +{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f}, +{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f}, +{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f}, +{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f}, +{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f}, +{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f}, +{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f}, +{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f}, +{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f}, +{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f}, +{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f}, +{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f}, +{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f}, +{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f}, +{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f}, +{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f}, +{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f}, +{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f}, +{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f}, +{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f}, +{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f}, +{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f}, +{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f}, +{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f}, +{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f}, +{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f}, +{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f}, +{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f}, +{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f}, +{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f}, +{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f}, +{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, +8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, +16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464, +24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, +4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, +12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, +20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, +28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, +1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, +9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, +17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465, +25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, +5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, +13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, +21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, +29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, +2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, +10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, +18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466, +26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, +6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, +14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, +22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, +30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, +3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, +11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, +19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467, +27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, +7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, +15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, +23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, +31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, +4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, +8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232, +12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, +1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, +5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, +9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, +13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, +2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, +6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, +10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234, +14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, +3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, +7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, +11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, +15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, +4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, +1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113, +5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, +2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, +6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, +3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, +7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, +1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, +2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, +3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +0.002083333f, /* scale */ +-1, /* shift */ +{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_480, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +0.004166667f, /* scale */ +1, /* shift */ +{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_240, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +0.008333333f, /* scale */ +2, /* shift */ +{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_120, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +0.016666667f, /* scale */ +3, /* shift */ +{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_60, +#else +NULL, +#endif +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[1800] = { +0.99999994f, 0.99999321f, 0.99997580f, 0.99994773f, 0.99990886f, +0.99985933f, 0.99979913f, 0.99972820f, 0.99964654f, 0.99955416f, +0.99945110f, 0.99933738f, 0.99921292f, 0.99907774f, 0.99893188f, +0.99877530f, 0.99860805f, 0.99843007f, 0.99824142f, 0.99804211f, +0.99783206f, 0.99761140f, 0.99737996f, 0.99713790f, 0.99688518f, +0.99662173f, 0.99634761f, 0.99606287f, 0.99576741f, 0.99546129f, +0.99514455f, 0.99481714f, 0.99447906f, 0.99413031f, 0.99377096f, +0.99340093f, 0.99302030f, 0.99262899f, 0.99222708f, 0.99181455f, +0.99139136f, 0.99095762f, 0.99051321f, 0.99005818f, 0.98959261f, +0.98911643f, 0.98862964f, 0.98813224f, 0.98762429f, 0.98710573f, +0.98657662f, 0.98603696f, 0.98548669f, 0.98492593f, 0.98435456f, +0.98377270f, 0.98318028f, 0.98257732f, 0.98196387f, 0.98133987f, +0.98070538f, 0.98006040f, 0.97940493f, 0.97873890f, 0.97806245f, +0.97737551f, 0.97667813f, 0.97597027f, 0.97525197f, 0.97452319f, +0.97378403f, 0.97303438f, 0.97227436f, 0.97150391f, 0.97072303f, +0.96993178f, 0.96913016f, 0.96831810f, 0.96749574f, 0.96666300f, +0.96581990f, 0.96496642f, 0.96410263f, 0.96322852f, 0.96234411f, +0.96144938f, 0.96054435f, 0.95962906f, 0.95870346f, 0.95776761f, +0.95682150f, 0.95586514f, 0.95489854f, 0.95392174f, 0.95293468f, +0.95193744f, 0.95093000f, 0.94991243f, 0.94888461f, 0.94784665f, +0.94679856f, 0.94574034f, 0.94467193f, 0.94359344f, 0.94250488f, +0.94140619f, 0.94029742f, 0.93917859f, 0.93804967f, 0.93691075f, +0.93576175f, 0.93460274f, 0.93343377f, 0.93225473f, 0.93106574f, +0.92986679f, 0.92865789f, 0.92743903f, 0.92621022f, 0.92497152f, +0.92372292f, 0.92246443f, 0.92119598f, 0.91991776f, 0.91862965f, +0.91733170f, 0.91602397f, 0.91470635f, 0.91337901f, 0.91204184f, +0.91069490f, 0.90933824f, 0.90797186f, 0.90659571f, 0.90520984f, +0.90381432f, 0.90240908f, 0.90099424f, 0.89956969f, 0.89813554f, +0.89669174f, 0.89523834f, 0.89377540f, 0.89230281f, 0.89082074f, +0.88932908f, 0.88782793f, 0.88631725f, 0.88479710f, 0.88326746f, +0.88172835f, 0.88017982f, 0.87862182f, 0.87705445f, 0.87547767f, +0.87389153f, 0.87229604f, 0.87069118f, 0.86907703f, 0.86745358f, +0.86582077f, 0.86417878f, 0.86252749f, 0.86086690f, 0.85919720f, +0.85751826f, 0.85583007f, 0.85413277f, 0.85242635f, 0.85071075f, +0.84898609f, 0.84725231f, 0.84550947f, 0.84375757f, 0.84199661f, +0.84022665f, 0.83844769f, 0.83665979f, 0.83486289f, 0.83305705f, +0.83124226f, 0.82941860f, 0.82758605f, 0.82574469f, 0.82389444f, +0.82203537f, 0.82016748f, 0.81829083f, 0.81640542f, 0.81451124f, +0.81260836f, 0.81069672f, 0.80877650f, 0.80684757f, 0.80490994f, +0.80296379f, 0.80100900f, 0.79904562f, 0.79707366f, 0.79509324f, +0.79310423f, 0.79110676f, 0.78910083f, 0.78708643f, 0.78506362f, +0.78303236f, 0.78099275f, 0.77894479f, 0.77688843f, 0.77482378f, +0.77275085f, 0.77066964f, 0.76858020f, 0.76648247f, 0.76437658f, +0.76226246f, 0.76014024f, 0.75800985f, 0.75587130f, 0.75372469f, +0.75157005f, 0.74940729f, 0.74723655f, 0.74505776f, 0.74287105f, +0.74067634f, 0.73847371f, 0.73626316f, 0.73404479f, 0.73181850f, +0.72958434f, 0.72734243f, 0.72509271f, 0.72283524f, 0.72057003f, +0.71829706f, 0.71601641f, 0.71372813f, 0.71143216f, 0.70912862f, +0.70681745f, 0.70449871f, 0.70217246f, 0.69983864f, 0.69749737f, +0.69514859f, 0.69279242f, 0.69042879f, 0.68805778f, 0.68567938f, +0.68329364f, 0.68090063f, 0.67850029f, 0.67609268f, 0.67367786f, +0.67125577f, 0.66882652f, 0.66639012f, 0.66394657f, 0.66149592f, +0.65903819f, 0.65657341f, 0.65410155f, 0.65162271f, 0.64913690f, +0.64664418f, 0.64414448f, 0.64163786f, 0.63912445f, 0.63660413f, +0.63407701f, 0.63154310f, 0.62900239f, 0.62645501f, 0.62390089f, +0.62134010f, 0.61877263f, 0.61619854f, 0.61361790f, 0.61103064f, +0.60843682f, 0.60583651f, 0.60322970f, 0.60061646f, 0.59799677f, +0.59537065f, 0.59273821f, 0.59009939f, 0.58745426f, 0.58480281f, +0.58214509f, 0.57948118f, 0.57681108f, 0.57413477f, 0.57145232f, +0.56876373f, 0.56606907f, 0.56336832f, 0.56066155f, 0.55794877f, +0.55523002f, 0.55250537f, 0.54977477f, 0.54703826f, 0.54429591f, +0.54154772f, 0.53879374f, 0.53603399f, 0.53326851f, 0.53049731f, +0.52772039f, 0.52493787f, 0.52214974f, 0.51935595f, 0.51655668f, +0.51375180f, 0.51094145f, 0.50812566f, 0.50530440f, 0.50247771f, +0.49964568f, 0.49680826f, 0.49396557f, 0.49111754f, 0.48826426f, +0.48540577f, 0.48254207f, 0.47967321f, 0.47679919f, 0.47392011f, +0.47103590f, 0.46814668f, 0.46525243f, 0.46235323f, 0.45944905f, +0.45653993f, 0.45362595f, 0.45070711f, 0.44778344f, 0.44485497f, +0.44192174f, 0.43898380f, 0.43604112f, 0.43309379f, 0.43014181f, +0.42718524f, 0.42422408f, 0.42125839f, 0.41828820f, 0.41531351f, +0.41233435f, 0.40935081f, 0.40636289f, 0.40337059f, 0.40037400f, +0.39737311f, 0.39436796f, 0.39135858f, 0.38834500f, 0.38532731f, +0.38230544f, 0.37927949f, 0.37624949f, 0.37321547f, 0.37017745f, +0.36713544f, 0.36408952f, 0.36103970f, 0.35798600f, 0.35492846f, +0.35186714f, 0.34880206f, 0.34573323f, 0.34266070f, 0.33958447f, +0.33650464f, 0.33342120f, 0.33033419f, 0.32724363f, 0.32414958f, +0.32105204f, 0.31795108f, 0.31484672f, 0.31173897f, 0.30862790f, +0.30551350f, 0.30239585f, 0.29927495f, 0.29615086f, 0.29302359f, +0.28989318f, 0.28675964f, 0.28362307f, 0.28048345f, 0.27734083f, +0.27419522f, 0.27104670f, 0.26789525f, 0.26474094f, 0.26158381f, +0.25842386f, 0.25526115f, 0.25209570f, 0.24892756f, 0.24575676f, +0.24258332f, 0.23940729f, 0.23622867f, 0.23304754f, 0.22986393f, +0.22667783f, 0.22348931f, 0.22029841f, 0.21710514f, 0.21390954f, +0.21071166f, 0.20751151f, 0.20430915f, 0.20110460f, 0.19789790f, +0.19468907f, 0.19147816f, 0.18826519f, 0.18505022f, 0.18183327f, +0.17861435f, 0.17539354f, 0.17217083f, 0.16894630f, 0.16571994f, +0.16249183f, 0.15926196f, 0.15603039f, 0.15279715f, 0.14956227f, +0.14632578f, 0.14308774f, 0.13984816f, 0.13660708f, 0.13336454f, +0.13012058f, 0.12687522f, 0.12362850f, 0.12038045f, 0.11713112f, +0.11388054f, 0.11062872f, 0.10737573f, 0.10412160f, 0.10086634f, +0.097609997f, 0.094352618f, 0.091094226f, 0.087834857f, 0.084574550f, +0.081313334f, 0.078051247f, 0.074788325f, 0.071524605f, 0.068260118f, +0.064994894f, 0.061728980f, 0.058462404f, 0.055195201f, 0.051927410f, +0.048659060f, 0.045390189f, 0.042120833f, 0.038851023f, 0.035580799f, +0.032310195f, 0.029039243f, 0.025767982f, 0.022496443f, 0.019224664f, +0.015952680f, 0.012680525f, 0.0094082337f, 0.0061358409f, 0.0028633832f, +-0.00040910527f, -0.0036815894f, -0.0069540343f, -0.010226404f, -0.013498665f, +-0.016770782f, -0.020042717f, -0.023314439f, -0.026585912f, -0.029857099f, +-0.033127967f, -0.036398482f, -0.039668605f, -0.042938303f, -0.046207540f, +-0.049476285f, -0.052744497f, -0.056012146f, -0.059279196f, -0.062545612f, +-0.065811358f, -0.069076397f, -0.072340697f, -0.075604223f, -0.078866936f, +-0.082128808f, -0.085389800f, -0.088649876f, -0.091909006f, -0.095167145f, +-0.098424271f, -0.10168034f, -0.10493532f, -0.10818918f, -0.11144188f, +-0.11469338f, -0.11794366f, -0.12119267f, -0.12444039f, -0.12768677f, +-0.13093179f, -0.13417540f, -0.13741758f, -0.14065829f, -0.14389749f, +-0.14713514f, -0.15037122f, -0.15360570f, -0.15683852f, -0.16006967f, +-0.16329910f, -0.16652679f, -0.16975269f, -0.17297678f, -0.17619900f, +-0.17941935f, -0.18263777f, -0.18585424f, -0.18906870f, -0.19228116f, +-0.19549155f, -0.19869985f, -0.20190603f, -0.20511003f, -0.20831184f, +-0.21151142f, -0.21470875f, -0.21790376f, -0.22109644f, -0.22428675f, +-0.22747467f, -0.23066014f, -0.23384315f, -0.23702365f, -0.24020162f, +-0.24337701f, -0.24654980f, -0.24971995f, -0.25288740f, -0.25605217f, +-0.25921419f, -0.26237345f, -0.26552987f, -0.26868346f, -0.27183419f, +-0.27498198f, -0.27812684f, -0.28126872f, -0.28440759f, -0.28754342f, +-0.29067615f, -0.29380578f, -0.29693225f, -0.30005556f, -0.30317566f, +-0.30629250f, -0.30940607f, -0.31251630f, -0.31562322f, -0.31872672f, +-0.32182685f, -0.32492352f, -0.32801670f, -0.33110636f, -0.33419248f, +-0.33727503f, -0.34035397f, -0.34342924f, -0.34650084f, -0.34956875f, +-0.35263291f, -0.35569328f, -0.35874987f, -0.36180258f, -0.36485144f, +-0.36789638f, -0.37093741f, -0.37397444f, -0.37700745f, -0.38003644f, +-0.38306138f, -0.38608220f, -0.38909888f, -0.39211139f, -0.39511973f, +-0.39812380f, -0.40112361f, -0.40411916f, -0.40711036f, -0.41009718f, +-0.41307965f, -0.41605768f, -0.41903123f, -0.42200032f, -0.42496487f, +-0.42792490f, -0.43088034f, -0.43383113f, -0.43677729f, -0.43971881f, +-0.44265559f, -0.44558764f, -0.44851488f, -0.45143735f, -0.45435500f, +-0.45726776f, -0.46017563f, -0.46307856f, -0.46597654f, -0.46886954f, +-0.47175750f, -0.47464043f, -0.47751826f, -0.48039100f, -0.48325855f, +-0.48612097f, -0.48897815f, -0.49183011f, -0.49467680f, -0.49751821f, +-0.50035429f, -0.50318497f, -0.50601029f, -0.50883019f, -0.51164466f, +-0.51445359f, -0.51725709f, -0.52005500f, -0.52284735f, -0.52563411f, +-0.52841520f, -0.53119069f, -0.53396046f, -0.53672451f, -0.53948283f, +-0.54223537f, -0.54498214f, -0.54772300f, -0.55045801f, -0.55318713f, +-0.55591035f, -0.55862761f, -0.56133890f, -0.56404412f, -0.56674337f, +-0.56943649f, -0.57212353f, -0.57480448f, -0.57747924f, -0.58014780f, +-0.58281022f, -0.58546633f, -0.58811617f, -0.59075975f, -0.59339696f, +-0.59602785f, -0.59865236f, -0.60127044f, -0.60388207f, -0.60648727f, +-0.60908598f, -0.61167812f, -0.61426371f, -0.61684275f, -0.61941516f, +-0.62198097f, -0.62454009f, -0.62709254f, -0.62963831f, -0.63217729f, +-0.63470948f, -0.63723493f, -0.63975352f, -0.64226526f, -0.64477009f, +-0.64726806f, -0.64975911f, -0.65224314f, -0.65472025f, -0.65719032f, +-0.65965337f, -0.66210932f, -0.66455823f, -0.66700000f, -0.66943461f, +-0.67186207f, -0.67428231f, -0.67669535f, -0.67910111f, -0.68149966f, +-0.68389088f, -0.68627477f, -0.68865126f, -0.69102043f, -0.69338220f, +-0.69573659f, -0.69808346f, -0.70042288f, -0.70275480f, -0.70507920f, +-0.70739603f, -0.70970529f, -0.71200693f, -0.71430099f, -0.71658736f, +-0.71886611f, -0.72113711f, -0.72340041f, -0.72565591f, -0.72790372f, +-0.73014367f, -0.73237586f, -0.73460019f, -0.73681659f, -0.73902518f, +-0.74122584f, -0.74341851f, -0.74560326f, -0.74778003f, -0.74994880f, +-0.75210953f, -0.75426215f, -0.75640678f, -0.75854325f, -0.76067162f, +-0.76279181f, -0.76490390f, -0.76700771f, -0.76910341f, -0.77119076f, +-0.77326995f, -0.77534080f, -0.77740335f, -0.77945763f, -0.78150350f, +-0.78354102f, -0.78557014f, -0.78759086f, -0.78960317f, -0.79160696f, +-0.79360235f, -0.79558921f, -0.79756755f, -0.79953730f, -0.80149853f, +-0.80345118f, -0.80539525f, -0.80733067f, -0.80925739f, -0.81117553f, +-0.81308490f, -0.81498563f, -0.81687760f, -0.81876087f, -0.82063532f, +-0.82250100f, -0.82435787f, -0.82620591f, -0.82804507f, -0.82987541f, +-0.83169687f, -0.83350939f, -0.83531296f, -0.83710766f, -0.83889335f, +-0.84067005f, -0.84243774f, -0.84419644f, -0.84594607f, -0.84768665f, +-0.84941816f, -0.85114056f, -0.85285389f, -0.85455805f, -0.85625303f, +-0.85793889f, -0.85961550f, -0.86128294f, -0.86294121f, -0.86459017f, +-0.86622989f, -0.86786032f, -0.86948150f, -0.87109333f, -0.87269586f, +-0.87428904f, -0.87587279f, -0.87744725f, -0.87901229f, -0.88056785f, +-0.88211405f, -0.88365078f, -0.88517809f, -0.88669586f, -0.88820416f, +-0.88970292f, -0.89119220f, -0.89267188f, -0.89414203f, -0.89560264f, +-0.89705360f, -0.89849502f, -0.89992678f, -0.90134889f, -0.90276134f, +-0.90416414f, -0.90555727f, -0.90694070f, -0.90831441f, -0.90967834f, +-0.91103262f, -0.91237706f, -0.91371179f, -0.91503674f, -0.91635185f, +-0.91765714f, -0.91895264f, -0.92023826f, -0.92151409f, -0.92277998f, +-0.92403603f, -0.92528218f, -0.92651838f, -0.92774469f, -0.92896110f, +-0.93016750f, -0.93136400f, -0.93255049f, -0.93372697f, -0.93489349f, +-0.93604994f, -0.93719643f, -0.93833286f, -0.93945926f, -0.94057560f, +-0.94168180f, -0.94277799f, -0.94386405f, -0.94494003f, -0.94600588f, +-0.94706154f, -0.94810712f, -0.94914252f, -0.95016778f, -0.95118284f, +-0.95218778f, -0.95318246f, -0.95416695f, -0.95514119f, -0.95610523f, +-0.95705903f, -0.95800257f, -0.95893586f, -0.95985889f, -0.96077162f, +-0.96167403f, -0.96256620f, -0.96344805f, -0.96431959f, -0.96518075f, +-0.96603161f, -0.96687216f, -0.96770233f, -0.96852213f, -0.96933156f, +-0.97013056f, -0.97091925f, -0.97169751f, -0.97246534f, -0.97322279f, +-0.97396982f, -0.97470641f, -0.97543252f, -0.97614825f, -0.97685349f, +-0.97754824f, -0.97823256f, -0.97890645f, -0.97956979f, -0.98022264f, +-0.98086500f, -0.98149687f, -0.98211825f, -0.98272908f, -0.98332942f, +-0.98391914f, -0.98449844f, -0.98506713f, -0.98562527f, -0.98617285f, +-0.98670989f, -0.98723638f, -0.98775226f, -0.98825759f, -0.98875231f, +-0.98923647f, -0.98971003f, -0.99017298f, -0.99062532f, -0.99106705f, +-0.99149817f, -0.99191868f, -0.99232858f, -0.99272782f, -0.99311644f, +-0.99349445f, -0.99386179f, -0.99421853f, -0.99456459f, -0.99489999f, +-0.99522477f, -0.99553883f, -0.99584228f, -0.99613506f, -0.99641716f, +-0.99668860f, -0.99694937f, -0.99719942f, -0.99743885f, -0.99766755f, +-0.99788558f, -0.99809295f, -0.99828959f, -0.99847561f, -0.99865085f, +-0.99881548f, -0.99896932f, -0.99911255f, -0.99924499f, -0.99936682f, +-0.99947786f, -0.99957830f, -0.99966794f, -0.99974692f, -0.99981517f, +-0.99987274f, -0.99991959f, -0.99995571f, -0.99998116f, -0.99999589f, +0.99999964f, 0.99997288f, 0.99990326f, 0.99979085f, 0.99963558f, +0.99943751f, 0.99919659f, 0.99891287f, 0.99858636f, 0.99821711f, +0.99780506f, 0.99735034f, 0.99685282f, 0.99631262f, 0.99572974f, +0.99510419f, 0.99443603f, 0.99372530f, 0.99297196f, 0.99217612f, +0.99133772f, 0.99045694f, 0.98953366f, 0.98856801f, 0.98756003f, +0.98650974f, 0.98541719f, 0.98428243f, 0.98310548f, 0.98188645f, +0.98062533f, 0.97932225f, 0.97797716f, 0.97659022f, 0.97516143f, +0.97369087f, 0.97217858f, 0.97062469f, 0.96902919f, 0.96739221f, +0.96571374f, 0.96399397f, 0.96223283f, 0.96043050f, 0.95858705f, +0.95670253f, 0.95477700f, 0.95281059f, 0.95080340f, 0.94875544f, +0.94666684f, 0.94453770f, 0.94236809f, 0.94015813f, 0.93790787f, +0.93561745f, 0.93328691f, 0.93091643f, 0.92850608f, 0.92605597f, +0.92356616f, 0.92103678f, 0.91846794f, 0.91585976f, 0.91321236f, +0.91052586f, 0.90780038f, 0.90503591f, 0.90223277f, 0.89939094f, +0.89651060f, 0.89359182f, 0.89063478f, 0.88763964f, 0.88460642f, +0.88153529f, 0.87842643f, 0.87527996f, 0.87209594f, 0.86887461f, +0.86561602f, 0.86232042f, 0.85898781f, 0.85561842f, 0.85221243f, +0.84876984f, 0.84529096f, 0.84177583f, 0.83822471f, 0.83463764f, +0.83101481f, 0.82735640f, 0.82366252f, 0.81993335f, 0.81616908f, +0.81236988f, 0.80853581f, 0.80466717f, 0.80076402f, 0.79682660f, +0.79285502f, 0.78884947f, 0.78481019f, 0.78073722f, 0.77663082f, +0.77249116f, 0.76831841f, 0.76411277f, 0.75987434f, 0.75560343f, +0.75130010f, 0.74696463f, 0.74259710f, 0.73819780f, 0.73376691f, +0.72930455f, 0.72481096f, 0.72028631f, 0.71573079f, 0.71114463f, +0.70652801f, 0.70188117f, 0.69720417f, 0.69249737f, 0.68776089f, +0.68299496f, 0.67819971f, 0.67337549f, 0.66852236f, 0.66364062f, +0.65873051f, 0.65379208f, 0.64882571f, 0.64383155f, 0.63880974f, +0.63376063f, 0.62868434f, 0.62358117f, 0.61845124f, 0.61329484f, +0.60811216f, 0.60290343f, 0.59766883f, 0.59240872f, 0.58712316f, +0.58181250f, 0.57647687f, 0.57111657f, 0.56573176f, 0.56032276f, +0.55488980f, 0.54943299f, 0.54395270f, 0.53844911f, 0.53292239f, +0.52737290f, 0.52180082f, 0.51620632f, 0.51058978f, 0.50495136f, +0.49929130f, 0.49360985f, 0.48790723f, 0.48218375f, 0.47643960f, +0.47067502f, 0.46489030f, 0.45908567f, 0.45326138f, 0.44741765f, +0.44155475f, 0.43567297f, 0.42977250f, 0.42385364f, 0.41791660f, +0.41196167f, 0.40598908f, 0.39999911f, 0.39399201f, 0.38796803f, +0.38192743f, 0.37587047f, 0.36979741f, 0.36370850f, 0.35760403f, +0.35148421f, 0.34534934f, 0.33919969f, 0.33303553f, 0.32685706f, +0.32066461f, 0.31445843f, 0.30823877f, 0.30200592f, 0.29576012f, +0.28950164f, 0.28323078f, 0.27694780f, 0.27065292f, 0.26434645f, +0.25802869f, 0.25169984f, 0.24536023f, 0.23901010f, 0.23264973f, +0.22627939f, 0.21989937f, 0.21350993f, 0.20711134f, 0.20070387f, +0.19428782f, 0.18786344f, 0.18143101f, 0.17499080f, 0.16854310f, +0.16208819f, 0.15562633f, 0.14915779f, 0.14268288f, 0.13620184f, +0.12971498f, 0.12322257f, 0.11672486f, 0.11022217f, 0.10371475f, +0.097202882f, 0.090686858f, 0.084166944f, 0.077643424f, 0.071116582f, +0.064586692f, 0.058054037f, 0.051518895f, 0.044981543f, 0.038442269f, +0.031901345f, 0.025359053f, 0.018815678f, 0.012271495f, 0.0057267868f, +-0.00081816671f, -0.0073630852f, -0.013907688f, -0.020451695f, -0.026994826f, +-0.033536803f, -0.040077340f, -0.046616159f, -0.053152986f, -0.059687532f, +-0.066219524f, -0.072748676f, -0.079274714f, -0.085797355f, -0.092316322f, +-0.098831341f, -0.10534211f, -0.11184838f, -0.11834986f, -0.12484626f, +-0.13133731f, -0.13782275f, -0.14430228f, -0.15077563f, -0.15724251f, +-0.16370267f, -0.17015581f, -0.17660165f, -0.18303993f, -0.18947038f, +-0.19589271f, -0.20230664f, -0.20871192f, -0.21510825f, -0.22149536f, +-0.22787298f, -0.23424086f, -0.24059868f, -0.24694622f, -0.25328314f, +-0.25960925f, -0.26592422f, -0.27222782f, -0.27851975f, -0.28479972f, +-0.29106751f, -0.29732284f, -0.30356544f, -0.30979502f, -0.31601134f, +-0.32221413f, -0.32840309f, -0.33457801f, -0.34073856f, -0.34688455f, +-0.35301566f, -0.35913166f, -0.36523229f, -0.37131724f, -0.37738630f, +-0.38343921f, -0.38947567f, -0.39549544f, -0.40149832f, -0.40748394f, +-0.41345215f, -0.41940263f, -0.42533514f, -0.43124944f, -0.43714526f, +-0.44302234f, -0.44888046f, -0.45471936f, -0.46053877f, -0.46633846f, +-0.47211814f, -0.47787762f, -0.48361665f, -0.48933494f, -0.49503228f, +-0.50070840f, -0.50636309f, -0.51199609f, -0.51760709f, -0.52319598f, +-0.52876246f, -0.53430629f, -0.53982723f, -0.54532504f, -0.55079949f, +-0.55625033f, -0.56167740f, -0.56708032f, -0.57245898f, -0.57781315f, +-0.58314258f, -0.58844697f, -0.59372622f, -0.59897995f, -0.60420811f, +-0.60941035f, -0.61458647f, -0.61973625f, -0.62485951f, -0.62995601f, +-0.63502556f, -0.64006782f, -0.64508271f, -0.65007001f, -0.65502942f, +-0.65996075f, -0.66486382f, -0.66973841f, -0.67458433f, -0.67940134f, +-0.68418926f, -0.68894786f, -0.69367695f, -0.69837630f, -0.70304573f, +-0.70768511f, -0.71229410f, -0.71687263f, -0.72142041f, -0.72593731f, +-0.73042315f, -0.73487765f, -0.73930067f, -0.74369204f, -0.74805158f, +-0.75237900f, -0.75667429f, -0.76093709f, -0.76516730f, -0.76936477f, +-0.77352923f, -0.77766061f, -0.78175867f, -0.78582323f, -0.78985411f, +-0.79385114f, -0.79781419f, -0.80174309f, -0.80563760f, -0.80949765f, +-0.81332302f, -0.81711352f, -0.82086903f, -0.82458937f, -0.82827437f, +-0.83192390f, -0.83553779f, -0.83911592f, -0.84265804f, -0.84616417f, +-0.84963393f, -0.85306740f, -0.85646427f, -0.85982448f, -0.86314780f, +-0.86643422f, -0.86968350f, -0.87289548f, -0.87607014f, -0.87920725f, +-0.88230664f, -0.88536829f, -0.88839203f, -0.89137769f, -0.89432514f, +-0.89723432f, -0.90010506f, -0.90293723f, -0.90573072f, -0.90848541f, +-0.91120118f, -0.91387796f, -0.91651553f, -0.91911387f, -0.92167282f, +-0.92419231f, -0.92667222f, -0.92911243f, -0.93151283f, -0.93387336f, +-0.93619382f, -0.93847424f, -0.94071442f, -0.94291431f, -0.94507378f, +-0.94719279f, -0.94927126f, -0.95130903f, -0.95330608f, -0.95526224f, +-0.95717752f, -0.95905179f, -0.96088499f, -0.96267700f, -0.96442777f, +-0.96613729f, -0.96780539f, -0.96943200f, -0.97101706f, -0.97256058f, +-0.97406244f, -0.97552258f, -0.97694093f, -0.97831738f, -0.97965199f, +-0.98094457f, -0.98219514f, -0.98340368f, -0.98457009f, -0.98569429f, +-0.98677629f, -0.98781598f, -0.98881340f, -0.98976845f, -0.99068111f, +-0.99155134f, -0.99237907f, -0.99316430f, -0.99390697f, -0.99460709f, +-0.99526459f, -0.99587947f, -0.99645168f, -0.99698120f, -0.99746799f, +-0.99791211f, -0.99831343f, -0.99867201f, -0.99898779f, -0.99926084f, +-0.99949104f, -0.99967843f, -0.99982297f, -0.99992472f, -0.99998361f, +0.99999869f, 0.99989158f, 0.99961317f, 0.99916345f, 0.99854255f, +0.99775058f, 0.99678761f, 0.99565387f, 0.99434954f, 0.99287480f, +0.99122995f, 0.98941529f, 0.98743105f, 0.98527765f, 0.98295540f, +0.98046476f, 0.97780609f, 0.97497988f, 0.97198665f, 0.96882683f, +0.96550101f, 0.96200979f, 0.95835376f, 0.95453346f, 0.95054960f, +0.94640291f, 0.94209403f, 0.93762374f, 0.93299282f, 0.92820197f, +0.92325211f, 0.91814411f, 0.91287869f, 0.90745693f, 0.90187967f, +0.89614785f, 0.89026248f, 0.88422459f, 0.87803519f, 0.87169534f, +0.86520612f, 0.85856867f, 0.85178405f, 0.84485358f, 0.83777827f, +0.83055943f, 0.82319832f, 0.81569612f, 0.80805415f, 0.80027372f, +0.79235619f, 0.78430289f, 0.77611518f, 0.76779449f, 0.75934225f, +0.75075996f, 0.74204898f, 0.73321080f, 0.72424710f, 0.71515924f, +0.70594883f, 0.69661748f, 0.68716675f, 0.67759830f, 0.66791373f, +0.65811473f, 0.64820296f, 0.63818014f, 0.62804794f, 0.61780810f, +0.60746247f, 0.59701276f, 0.58646071f, 0.57580817f, 0.56505698f, +0.55420899f, 0.54326600f, 0.53222996f, 0.52110273f, 0.50988621f, +0.49858227f, 0.48719296f, 0.47572014f, 0.46416581f, 0.45253196f, +0.44082057f, 0.42903364f, 0.41717321f, 0.40524128f, 0.39323992f, +0.38117120f, 0.36903715f, 0.35683987f, 0.34458145f, 0.33226398f, +0.31988961f, 0.30746040f, 0.29497850f, 0.28244606f, 0.26986524f, +0.25723818f, 0.24456702f, 0.23185398f, 0.21910121f, 0.20631088f, +0.19348522f, 0.18062639f, 0.16773662f, 0.15481812f, 0.14187308f, +0.12890373f, 0.11591230f, 0.10290100f, 0.089872077f, 0.076827750f, +0.063770257f, 0.050701842f, 0.037624735f, 0.024541186f, 0.011453429f, +-0.0016362892f, -0.014725727f, -0.027812643f, -0.040894791f, -0.053969935f, +-0.067035832f, -0.080090240f, -0.093130924f, -0.10615565f, -0.11916219f, +-0.13214831f, -0.14511178f, -0.15805040f, -0.17096193f, -0.18384418f, +-0.19669491f, -0.20951195f, -0.22229309f, -0.23503613f, -0.24773891f, +-0.26039925f, -0.27301496f, -0.28558388f, -0.29810387f, -0.31057280f, +-0.32298848f, -0.33534884f, -0.34765175f, -0.35989508f, -0.37207675f, +-0.38419467f, -0.39624676f, -0.40823093f, -0.42014518f, -0.43198743f, +-0.44375566f, -0.45544785f, -0.46706200f, -0.47859612f, -0.49004826f, +-0.50141639f, -0.51269865f, -0.52389306f, -0.53499764f, -0.54601061f, +-0.55693001f, -0.56775403f, -0.57848072f, -0.58910829f, -0.59963489f, +-0.61005878f, -0.62037814f, -0.63059121f, -0.64069623f, -0.65069145f, +-0.66057515f, -0.67034572f, -0.68000144f, -0.68954057f, -0.69896162f, +-0.70826286f, -0.71744281f, -0.72649974f, -0.73543227f, -0.74423873f, +-0.75291771f, -0.76146764f, -0.76988715f, -0.77817470f, -0.78632891f, +-0.79434842f, -0.80223179f, -0.80997771f, -0.81758487f, -0.82505190f, +-0.83237761f, -0.83956063f, -0.84659988f, -0.85349399f, -0.86024189f, +-0.86684239f, -0.87329435f, -0.87959671f, -0.88574833f, -0.89174819f, +-0.89759529f, -0.90328854f, -0.90882701f, -0.91420978f, -0.91943592f, +-0.92450452f, -0.92941469f, -0.93416560f, -0.93875647f, -0.94318646f, +-0.94745487f, -0.95156091f, -0.95550388f, -0.95928317f, -0.96289814f, +-0.96634805f, -0.96963239f, -0.97275060f, -0.97570217f, -0.97848648f, +-0.98110318f, -0.98355180f, -0.98583186f, -0.98794299f, -0.98988485f, +-0.99165714f, -0.99325943f, -0.99469161f, -0.99595332f, -0.99704438f, +-0.99796462f, -0.99871385f, -0.99929196f, -0.99969882f, -0.99993443f, +0.99999464f, 0.99956632f, 0.99845290f, 0.99665523f, 0.99417448f, +0.99101239f, 0.98717111f, 0.98265326f, 0.97746199f, 0.97160077f, +0.96507365f, 0.95788515f, 0.95004016f, 0.94154406f, 0.93240267f, +0.92262226f, 0.91220951f, 0.90117162f, 0.88951606f, 0.87725091f, +0.86438453f, 0.85092574f, 0.83688372f, 0.82226819f, 0.80708915f, +0.79135692f, 0.77508235f, 0.75827658f, 0.74095112f, 0.72311783f, +0.70478898f, 0.68597710f, 0.66669506f, 0.64695615f, 0.62677377f, +0.60616189f, 0.58513457f, 0.56370622f, 0.54189157f, 0.51970547f, +0.49716324f, 0.47428027f, 0.45107225f, 0.42755505f, 0.40374488f, +0.37965798f, 0.35531086f, 0.33072025f, 0.30590299f, 0.28087607f, +0.25565663f, 0.23026201f, 0.20470956f, 0.17901683f, 0.15320139f, +0.12728097f, 0.10127331f, 0.075196236f, 0.049067631f, 0.022905400f, +-0.0032725304f, -0.029448219f, -0.055603724f, -0.081721120f, -0.10778251f, +-0.13377003f, -0.15966587f, -0.18545228f, -0.21111161f, -0.23662624f, +-0.26197869f, -0.28715160f, -0.31212771f, -0.33688989f, -0.36142120f, +-0.38570482f, -0.40972409f, -0.43346253f, -0.45690393f, -0.48003218f, +-0.50283146f, -0.52528608f, -0.54738069f, -0.56910020f, -0.59042966f, +-0.61135447f, -0.63186026f, -0.65193301f, -0.67155898f, -0.69072473f, +-0.70941705f, -0.72762316f, -0.74533063f, -0.76252723f, -0.77920127f, +-0.79534131f, -0.81093621f, -0.82597536f, -0.84044844f, -0.85434550f, +-0.86765707f, -0.88037395f, -0.89248747f, -0.90398932f, -0.91487163f, +-0.92512697f, -0.93474823f, -0.94372886f, -0.95206273f, -0.95974404f, +-0.96676767f, -0.97312868f, -0.97882277f, -0.98384601f, -0.98819500f, +-0.99186671f, -0.99485862f, -0.99716878f, -0.99879545f, -0.99973762f, +}; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/native/codec/libraries/opus/celt/static_modes_float_arm_ne10.h b/native/codec/libraries/opus/celt/static_modes_float_arm_ne10.h new file mode 100644 index 0000000..66e1abb --- /dev/null +++ b/native/codec/libraries/opus/celt/static_modes_float_arm_ne10.h @@ -0,0 +1,404 @@ +/* The contents of this file was automatically generated by + * dump_mode_arm_ne10.c with arguments: 48000 960 + * It contains static definitions for some pre-defined modes. */ +#include + +#ifndef NE10_FFT_PARAMS48000_960 +#define NE10_FFT_PARAMS48000_960 +static const ne10_int32_t ne10_factors_480[64] = { +4, 40, 4, 30, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_240[64] = { +3, 20, 4, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_120[64] = { +3, 10, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_60[64] = { +2, 5, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_fft_cpx_float32_t ne10_twiddles_480[480] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f}, +{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f}, +{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f}, +{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f}, +{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f}, +{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f}, +{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f}, +{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f}, +{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f}, +{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f}, +{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f}, +{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f}, +{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f}, +{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f}, +{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f}, +{1.0000000f,-0.0000000f}, {0.99991435f,-0.013089596f}, {0.99965733f,-0.026176950f}, +{0.99922901f,-0.039259817f}, {0.99862951f,-0.052335959f}, {0.99785894f,-0.065403134f}, +{0.99691731f,-0.078459099f}, {0.99580491f,-0.091501623f}, {0.99452192f,-0.10452846f}, +{0.99306846f,-0.11753740f}, {0.99144489f,-0.13052620f}, {0.98965138f,-0.14349262f}, +{0.98768836f,-0.15643448f}, {0.98555607f,-0.16934951f}, {0.98325491f,-0.18223552f}, +{0.98078525f,-0.19509032f}, {0.97814763f,-0.20791170f}, {0.97534233f,-0.22069745f}, +{0.97236991f,-0.23344538f}, {0.96923089f,-0.24615330f}, {0.96592581f,-0.25881904f}, +{0.96245521f,-0.27144045f}, {0.95881975f,-0.28401536f}, {0.95501995f,-0.29654160f}, +{0.95105648f,-0.30901700f}, {0.94693011f,-0.32143945f}, {0.94264150f,-0.33380687f}, +{0.93819129f,-0.34611708f}, {0.93358040f,-0.35836795f}, {0.92880952f,-0.37055743f}, +{0.92387956f,-0.38268346f}, {0.91879117f,-0.39474389f}, {0.91354543f,-0.40673664f}, +{0.90814316f,-0.41865975f}, {0.90258527f,-0.43051112f}, {0.89687270f,-0.44228873f}, +{0.89100653f,-0.45399052f}, {0.88498765f,-0.46561453f}, {0.87881708f,-0.47715878f}, +{0.87249601f,-0.48862126f}, {0.86602545f,-0.50000000f}, {0.85940641f,-0.51129311f}, +{0.85264015f,-0.52249855f}, {0.84572786f,-0.53361452f}, {0.83867055f,-0.54463905f}, +{0.83146960f,-0.55557024f}, {0.82412618f,-0.56640625f}, {0.81664151f,-0.57714522f}, +{0.80901700f,-0.58778524f}, {0.80125380f,-0.59832460f}, {0.79335332f,-0.60876143f}, +{0.78531694f,-0.61909395f}, {0.77714598f,-0.62932038f}, {0.76884180f,-0.63943899f}, +{0.76040596f,-0.64944810f}, {0.75183982f,-0.65934587f}, {0.74314475f,-0.66913062f}, +{0.73432249f,-0.67880076f}, {0.72537434f,-0.68835455f}, {0.71630192f,-0.69779050f}, +{0.70710677f,-0.70710683f}, {0.69779044f,-0.71630198f}, {0.68835455f,-0.72537440f}, +{0.67880070f,-0.73432255f}, {0.66913056f,-0.74314487f}, {0.65934581f,-0.75183982f}, +{0.64944804f,-0.76040596f}, {0.63943899f,-0.76884186f}, {0.62932038f,-0.77714598f}, +{0.61909395f,-0.78531694f}, {0.60876137f,-0.79335338f}, {0.59832460f,-0.80125386f}, +{0.58778524f,-0.80901700f}, {0.57714516f,-0.81664151f}, {0.56640625f,-0.82412618f}, +{0.55557019f,-0.83146960f}, {0.54463899f,-0.83867055f}, {0.53361452f,-0.84572786f}, +{0.52249849f,-0.85264015f}, {0.51129311f,-0.85940641f}, {0.49999997f,-0.86602545f}, +{0.48862118f,-0.87249601f}, {0.47715876f,-0.87881708f}, {0.46561447f,-0.88498765f}, +{0.45399052f,-0.89100653f}, {0.44228867f,-0.89687276f}, {0.43051103f,-0.90258533f}, +{0.41865975f,-0.90814316f}, {0.40673661f,-0.91354549f}, {0.39474380f,-0.91879129f}, +{0.38268343f,-0.92387956f}, {0.37055740f,-0.92880958f}, {0.35836786f,-0.93358046f}, +{0.34611705f,-0.93819135f}, {0.33380681f,-0.94264150f}, {0.32143947f,-0.94693011f}, +{0.30901697f,-0.95105654f}, {0.29654151f,-0.95501995f}, {0.28401533f,-0.95881975f}, +{0.27144039f,-0.96245527f}, {0.25881907f,-0.96592581f}, {0.24615327f,-0.96923089f}, +{0.23344530f,-0.97236991f}, {0.22069745f,-0.97534233f}, {0.20791166f,-0.97814763f}, +{0.19509023f,-0.98078531f}, {0.18223552f,-0.98325491f}, {0.16934945f,-0.98555607f}, +{0.15643437f,-0.98768836f}, {0.14349259f,-0.98965138f}, {0.13052613f,-0.99144489f}, +{0.11753740f,-0.99306846f}, {0.10452842f,-0.99452192f}, {0.091501534f,-0.99580491f}, +{0.078459084f,-0.99691731f}, {0.065403074f,-0.99785894f}, {0.052335974f,-0.99862951f}, +{0.039259788f,-0.99922901f}, {0.026176875f,-0.99965733f}, {0.013089597f,-0.99991435f}, +{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f}, +{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f}, +{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f}, +{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f}, +{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f}, +{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f}, +{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f}, +{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f}, +{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f}, +{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f}, +{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f}, +{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f}, +{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f}, +{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f}, +{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f}, +{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f}, +{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f}, +{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f}, +{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f}, +{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f}, +{-4.3711388e-08f,-1.0000000f}, {-0.026176963f,-0.99965733f}, {-0.052336060f,-0.99862951f}, +{-0.078459173f,-0.99691731f}, {-0.10452851f,-0.99452192f}, {-0.13052621f,-0.99144489f}, +{-0.15643445f,-0.98768836f}, {-0.18223560f,-0.98325491f}, {-0.20791174f,-0.97814757f}, +{-0.23344538f,-0.97236991f}, {-0.25881916f,-0.96592581f}, {-0.28401542f,-0.95881969f}, +{-0.30901703f,-0.95105648f}, {-0.33380687f,-0.94264150f}, {-0.35836795f,-0.93358040f}, +{-0.38268352f,-0.92387950f}, {-0.40673670f,-0.91354543f}, {-0.43051112f,-0.90258527f}, +{-0.45399061f,-0.89100647f}, {-0.47715873f,-0.87881708f}, {-0.50000006f,-0.86602533f}, +{-0.52249867f,-0.85264009f}, {-0.54463905f,-0.83867055f}, {-0.56640631f,-0.82412612f}, +{-0.58778518f,-0.80901700f}, {-0.60876143f,-0.79335332f}, {-0.62932050f,-0.77714586f}, +{-0.64944804f,-0.76040596f}, {-0.66913068f,-0.74314475f}, {-0.68835467f,-0.72537428f}, +{-0.70710677f,-0.70710677f}, {-0.72537446f,-0.68835449f}, {-0.74314493f,-0.66913044f}, +{-0.76040596f,-0.64944804f}, {-0.77714604f,-0.62932026f}, {-0.79335332f,-0.60876143f}, +{-0.80901700f,-0.58778518f}, {-0.82412624f,-0.56640613f}, {-0.83867055f,-0.54463899f}, +{-0.85264021f,-0.52249849f}, {-0.86602539f,-0.50000006f}, {-0.87881714f,-0.47715873f}, +{-0.89100659f,-0.45399037f}, {-0.90258527f,-0.43051112f}, {-0.91354549f,-0.40673658f}, +{-0.92387956f,-0.38268328f}, {-0.93358040f,-0.35836792f}, {-0.94264150f,-0.33380675f}, +{-0.95105654f,-0.30901679f}, {-0.95881975f,-0.28401530f}, {-0.96592587f,-0.25881892f}, +{-0.97236991f,-0.23344538f}, {-0.97814763f,-0.20791161f}, {-0.98325491f,-0.18223536f}, +{-0.98768836f,-0.15643445f}, {-0.99144489f,-0.13052608f}, {-0.99452192f,-0.10452849f}, +{-0.99691737f,-0.078459039f}, {-0.99862957f,-0.052335810f}, {-0.99965733f,-0.026176952f}, +{1.0000000f,-0.0000000f}, {0.99922901f,-0.039259817f}, {0.99691731f,-0.078459099f}, +{0.99306846f,-0.11753740f}, {0.98768836f,-0.15643448f}, {0.98078525f,-0.19509032f}, +{0.97236991f,-0.23344538f}, {0.96245521f,-0.27144045f}, {0.95105648f,-0.30901700f}, +{0.93819129f,-0.34611708f}, {0.92387956f,-0.38268346f}, {0.90814316f,-0.41865975f}, +{0.89100653f,-0.45399052f}, {0.87249601f,-0.48862126f}, {0.85264015f,-0.52249855f}, +{0.83146960f,-0.55557024f}, {0.80901700f,-0.58778524f}, {0.78531694f,-0.61909395f}, +{0.76040596f,-0.64944810f}, {0.73432249f,-0.67880076f}, {0.70710677f,-0.70710683f}, +{0.67880070f,-0.73432255f}, {0.64944804f,-0.76040596f}, {0.61909395f,-0.78531694f}, +{0.58778524f,-0.80901700f}, {0.55557019f,-0.83146960f}, {0.52249849f,-0.85264015f}, +{0.48862118f,-0.87249601f}, {0.45399052f,-0.89100653f}, {0.41865975f,-0.90814316f}, +{0.38268343f,-0.92387956f}, {0.34611705f,-0.93819135f}, {0.30901697f,-0.95105654f}, +{0.27144039f,-0.96245527f}, {0.23344530f,-0.97236991f}, {0.19509023f,-0.98078531f}, +{0.15643437f,-0.98768836f}, {0.11753740f,-0.99306846f}, {0.078459084f,-0.99691731f}, +{0.039259788f,-0.99922901f}, {-4.3711388e-08f,-1.0000000f}, {-0.039259877f,-0.99922901f}, +{-0.078459173f,-0.99691731f}, {-0.11753749f,-0.99306846f}, {-0.15643445f,-0.98768836f}, +{-0.19509032f,-0.98078525f}, {-0.23344538f,-0.97236991f}, {-0.27144048f,-0.96245521f}, +{-0.30901703f,-0.95105648f}, {-0.34611711f,-0.93819129f}, {-0.38268352f,-0.92387950f}, +{-0.41865984f,-0.90814310f}, {-0.45399061f,-0.89100647f}, {-0.48862135f,-0.87249595f}, +{-0.52249867f,-0.85264009f}, {-0.55557036f,-0.83146954f}, {-0.58778518f,-0.80901700f}, +{-0.61909389f,-0.78531694f}, {-0.64944804f,-0.76040596f}, {-0.67880076f,-0.73432249f}, +{-0.70710677f,-0.70710677f}, {-0.73432249f,-0.67880070f}, {-0.76040596f,-0.64944804f}, +{-0.78531694f,-0.61909389f}, {-0.80901700f,-0.58778518f}, {-0.83146966f,-0.55557019f}, +{-0.85264021f,-0.52249849f}, {-0.87249607f,-0.48862115f}, {-0.89100659f,-0.45399037f}, +{-0.90814322f,-0.41865960f}, {-0.92387956f,-0.38268328f}, {-0.93819135f,-0.34611690f}, +{-0.95105654f,-0.30901679f}, {-0.96245521f,-0.27144048f}, {-0.97236991f,-0.23344538f}, +{-0.98078531f,-0.19509031f}, {-0.98768836f,-0.15643445f}, {-0.99306846f,-0.11753736f}, +{-0.99691737f,-0.078459039f}, {-0.99922901f,-0.039259743f}, {-1.0000000f,8.7422777e-08f}, +{-0.99922901f,0.039259918f}, {-0.99691731f,0.078459218f}, {-0.99306846f,0.11753753f}, +{-0.98768830f,0.15643461f}, {-0.98078525f,0.19509049f}, {-0.97236985f,0.23344554f}, +{-0.96245515f,0.27144065f}, {-0.95105654f,0.30901697f}, {-0.93819135f,0.34611705f}, +{-0.92387956f,0.38268346f}, {-0.90814316f,0.41865975f}, {-0.89100653f,0.45399055f}, +{-0.87249601f,0.48862129f}, {-0.85264015f,0.52249861f}, {-0.83146960f,0.55557030f}, +{-0.80901694f,0.58778536f}, {-0.78531688f,0.61909401f}, {-0.76040590f,0.64944816f}, +{-0.73432243f,0.67880082f}, {-0.70710665f,0.70710689f}, {-0.67880058f,0.73432261f}, +{-0.64944792f,0.76040608f}, {-0.61909378f,0.78531706f}, {-0.58778507f,0.80901712f}, +{-0.55557001f,0.83146977f}, {-0.52249837f,0.85264033f}, {-0.48862100f,0.87249613f}, +{-0.45399022f,0.89100665f}, {-0.41865945f,0.90814328f}, {-0.38268313f,0.92387968f}, +{-0.34611672f,0.93819147f}, {-0.30901709f,0.95105648f}, {-0.27144054f,0.96245521f}, +{-0.23344545f,0.97236991f}, {-0.19509038f,0.98078525f}, {-0.15643452f,0.98768830f}, +{-0.11753743f,0.99306846f}, {-0.078459114f,0.99691731f}, {-0.039259821f,0.99922901f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_240[240] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f}, +{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f}, +{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f}, +{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f}, +{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f}, +{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f}, +{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f}, +{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f}, +{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f}, +{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f}, +{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f}, +{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f}, +{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f}, +{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f}, +{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f}, +{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f}, +{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f}, +{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f}, +{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f}, +{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f}, +{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f}, +{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f}, +{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f}, +{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f}, +{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{-4.3711388e-08f,-1.0000000f}, {-0.052336060f,-0.99862951f}, {-0.10452851f,-0.99452192f}, +{-0.15643445f,-0.98768836f}, {-0.20791174f,-0.97814757f}, {-0.25881916f,-0.96592581f}, +{-0.30901703f,-0.95105648f}, {-0.35836795f,-0.93358040f}, {-0.40673670f,-0.91354543f}, +{-0.45399061f,-0.89100647f}, {-0.50000006f,-0.86602533f}, {-0.54463905f,-0.83867055f}, +{-0.58778518f,-0.80901700f}, {-0.62932050f,-0.77714586f}, {-0.66913068f,-0.74314475f}, +{-0.70710677f,-0.70710677f}, {-0.74314493f,-0.66913044f}, {-0.77714604f,-0.62932026f}, +{-0.80901700f,-0.58778518f}, {-0.83867055f,-0.54463899f}, {-0.86602539f,-0.50000006f}, +{-0.89100659f,-0.45399037f}, {-0.91354549f,-0.40673658f}, {-0.93358040f,-0.35836792f}, +{-0.95105654f,-0.30901679f}, {-0.96592587f,-0.25881892f}, {-0.97814763f,-0.20791161f}, +{-0.98768836f,-0.15643445f}, {-0.99452192f,-0.10452849f}, {-0.99862957f,-0.052335810f}, +{1.0000000f,-0.0000000f}, {0.99691731f,-0.078459099f}, {0.98768836f,-0.15643448f}, +{0.97236991f,-0.23344538f}, {0.95105648f,-0.30901700f}, {0.92387956f,-0.38268346f}, +{0.89100653f,-0.45399052f}, {0.85264015f,-0.52249855f}, {0.80901700f,-0.58778524f}, +{0.76040596f,-0.64944810f}, {0.70710677f,-0.70710683f}, {0.64944804f,-0.76040596f}, +{0.58778524f,-0.80901700f}, {0.52249849f,-0.85264015f}, {0.45399052f,-0.89100653f}, +{0.38268343f,-0.92387956f}, {0.30901697f,-0.95105654f}, {0.23344530f,-0.97236991f}, +{0.15643437f,-0.98768836f}, {0.078459084f,-0.99691731f}, {-4.3711388e-08f,-1.0000000f}, +{-0.078459173f,-0.99691731f}, {-0.15643445f,-0.98768836f}, {-0.23344538f,-0.97236991f}, +{-0.30901703f,-0.95105648f}, {-0.38268352f,-0.92387950f}, {-0.45399061f,-0.89100647f}, +{-0.52249867f,-0.85264009f}, {-0.58778518f,-0.80901700f}, {-0.64944804f,-0.76040596f}, +{-0.70710677f,-0.70710677f}, {-0.76040596f,-0.64944804f}, {-0.80901700f,-0.58778518f}, +{-0.85264021f,-0.52249849f}, {-0.89100659f,-0.45399037f}, {-0.92387956f,-0.38268328f}, +{-0.95105654f,-0.30901679f}, {-0.97236991f,-0.23344538f}, {-0.98768836f,-0.15643445f}, +{-0.99691737f,-0.078459039f}, {-1.0000000f,8.7422777e-08f}, {-0.99691731f,0.078459218f}, +{-0.98768830f,0.15643461f}, {-0.97236985f,0.23344554f}, {-0.95105654f,0.30901697f}, +{-0.92387956f,0.38268346f}, {-0.89100653f,0.45399055f}, {-0.85264015f,0.52249861f}, +{-0.80901694f,0.58778536f}, {-0.76040590f,0.64944816f}, {-0.70710665f,0.70710689f}, +{-0.64944792f,0.76040608f}, {-0.58778507f,0.80901712f}, {-0.52249837f,0.85264033f}, +{-0.45399022f,0.89100665f}, {-0.38268313f,0.92387968f}, {-0.30901709f,0.95105648f}, +{-0.23344545f,0.97236991f}, {-0.15643452f,0.98768830f}, {-0.078459114f,0.99691731f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_120[120] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f}, +{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f}, +{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f}, +{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f}, +{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f}, +{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f}, +{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f}, +{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f}, +{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f}, +{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f}, +{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f}, +{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f}, +{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f}, +{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f}, +{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_60[60] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f}, +{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f}, +{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f}, +{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f}, +{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f}, +}; +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_480 = { +120, +(ne10_int32_t *)ne10_factors_480, +(ne10_fft_cpx_float32_t *)ne10_twiddles_480, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_480[120], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_480 = { +1, +(void *)&ne10_fft_state_float32_t_480, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_240 = { +60, +(ne10_int32_t *)ne10_factors_240, +(ne10_fft_cpx_float32_t *)ne10_twiddles_240, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_240[60], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_240 = { +1, +(void *)&ne10_fft_state_float32_t_240, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_120 = { +30, +(ne10_int32_t *)ne10_factors_120, +(ne10_fft_cpx_float32_t *)ne10_twiddles_120, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_120[30], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_120 = { +1, +(void *)&ne10_fft_state_float32_t_120, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_60 = { +15, +(ne10_int32_t *)ne10_factors_60, +(ne10_fft_cpx_float32_t *)ne10_twiddles_60, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_60[15], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_60 = { +1, +(void *)&ne10_fft_state_float32_t_60, +}; + +#endif /* end NE10_FFT_PARAMS48000_960 */ diff --git a/native/codec/libraries/opus/celt/tests/test_unit_cwrs32.c b/native/codec/libraries/opus/celt/tests/test_unit_cwrs32.c new file mode 100644 index 0000000..36dd8af --- /dev/null +++ b/native/codec/libraries/opus/celt/tests/test_unit_cwrs32.c @@ -0,0 +1,161 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation, + Gregory Maxwell + Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#else +#define TEST_CUSTOM_MODES +#endif + +#define CELT_C +#include "stack_alloc.h" +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" +#include "cwrs.c" +#include "mathops.c" +#include "rate.h" + +#define NMAX (240) +#define KMAX (128) + +#ifdef TEST_CUSTOM_MODES + +#define NDIMS (44) +static const int pn[NDIMS]={ + 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 20, 22, + 24, 26, 28, 30, 32, 36, 40, 44, 48, + 52, 56, 60, 64, 72, 80, 88, 96, 104, + 112, 120, 128, 144, 160, 176, 192, 208 +}; +static const int pkmax[NDIMS]={ + 128, 128, 128, 128, 88, 52, 36, 26, 22, + 18, 16, 15, 13, 12, 12, 11, 10, 9, + 9, 8, 8, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 5, 5, 5, 5, 5, 5, + 4, 4, 4, 4, 4, 4, 4, 4 +}; + +#else /* TEST_CUSTOM_MODES */ + +#define NDIMS (22) +static const int pn[NDIMS]={ + 2, 3, 4, 6, 8, 9, 11, 12, 16, + 18, 22, 24, 32, 36, 44, 48, 64, 72, + 88, 96, 144, 176 +}; +static const int pkmax[NDIMS]={ + 128, 128, 128, 88, 36, 26, 18, 16, 12, + 11, 9, 9, 7, 7, 6, 6, 5, 5, + 5, 5, 4, 4 +}; + +#endif + +int main(void){ + int t; + int n; + ALLOC_STACK; + for(t=0;tpkmax[t])break; + printf("Testing CWRS with N=%i, K=%i...\n",n,k); +#if defined(SMALL_FOOTPRINT) + nc=ncwrs_urow(n,k,uu); +#else + nc=CELT_PVQ_V(n,k); +#endif + inc=nc/20000; + if(inc<1)inc=1; + for(i=0;i");*/ +#if defined(SMALL_FOOTPRINT) + ii=icwrs(n,k,&v,y,u); +#else + ii=icwrs(n,y); + v=CELT_PVQ_V(n,k); +#endif + if(ii!=i){ + fprintf(stderr,"Combination-index mismatch (%lu!=%lu).\n", + (long)ii,(long)i); + return 1; + } + if(v!=nc){ + fprintf(stderr,"Combination count mismatch (%lu!=%lu).\n", + (long)v,(long)nc); + return 2; + } + /*printf(" %6u\n",i);*/ + } + /*printf("\n");*/ + } + } + return 0; +} diff --git a/native/codec/libraries/opus/celt/tests/test_unit_dft.c b/native/codec/libraries/opus/celt/tests/test_unit_dft.c new file mode 100644 index 0000000..70f8f49 --- /dev/null +++ b/native/codec/libraries/opus/celt/tests/test_unit_dft.c @@ -0,0 +1,179 @@ +/* Copyright (c) 2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "stack_alloc.h" +#include "kiss_fft.h" +#include "mathops.h" +#include "modes.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +int ret = 0; + +void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse) +{ + int bin,k; + double errpow=0,sigpow=0, snr; + + for (bin=0;binmdct.kfft[id]; +#endif + + in = (kiss_fft_cpx*)malloc(buflen); + out = (kiss_fft_cpx*)malloc(buflen); + + for (k=0;k1) { + int k; + for (k=1;k +#include +#include +#include +#define CELT_C +#include "entcode.h" +#include "entenc.h" +#include "entdec.h" +#include + +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" + +#ifndef M_LOG2E +# define M_LOG2E 1.4426950408889634074 +#endif +#define DATA_SIZE 10000000 +#define DATA_SIZE2 10000 + +int main(int _argc,char **_argv){ + ec_enc enc; + ec_dec dec; + long nbits; + long nbits2; + double entropy; + int ft; + int ftb; + int sz; + int i; + int ret; + unsigned int sym; + unsigned int seed; + unsigned char *ptr; + const char *env_seed; + ret=0; + entropy=0; + if (_argc > 2) { + fprintf(stderr, "Usage: %s []\n", _argv[0]); + return 1; + } + env_seed = getenv("SEED"); + if (_argc > 1) + seed = atoi(_argv[1]); + else if (env_seed) + seed = atoi(env_seed); + else + seed = time(NULL); + /*Testing encoding of raw bit values.*/ + ptr = (unsigned char *)malloc(DATA_SIZE); + ec_enc_init(&enc,ptr, DATA_SIZE); + for(ft=2;ft<1024;ft++){ + for(i=0;i>(rand()%11U))+1U)+10; + sz=rand()/((RAND_MAX>>(rand()%9U))+1U); + data=(unsigned *)malloc(sz*sizeof(*data)); + tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); + ec_enc_init(&enc,ptr,DATA_SIZE2); + zeros = rand()%13==0; + tell[0]=ec_tell_frac(&enc); + for(j=0;j>(rand()%9U))+1U); + logp1=(unsigned *)malloc(sz*sizeof(*logp1)); + data=(unsigned *)malloc(sz*sizeof(*data)); + tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); + enc_method=(unsigned *)malloc(sz*sizeof(*enc_method)); + ec_enc_init(&enc,ptr,DATA_SIZE2); + tell[0]=ec_tell_frac(&enc); + for(j=0;j>1)+1); + logp1[j]=(rand()%15)+1; + enc_method[j]=rand()/((RAND_MAX>>2)+1); + switch(enc_method[j]){ + case 0:{ + ec_encode(&enc,data[j]?(1<>2)+1); + switch(dec_method){ + case 0:{ + fs=ec_decode(&dec,1<=(1<=(1< +#include +#define CELT_C +#include "laplace.h" +#include "stack_alloc.h" + +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" +#include "laplace.c" + +#define DATA_SIZE 40000 + +int ec_laplace_get_start_freq(int decay) +{ + opus_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1); + int fs = (ft*(16384-decay))/(16384+decay); + return fs+LAPLACE_MINP; +} + +int main(void) +{ + int i; + int ret = 0; + ec_enc enc; + ec_dec dec; + unsigned char *ptr; + int val[10000], decay[10000]; + ALLOC_STACK; + ptr = (unsigned char *)malloc(DATA_SIZE); + ec_enc_init(&enc,ptr,DATA_SIZE); + + val[0] = 3; decay[0] = 6000; + val[1] = 0; decay[1] = 5800; + val[2] = -1; decay[2] = 5600; + for (i=3;i<10000;i++) + { + val[i] = rand()%15-7; + decay[i] = rand()%11000+5000; + } + for (i=0;i<10000;i++) + ec_laplace_encode(&enc, &val[i], + ec_laplace_get_start_freq(decay[i]), decay[i]); + + ec_enc_done(&enc); + + ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc)); + + for (i=0;i<10000;i++) + { + int d = ec_laplace_decode(&dec, + ec_laplace_get_start_freq(decay[i]), decay[i]); + if (d != val[i]) + { + fprintf (stderr, "Got %d instead of %d\n", d, val[i]); + ret = 1; + } + } + + free(ptr); + return ret; +} diff --git a/native/codec/libraries/opus/celt/tests/test_unit_mathops.c b/native/codec/libraries/opus/celt/tests/test_unit_mathops.c new file mode 100644 index 0000000..874e9ad --- /dev/null +++ b/native/codec/libraries/opus/celt/tests/test_unit_mathops.c @@ -0,0 +1,266 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation, + Gregory Maxwell + Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#endif + +#include +#include +#include "mathops.h" +#include "bands.h" + +#ifdef FIXED_POINT +#define WORD "%d" +#else +#define WORD "%f" +#endif + +int ret = 0; + +void testdiv(void) +{ + opus_int32 i; + for (i=1;i<=327670;i++) + { + double prod; + opus_val32 val; + val = celt_rcp(i); +#ifdef FIXED_POINT + prod = (1./32768./65526.)*val*i; +#else + prod = val*i; +#endif + if (fabs(prod-1) > .00025) + { + fprintf (stderr, "div failed: 1/%d="WORD" (product = %f)\n", i, val, prod); + ret = 1; + } + } +} + +void testsqrt(void) +{ + opus_int32 i; + for (i=1;i<=1000000000;i++) + { + double ratio; + opus_val16 val; + val = celt_sqrt(i); + ratio = val/sqrt(i); + if (fabs(ratio - 1) > .0005 && fabs(val-sqrt(i)) > 2) + { + fprintf (stderr, "sqrt failed: sqrt(%d)="WORD" (ratio = %f)\n", i, val, ratio); + ret = 1; + } + i+= i>>10; + } +} + +void testbitexactcos(void) +{ + int i; + opus_int32 min_d,max_d,last,chk; + chk=max_d=0; + last=min_d=32767; + for(i=64;i<=16320;i++) + { + opus_int32 d; + opus_int32 q=bitexact_cos(i); + chk ^= q*i; + d = last - q; + if (d>max_d)max_d=d; + if (dmax_d)max_d=d; + if (d0.0009) + { + fprintf (stderr, "celt_log2 failed: fabs((1.442695040888963387*log(x))-celt_log2(x))>0.001 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} + +void testexp2(void) +{ + float x; + for (x=-11.0;x<24.0;x+=0.0007) + { + float error = fabs(x-(1.442695040888963387*log(celt_exp2(x)))); + if (error>0.0002) + { + fprintf (stderr, "celt_exp2 failed: fabs(x-(1.442695040888963387*log(celt_exp2(x))))>0.0005 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} + +void testexp2log2(void) +{ + float x; + for (x=-11.0;x<24.0;x+=0.0007) + { + float error = fabs(x-(celt_log2(celt_exp2(x)))); + if (error>0.001) + { + fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_log2(celt_exp2(x))))>0.001 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} +#else +void testlog2(void) +{ + opus_val32 x; + for (x=8;x<1073741824;x+=(x>>3)) + { + float error = fabs((1.442695040888963387*log(x/16384.0))-celt_log2(x)/1024.0); + if (error>0.003) + { + fprintf (stderr, "celt_log2 failed: x = %ld, error = %f\n", (long)x,error); + ret = 1; + } + } +} + +void testexp2(void) +{ + opus_val16 x; + for (x=-32768;x<15360;x++) + { + float error1 = fabs(x/1024.0-(1.442695040888963387*log(celt_exp2(x)/65536.0))); + float error2 = fabs(exp(0.6931471805599453094*x/1024.0)-celt_exp2(x)/65536.0); + if (error1>0.0002&&error2>0.00004) + { + fprintf (stderr, "celt_exp2 failed: x = "WORD", error1 = %f, error2 = %f\n", x,error1,error2); + ret = 1; + } + } +} + +void testexp2log2(void) +{ + opus_val32 x; + for (x=8;x<65536;x+=(x>>3)) + { + float error = fabs(x-0.25*celt_exp2(celt_log2(x)))/16384; + if (error>0.004) + { + fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_exp2(celt_log2(x))))>0.001 (x = %ld, error = %f)\n", (long)x,error); + ret = 1; + } + } +} + +void testilog2(void) +{ + opus_val32 x; + for (x=1;x<=268435455;x+=127) + { + opus_val32 lg; + opus_val32 y; + + lg = celt_ilog2(x); + if (lg<0 || lg>=31) + { + printf("celt_ilog2 failed: 0<=celt_ilog2(x)<31 (x = %d, celt_ilog2(x) = %d)\n",x,lg); + ret = 1; + } + y = 1<>1)>=y) + { + printf("celt_ilog2 failed: 2**celt_ilog2(x)<=x<2**(celt_ilog2(x)+1) (x = %d, 2**celt_ilog2(x) = %d)\n",x,y); + ret = 1; + } + } +} +#endif + +int main(void) +{ + testbitexactcos(); + testbitexactlog2tan(); + testdiv(); + testsqrt(); + testlog2(); + testexp2(); + testexp2log2(); +#ifdef FIXED_POINT + testilog2(); +#endif + return ret; +} diff --git a/native/codec/libraries/opus/celt/tests/test_unit_mdct.c b/native/codec/libraries/opus/celt/tests/test_unit_mdct.c new file mode 100644 index 0000000..4a563cc --- /dev/null +++ b/native/codec/libraries/opus/celt/tests/test_unit_mdct.c @@ -0,0 +1,227 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "mdct.h" +#include "stack_alloc.h" +#include "kiss_fft.h" +#include "mdct.h" +#include "modes.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +int ret = 0; +void check(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse) +{ + int bin,k; + double errpow=0,sigpow=0; + double snr; + for (bin=0;binmdct; +#endif + + in = (kiss_fft_scalar*)malloc(buflen); + in_copy = (kiss_fft_scalar*)malloc(buflen); + out = (kiss_fft_scalar*)malloc(buflen); + window = (opus_val16*)malloc(sizeof(opus_val16)*nfft/2); + + for (k=0;k1) { + int k; + for (k=1;k +#include +#include "vq.h" +#include "bands.h" +#include "stack_alloc.h" +#include + + +#define MAX_SIZE 100 + +int ret=0; +void test_rotation(int N, int K) +{ + int i; + double err = 0, ener = 0, snr, snr0; + opus_val16 x0[MAX_SIZE]; + opus_val16 x1[MAX_SIZE]; + for (i=0;i 20) + { + fprintf(stderr, "FAIL!\n"); + ret = 1; + } +} + +int main(void) +{ + ALLOC_STACK; + test_rotation(15, 3); + test_rotation(23, 5); + test_rotation(50, 3); + test_rotation(80, 1); + return ret; +} diff --git a/native/codec/libraries/opus/celt/tests/test_unit_types.c b/native/codec/libraries/opus/celt/tests/test_unit_types.c new file mode 100644 index 0000000..67a0fb8 --- /dev/null +++ b/native/codec/libraries/opus/celt/tests/test_unit_types.c @@ -0,0 +1,50 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_types.h" +#include + +int main(void) +{ + opus_int16 i = 1; + i <<= 14; + if (i>>14 != 1) + { + fprintf(stderr, "opus_int16 isn't 16 bits\n"); + return 1; + } + if (sizeof(opus_int16)*2 != sizeof(opus_int32)) + { + fprintf(stderr, "16*2 != 32\n"); + return 1; + } + return 0; +} diff --git a/native/codec/libraries/opus/celt/vq.c b/native/codec/libraries/opus/celt/vq.c new file mode 100644 index 0000000..8011e22 --- /dev/null +++ b/native/codec/libraries/opus/celt/vq.c @@ -0,0 +1,442 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "cwrs.h" +#include "vq.h" +#include "arch.h" +#include "os_support.h" +#include "bands.h" +#include "rate.h" +#include "pitch.h" + +#if defined(MIPSr1_ASM) +#include "mips/vq_mipsr1.h" +#endif + +#ifndef OVERRIDE_vq_exp_rotation1 +static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) +{ + int i; + opus_val16 ms; + celt_norm *Xptr; + Xptr = X; + ms = NEG16(s); + for (i=0;i=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } +} +#endif /* OVERRIDE_vq_exp_rotation1 */ + +void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread) +{ + static const int SPREAD_FACTOR[3]={15,10,5}; + int i; + opus_val16 c, s; + opus_val16 gain, theta; + int stride2=0; + int factor; + + if (2*K>=len || spread==SPREAD_NONE) + return; + factor = SPREAD_FACTOR[spread-1]; + + gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K)); + theta = HALF16(MULT16_16_Q15(gain,gain)); + + c = celt_cos_norm(EXTEND32(theta)); + s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */ + + if (len>=8*stride) + { + stride2 = 1; + /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. */ + while ((stride2*stride2+stride2)*stride + (stride>>2) < len) + stride2++; + } + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ + len = celt_udiv(len, stride); + for (i=0;i>1; +#endif + t = VSHR32(Ryy, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + i=0; + do + X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1)); + while (++i < N); +} + +static unsigned extract_collapse_mask(int *iy, int N, int B) +{ + unsigned collapse_mask; + int N0; + int i; + if (B<=1) + return 1; + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + exp_rotation().*/ + N0 = celt_udiv(N, B); + collapse_mask = 0; + i=0; do { + int j; + unsigned tmp=0; + j=0; do { + tmp |= iy[i*N0+j]; + } while (++j (N>>1)) + { + opus_val16 rcp; + j=0; do { + sum += X[j]; + } while (++j EPSILON && sum < 64)) +#endif + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=0); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ +#ifdef FIXED_POINT_DEBUG + celt_sig_assert(pulsesLeft<=N+3); +#endif + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + for (i=0;i= best_num/best_den, but that way + we can do it without any division */ + /* OPT: It's not clear whether a cmov is faster than a branch here + since the condition is more often false than true and using + a cmov introduces data dependencies across iterations. The optimal + choice may be architecture-dependent. */ + if (opus_unlikely(MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))) + { + best_den = Ryy; + best_num = Rxy; + best_id = j; + } + } while (++j0, "alg_quant() needs at least one pulse"); + celt_assert2(N>1, "alg_quant() needs at least two dimensions"); + + /* Covers vectorization by up to 4. */ + ALLOC(iy, N+3, int); + + exp_rotation(X, N, 1, B, K, spread); + + yy = op_pvq_search(X, iy, K, N, arch); + + encode_pulses(iy, N, K, enc); + + if (resynth) + { + normalise_residual(iy, X, N, yy, gain); + exp_rotation(X, N, -1, B, K, spread); + } + + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +/** Decode pulse vector and combine the result with the pitch vector to produce + the final normalised signal in the current band. */ +unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B, + ec_dec *dec, opus_val16 gain) +{ + opus_val32 Ryy; + unsigned collapse_mask; + VARDECL(int, iy); + SAVE_STACK; + + celt_assert2(K>0, "alg_unquant() needs at least one pulse"); + celt_assert2(N>1, "alg_unquant() needs at least two dimensions"); + ALLOC(iy, N, int); + Ryy = decode_pulses(iy, N, K, dec); + normalise_residual(iy, X, N, Ryy, gain); + exp_rotation(X, N, -1, B, K, spread); + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +#ifndef OVERRIDE_renormalise_vector +void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E; + opus_val16 g; + opus_val32 t; + celt_norm *xptr; + E = EPSILON + celt_inner_prod(X, X, N, arch); +#ifdef FIXED_POINT + k = celt_ilog2(E)>>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i +#include +#include +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" +#include "x86cpu.h" + +#if defined(FIXED_POINT) + +void celt_fir_sse4_1(const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + int arch) +{ + int i,j; + VARDECL(opus_val16, rnum); + + __m128i vecNoA; + opus_int32 noA ; + SAVE_STACK; + + ALLOC(rnum, ord, opus_val16); + for(i=0;i> 1; + vecNoA = _mm_set_epi32(noA, noA, noA, noA); + + for (i=0;i +#include "arch.h" + +void xcorr_kernel_sse(const opus_val16 *x, const opus_val16 *y, opus_val32 sum[4], int len) +{ + int j; + __m128 xsum1, xsum2; + xsum1 = _mm_loadu_ps(sum); + xsum2 = _mm_setzero_ps(); + + for (j = 0; j < len-3; j += 4) + { + __m128 x0 = _mm_loadu_ps(x+j); + __m128 yj = _mm_loadu_ps(y+j); + __m128 y3 = _mm_loadu_ps(y+j+3); + + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x00),yj)); + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x55), + _mm_shuffle_ps(yj,y3,0x49))); + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xaa), + _mm_shuffle_ps(yj,y3,0x9e))); + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xff),y3)); + } + if (j < len) + { + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + if (++j < len) + { + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + if (++j < len) + { + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + } + } + } + _mm_storeu_ps(sum,_mm_add_ps(xsum1,xsum2)); +} + + +void dual_inner_prod_sse(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + __m128 xsum1, xsum2; + xsum1 = _mm_setzero_ps(); + xsum2 = _mm_setzero_ps(); + for (i=0;i +#include + +#include "macros.h" +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE2) && defined(FIXED_POINT) +opus_val32 celt_inner_prod_sse2(const opus_val16 *x, const opus_val16 *y, + int N) +{ + opus_int i, dataSize16; + opus_int32 sum; + + __m128i inVec1_76543210, inVec1_FEDCBA98, acc1; + __m128i inVec2_76543210, inVec2_FEDCBA98, acc2; + + sum = 0; + dataSize16 = N & ~15; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for (i=0;i= 8) + { + inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0])); + inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0])); + + inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210); + + acc1 = _mm_add_epi32(acc1, inVec1_76543210); + i += 8; + } + + acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64( acc1, acc1)); + acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16( acc1, 0x0E)); + sum += _mm_cvtsi128_si32(acc1); + + for (;i +#include + +#include "macros.h" +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT) +#include +#include "x86cpu.h" + +opus_val32 celt_inner_prod_sse4_1(const opus_val16 *x, const opus_val16 *y, + int N) +{ + opus_int i, dataSize16; + opus_int32 sum; + __m128i inVec1_76543210, inVec1_FEDCBA98, acc1; + __m128i inVec2_76543210, inVec2_FEDCBA98, acc2; + __m128i inVec1_3210, inVec2_3210; + + sum = 0; + dataSize16 = N & ~15; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for (i=0;i= 8) + { + inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0])); + inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0])); + + inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210); + + acc1 = _mm_add_epi32(acc1, inVec1_76543210); + i += 8; + } + + if (N - i >= 4) + { + inVec1_3210 = OP_CVTEPI16_EPI32_M64(&x[i + 0]); + inVec2_3210 = OP_CVTEPI16_EPI32_M64(&y[i + 0]); + + inVec1_3210 = _mm_mullo_epi32(inVec1_3210, inVec2_3210); + + acc1 = _mm_add_epi32(acc1, inVec1_3210); + i += 4; + } + + acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64(acc1, acc1)); + acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16(acc1, 0x0E)); + + sum += _mm_cvtsi128_si32(acc1); + + for (;i= 3); + + sum0 = _mm_setzero_si128(); + sum1 = _mm_setzero_si128(); + sum2 = _mm_setzero_si128(); + sum3 = _mm_setzero_si128(); + + for (j=0;j<(len-7);j+=8) + { + vecX = _mm_loadu_si128((__m128i *)(&x[j + 0])); + vecY0 = _mm_loadu_si128((__m128i *)(&y[j + 0])); + vecY1 = _mm_loadu_si128((__m128i *)(&y[j + 1])); + vecY2 = _mm_loadu_si128((__m128i *)(&y[j + 2])); + vecY3 = _mm_loadu_si128((__m128i *)(&y[j + 3])); + + sum0 = _mm_add_epi32(sum0, _mm_madd_epi16(vecX, vecY0)); + sum1 = _mm_add_epi32(sum1, _mm_madd_epi16(vecX, vecY1)); + sum2 = _mm_add_epi32(sum2, _mm_madd_epi16(vecX, vecY2)); + sum3 = _mm_add_epi32(sum3, _mm_madd_epi16(vecX, vecY3)); + } + + sum0 = _mm_add_epi32(sum0, _mm_unpackhi_epi64( sum0, sum0)); + sum0 = _mm_add_epi32(sum0, _mm_shufflelo_epi16( sum0, 0x0E)); + + sum1 = _mm_add_epi32(sum1, _mm_unpackhi_epi64( sum1, sum1)); + sum1 = _mm_add_epi32(sum1, _mm_shufflelo_epi16( sum1, 0x0E)); + + sum2 = _mm_add_epi32(sum2, _mm_unpackhi_epi64( sum2, sum2)); + sum2 = _mm_add_epi32(sum2, _mm_shufflelo_epi16( sum2, 0x0E)); + + sum3 = _mm_add_epi32(sum3, _mm_unpackhi_epi64( sum3, sum3)); + sum3 = _mm_add_epi32(sum3, _mm_shufflelo_epi16( sum3, 0x0E)); + + vecSum = _mm_unpacklo_epi64(_mm_unpacklo_epi32(sum0, sum1), + _mm_unpacklo_epi32(sum2, sum3)); + + for (;j<(len-3);j+=4) + { + vecX = OP_CVTEPI16_EPI32_M64(&x[j + 0]); + vecX0 = _mm_shuffle_epi32(vecX, 0x00); + vecX1 = _mm_shuffle_epi32(vecX, 0x55); + vecX2 = _mm_shuffle_epi32(vecX, 0xaa); + vecX3 = _mm_shuffle_epi32(vecX, 0xff); + + vecY0 = OP_CVTEPI16_EPI32_M64(&y[j + 0]); + vecY1 = OP_CVTEPI16_EPI32_M64(&y[j + 1]); + vecY2 = OP_CVTEPI16_EPI32_M64(&y[j + 2]); + vecY3 = OP_CVTEPI16_EPI32_M64(&y[j + 3]); + + sum0 = _mm_mullo_epi32(vecX0, vecY0); + sum1 = _mm_mullo_epi32(vecX1, vecY1); + sum2 = _mm_mullo_epi32(vecX2, vecY2); + sum3 = _mm_mullo_epi32(vecX3, vecY3); + + sum0 = _mm_add_epi32(sum0, sum1); + sum2 = _mm_add_epi32(sum2, sum3); + vecSum = _mm_add_epi32(vecSum, sum0); + vecSum = _mm_add_epi32(vecSum, sum2); + } + + for (;j +#include +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "vq.h" +#include "x86cpu.h" + + +#ifndef FIXED_POINT + +opus_val16 op_pvq_search_sse2(celt_norm *_X, int *iy, int K, int N, int arch) +{ + int i, j; + int pulsesLeft; + float xy, yy; + VARDECL(celt_norm, y); + VARDECL(celt_norm, X); + VARDECL(float, signy); + __m128 signmask; + __m128 sums; + __m128i fours; + SAVE_STACK; + + (void)arch; + /* All bits set to zero, except for the sign bit. */ + signmask = _mm_set_ps1(-0.f); + fours = _mm_set_epi32(4, 4, 4, 4); + ALLOC(y, N+3, celt_norm); + ALLOC(X, N+3, celt_norm); + ALLOC(signy, N+3, float); + + OPUS_COPY(X, _X, N); + X[N] = X[N+1] = X[N+2] = 0; + sums = _mm_setzero_ps(); + for (j=0;j (N>>1)) + { + __m128i pulses_sum; + __m128 yy4, xy4; + __m128 rcp4; + opus_val32 sum = _mm_cvtss_f32(sums); + /* If X is too small, just replace it with a pulse at 0 */ + /* Prevents infinities and NaNs from causing too many pulses + to be allocated. 64 is an approximation of infinity here. */ + if (!(sum > EPSILON && sum < 64)) + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=0); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + for (i=0;i +static _inline void cpuid(unsigned int CPUInfo[4], unsigned int InfoType) +{ + __cpuid((int*)CPUInfo, InfoType); +} + +#else + +#if defined(CPU_INFO_BY_C) +#include +#endif + +static void cpuid(unsigned int CPUInfo[4], unsigned int InfoType) +{ +#if defined(CPU_INFO_BY_ASM) +#if defined(__i386__) && defined(__PIC__) +/* %ebx is PIC register in 32-bit, so mustn't clobber it. */ + __asm__ __volatile__ ( + "xchg %%ebx, %1\n" + "cpuid\n" + "xchg %%ebx, %1\n": + "=a" (CPUInfo[0]), + "=r" (CPUInfo[1]), + "=c" (CPUInfo[2]), + "=d" (CPUInfo[3]) : + "0" (InfoType) + ); +#else + __asm__ __volatile__ ( + "cpuid": + "=a" (CPUInfo[0]), + "=b" (CPUInfo[1]), + "=c" (CPUInfo[2]), + "=d" (CPUInfo[3]) : + "0" (InfoType) + ); +#endif +#elif defined(CPU_INFO_BY_C) + __get_cpuid(InfoType, &(CPUInfo[0]), &(CPUInfo[1]), &(CPUInfo[2]), &(CPUInfo[3])); +#endif +} + +#endif + +typedef struct CPU_Feature{ + /* SIMD: 128-bit */ + int HW_SSE; + int HW_SSE2; + int HW_SSE41; + /* SIMD: 256-bit */ + int HW_AVX; +} CPU_Feature; + +static void opus_cpu_feature_check(CPU_Feature *cpu_feature) +{ + unsigned int info[4] = {0}; + unsigned int nIds = 0; + + cpuid(info, 0); + nIds = info[0]; + + if (nIds >= 1){ + cpuid(info, 1); + cpu_feature->HW_SSE = (info[3] & (1 << 25)) != 0; + cpu_feature->HW_SSE2 = (info[3] & (1 << 26)) != 0; + cpu_feature->HW_SSE41 = (info[2] & (1 << 19)) != 0; + cpu_feature->HW_AVX = (info[2] & (1 << 28)) != 0; + } + else { + cpu_feature->HW_SSE = 0; + cpu_feature->HW_SSE2 = 0; + cpu_feature->HW_SSE41 = 0; + cpu_feature->HW_AVX = 0; + } +} + +int opus_select_arch(void) +{ + CPU_Feature cpu_feature; + int arch; + + opus_cpu_feature_check(&cpu_feature); + + arch = 0; + if (!cpu_feature.HW_SSE) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_SSE2) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_SSE41) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_AVX) + { + return arch; + } + arch++; + + return arch; +} + +#endif diff --git a/native/codec/libraries/opus/celt/x86/x86cpu.h b/native/codec/libraries/opus/celt/x86/x86cpu.h new file mode 100644 index 0000000..1e2bf17 --- /dev/null +++ b/native/codec/libraries/opus/celt/x86/x86cpu.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(X86CPU_H) +# define X86CPU_H + +# if defined(OPUS_X86_MAY_HAVE_SSE) +# define MAY_HAVE_SSE(name) name ## _sse +# else +# define MAY_HAVE_SSE(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_SSE2) +# define MAY_HAVE_SSE2(name) name ## _sse2 +# else +# define MAY_HAVE_SSE2(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_SSE4_1) +# define MAY_HAVE_SSE4_1(name) name ## _sse4_1 +# else +# define MAY_HAVE_SSE4_1(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_AVX) +# define MAY_HAVE_AVX(name) name ## _avx +# else +# define MAY_HAVE_AVX(name) name ## _c +# endif + +# if defined(OPUS_HAVE_RTCD) +int opus_select_arch(void); +# endif + +/*gcc appears to emit MOVDQA's to load the argument of an _mm_cvtepi8_epi32() + or _mm_cvtepi16_epi32() when optimizations are disabled, even though the + actual PMOVSXWD instruction takes an m32 or m64. Unlike a normal memory + reference, these require 16-byte alignment and load a full 16 bytes (instead + of 4 or 8), possibly reading out of bounds. + + We can insert an explicit MOVD or MOVQ using _mm_cvtsi32_si128() or + _mm_loadl_epi64(), which should have the same semantics as an m32 or m64 + reference in the PMOVSXWD instruction itself, but gcc is not smart enough to + optimize this out when optimizations ARE enabled. + + Clang, in contrast, requires us to do this always for _mm_cvtepi8_epi32 + (which is fair, since technically the compiler is always allowed to do the + dereference before invoking the function implementing the intrinsic). + However, it is smart enough to eliminate the extra MOVD instruction. + For _mm_cvtepi16_epi32, it does the right thing, though does *not* optimize out + the extra MOVQ if it's specified explicitly */ + +# if defined(__clang__) || !defined(__OPTIMIZE__) +# define OP_CVTEPI8_EPI32_M32(x) \ + (_mm_cvtepi8_epi32(_mm_cvtsi32_si128(*(int *)(x)))) +# else +# define OP_CVTEPI8_EPI32_M32(x) \ + (_mm_cvtepi8_epi32(*(__m128i *)(x))) +#endif + +/* similar reasoning about the instruction sequence as in the 32-bit macro above, + */ +# if defined(__clang__) || !defined(__OPTIMIZE__) +# define OP_CVTEPI16_EPI32_M64(x) \ + (_mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i *)(x)))) +# else +# define OP_CVTEPI16_EPI32_M64(x) \ + (_mm_cvtepi16_epi32(*(__m128i *)(x))) +# endif + +#endif diff --git a/native/codec/libraries/opus/celt_headers.mk b/native/codec/libraries/opus/celt_headers.mk new file mode 100644 index 0000000..706185d --- /dev/null +++ b/native/codec/libraries/opus/celt_headers.mk @@ -0,0 +1,53 @@ +CELT_HEAD = \ +celt/arch.h \ +celt/bands.h \ +celt/celt.h \ +celt/cpu_support.h \ +include/opus_types.h \ +include/opus_defines.h \ +include/opus_custom.h \ +celt/cwrs.h \ +celt/ecintrin.h \ +celt/entcode.h \ +celt/entdec.h \ +celt/entenc.h \ +celt/fixed_debug.h \ +celt/fixed_generic.h \ +celt/float_cast.h \ +celt/_kiss_fft_guts.h \ +celt/kiss_fft.h \ +celt/laplace.h \ +celt/mathops.h \ +celt/mdct.h \ +celt/mfrngcod.h \ +celt/modes.h \ +celt/os_support.h \ +celt/pitch.h \ +celt/celt_lpc.h \ +celt/x86/celt_lpc_sse.h \ +celt/quant_bands.h \ +celt/rate.h \ +celt/stack_alloc.h \ +celt/vq.h \ +celt/static_modes_float.h \ +celt/static_modes_fixed.h \ +celt/static_modes_float_arm_ne10.h \ +celt/static_modes_fixed_arm_ne10.h \ +celt/arm/armcpu.h \ +celt/arm/fixed_armv4.h \ +celt/arm/fixed_armv5e.h \ +celt/arm/fixed_arm64.h \ +celt/arm/kiss_fft_armv4.h \ +celt/arm/kiss_fft_armv5e.h \ +celt/arm/pitch_arm.h \ +celt/arm/fft_arm.h \ +celt/arm/mdct_arm.h \ +celt/mips/celt_mipsr1.h \ +celt/mips/fixed_generic_mipsr1.h \ +celt/mips/kiss_fft_mipsr1.h \ +celt/mips/mdct_mipsr1.h \ +celt/mips/pitch_mipsr1.h \ +celt/mips/vq_mipsr1.h \ +celt/x86/pitch_sse.h \ +celt/x86/vq_sse.h \ +celt/x86/x86cpu.h diff --git a/native/codec/libraries/opus/celt_sources.mk b/native/codec/libraries/opus/celt_sources.mk new file mode 100644 index 0000000..c9dab06 --- /dev/null +++ b/native/codec/libraries/opus/celt_sources.mk @@ -0,0 +1,50 @@ +CELT_SOURCES = \ +celt/bands.c \ +celt/celt.c \ +celt/celt_encoder.c \ +celt/celt_decoder.c \ +celt/cwrs.c \ +celt/entcode.c \ +celt/entdec.c \ +celt/entenc.c \ +celt/kiss_fft.c \ +celt/laplace.c \ +celt/mathops.c \ +celt/mdct.c \ +celt/modes.c \ +celt/pitch.c \ +celt/celt_lpc.c \ +celt/quant_bands.c \ +celt/rate.c \ +celt/vq.c + +CELT_SOURCES_SSE = \ +celt/x86/x86cpu.c \ +celt/x86/x86_celt_map.c \ +celt/x86/pitch_sse.c + +CELT_SOURCES_SSE2 = \ +celt/x86/pitch_sse2.c \ +celt/x86/vq_sse2.c + +CELT_SOURCES_SSE4_1 = \ +celt/x86/celt_lpc_sse4_1.c \ +celt/x86/pitch_sse4_1.c + +CELT_SOURCES_ARM = \ +celt/arm/armcpu.c \ +celt/arm/arm_celt_map.c + +CELT_SOURCES_ARM_ASM = \ +celt/arm/celt_pitch_xcorr_arm.s + +CELT_AM_SOURCES_ARM_ASM = \ +celt/arm/armopts.s.in + +CELT_SOURCES_ARM_NEON_INTR = \ +celt/arm/celt_neon_intr.c \ +celt/arm/pitch_neon_intr.c + +CELT_SOURCES_ARM_NE10 = \ +celt/arm/celt_fft_ne10.c \ +celt/arm/celt_mdct_ne10.c diff --git a/native/codec/libraries/opus/config.h.cmake.in b/native/codec/libraries/opus/config.h.cmake.in new file mode 100644 index 0000000..5550842 --- /dev/null +++ b/native/codec/libraries/opus/config.h.cmake.in @@ -0,0 +1 @@ +#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" \ No newline at end of file diff --git a/native/codec/libraries/opus/configure.ac b/native/codec/libraries/opus/configure.ac new file mode 100644 index 0000000..18ece29 --- /dev/null +++ b/native/codec/libraries/opus/configure.ac @@ -0,0 +1,933 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- + +dnl The package_version file will be automatically synced to the git revision +dnl by the update_version script when configured in the repository, but will +dnl remain constant in tarball releases unless it is manually edited. +m4_define([CURRENT_VERSION], + m4_esyscmd([ ./update_version 2>/dev/null || true + if test -e package_version; then + . ./package_version + printf "$PACKAGE_VERSION" + else + printf "unknown" + fi ])) + +AC_INIT([opus],[CURRENT_VERSION],[opus@xiph.org]) + +AC_CONFIG_SRCDIR(src/opus_encoder.c) +AC_CONFIG_MACRO_DIR([m4]) + +dnl enable silent rules on automake 1.11 and later +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +# For libtool. +dnl Please update these for releases. +OPUS_LT_CURRENT=8 +OPUS_LT_REVISION=0 +OPUS_LT_AGE=8 + +AC_SUBST(OPUS_LT_CURRENT) +AC_SUBST(OPUS_LT_REVISION) +AC_SUBST(OPUS_LT_AGE) + +AM_INIT_AUTOMAKE([no-define]) +AM_MAINTAINER_MODE([enable]) + +AC_CANONICAL_HOST +AC_MINGW32 +AM_PROG_LIBTOOL +AM_PROG_CC_C_O + +AC_PROG_CC_C99 +AC_C_CONST +AC_C_INLINE + +AM_PROG_AS + +AC_DEFINE([OPUS_BUILD], [], [This is a build of OPUS]) + +#Use a hacked up version of autoconf's AC_C_RESTRICT because it's not +#strong enough a test to detect old buggy versions of GCC (e.g. 2.95.3) +#Note: Both this and the test for variable-size arrays below are also +# done by AC_PROG_CC_C99, but not thoroughly enough apparently. +AC_CACHE_CHECK([for C/C++ restrict keyword], ac_cv_c_restrict, + [ac_cv_c_restrict=no + # The order here caters to the fact that C++ does not require restrict. + for ac_kw in __restrict __restrict__ _Restrict restrict; do + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[typedef int * int_ptr; + int foo (int_ptr $ac_kw ip, int * $ac_kw baz[]) { + return ip[0]; + }]], + [[int s[1]; + int * $ac_kw t = s; + t[0] = 0; + return foo(t, (void *)0)]])], + [ac_cv_c_restrict=$ac_kw]) + test "$ac_cv_c_restrict" != no && break + done + ]) + +AH_VERBATIM([restrict], +[/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#undef restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif]) + +case $ac_cv_c_restrict in + restrict) ;; + no) AC_DEFINE([restrict], []) ;; + *) AC_DEFINE_UNQUOTED([restrict], [$ac_cv_c_restrict]) ;; +esac + +AC_MSG_CHECKING(for C99 variable-size arrays) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [[static int x; char a[++x]; a[sizeof a - 1] = 0; int N; return a[0];]])], + [ has_var_arrays=yes + use_alloca="no (using var arrays)" + AC_DEFINE([VAR_ARRAYS], [1], [Use C99 variable-size arrays]) + ],[ + has_var_arrays=no + ]) +AC_MSG_RESULT([$has_var_arrays]) + +AS_IF([test "$has_var_arrays" = "no"], + [ + AC_CHECK_HEADERS([alloca.h]) + AC_MSG_CHECKING(for alloca) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int foo=10; int *array = alloca(foo);]])], + [ use_alloca=yes; + AC_DEFINE([USE_ALLOCA], [], [Make use of alloca]) + ],[ + use_alloca=no + ]) + AC_MSG_RESULT([$use_alloca]) + ]) + +LT_LIB_M + +AC_ARG_ENABLE([fixed-point], + [AS_HELP_STRING([--enable-fixed-point], + [compile without floating point (for machines without a fast enough FPU)])],, + [enable_fixed_point=no]) + +AS_IF([test "$enable_fixed_point" = "yes"],[ + enable_float="no" + AC_DEFINE([FIXED_POINT], [1], [Compile as fixed-point (for machines without a fast enough FPU)]) + PC_BUILD="fixed-point" +],[ + enable_float="yes"; + PC_BUILD="floating-point" +]) + +AM_CONDITIONAL([FIXED_POINT], [test "$enable_fixed_point" = "yes"]) + +AC_ARG_ENABLE([fixed-point-debug], + [AS_HELP_STRING([--enable-fixed-point-debug], [debug fixed-point implementation])],, + [enable_fixed_point_debug=no]) + +AS_IF([test "$enable_fixed_point_debug" = "yes"],[ + AC_DEFINE([FIXED_DEBUG], [1], [Debug fixed-point implementation]) +]) + +AC_ARG_ENABLE([float_api], + [AS_HELP_STRING([--disable-float-api], + [compile without the floating point API (for machines with no float library)])],, + [enable_float_api=yes]) + +AM_CONDITIONAL([DISABLE_FLOAT_API], [test "$enable_float_api" = "no"]) + +AS_IF([test "$enable_float_api" = "no"],[ + AC_DEFINE([DISABLE_FLOAT_API], [1], [Do not build the float API]) +]) + +AC_ARG_ENABLE([custom-modes], + [AS_HELP_STRING([--enable-custom-modes], [enable non-Opus modes, e.g. 44.1 kHz & 2^n frames])],, + [enable_custom_modes=no]) + +AS_IF([test "$enable_custom_modes" = "yes"],[ + AC_DEFINE([CUSTOM_MODES], [1], [Custom modes]) + PC_BUILD="$PC_BUILD, custom modes" +]) + +AM_CONDITIONAL([CUSTOM_MODES], [test "$enable_custom_modes" = "yes"]) + +has_float_approx=no +#case "$host_cpu" in +#i[[3456]]86 | x86_64 | powerpc64 | powerpc32 | ia64) +# has_float_approx=yes +# ;; +#esac + +AC_ARG_ENABLE([float-approx], + [AS_HELP_STRING([--enable-float-approx], [enable fast approximations for floating point])], + [if test "$enable_float_approx" = "yes"; then + AC_WARN([Floating point approximations are not supported on all platforms.]) + fi + ], + [enable_float_approx=$has_float_approx]) + +AS_IF([test "$enable_float_approx" = "yes"],[ + AC_DEFINE([FLOAT_APPROX], [1], [Float approximations]) +]) + +AC_ARG_ENABLE([asm], + [AS_HELP_STRING([--disable-asm], [Disable assembly optimizations])],, + [enable_asm=yes]) + +AC_ARG_ENABLE([rtcd], + [AS_HELP_STRING([--disable-rtcd], [Disable run-time CPU capabilities detection])],, + [enable_rtcd=yes]) + +AC_ARG_ENABLE([intrinsics], + [AS_HELP_STRING([--disable-intrinsics], [Disable intrinsics optimizations])],, + [enable_intrinsics=yes]) + +rtcd_support=no +cpu_arm=no + +AS_IF([test x"${enable_asm}" = x"yes"],[ + inline_optimization="No inline ASM for your platform, please send patches" + case $host_cpu in + arm*) + dnl Currently we only have asm for fixed-point + AS_IF([test "$enable_float" != "yes"],[ + cpu_arm=yes + AC_DEFINE([OPUS_ARM_ASM], [], [Make use of ARM asm optimization]) + AS_GCC_INLINE_ASSEMBLY( + [inline_optimization="ARM"], + [inline_optimization="disabled"] + ) + AS_ASM_ARM_EDSP([OPUS_ARM_INLINE_EDSP=1],[OPUS_ARM_INLINE_EDSP=0]) + AS_ASM_ARM_MEDIA([OPUS_ARM_INLINE_MEDIA=1], + [OPUS_ARM_INLINE_MEDIA=0]) + AS_ASM_ARM_NEON([OPUS_ARM_INLINE_NEON=1],[OPUS_ARM_INLINE_NEON=0]) + AS_IF([test x"$inline_optimization" = x"ARM"],[ + AM_CONDITIONAL([OPUS_ARM_INLINE_ASM],[true]) + AC_DEFINE([OPUS_ARM_INLINE_ASM], 1, + [Use generic ARMv4 inline asm optimizations]) + AS_IF([test x"$OPUS_ARM_INLINE_EDSP" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_EDSP], [1], + [Use ARMv5E inline asm optimizations]) + inline_optimization="$inline_optimization (EDSP)" + ]) + AS_IF([test x"$OPUS_ARM_INLINE_MEDIA" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_MEDIA], [1], + [Use ARMv6 inline asm optimizations]) + inline_optimization="$inline_optimization (Media)" + ]) + AS_IF([test x"$OPUS_ARM_INLINE_NEON" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_NEON], 1, + [Use ARM NEON inline asm optimizations]) + inline_optimization="$inline_optimization (NEON)" + ]) + ]) + dnl We need Perl to translate RVCT-syntax asm to gas syntax. + AC_CHECK_PROG([HAVE_PERL], perl, yes, no) + AS_IF([test x"$HAVE_PERL" = x"yes"],[ + AM_CONDITIONAL([OPUS_ARM_EXTERNAL_ASM],[true]) + asm_optimization="ARM" + AS_IF([test x"$OPUS_ARM_INLINE_EDSP" = x"1"], [ + OPUS_ARM_PRESUME_EDSP=1 + OPUS_ARM_MAY_HAVE_EDSP=1 + ], + [ + OPUS_ARM_PRESUME_EDSP=0 + OPUS_ARM_MAY_HAVE_EDSP=0 + ]) + AS_IF([test x"$OPUS_ARM_INLINE_MEDIA" = x"1"], [ + OPUS_ARM_PRESUME_MEDIA=1 + OPUS_ARM_MAY_HAVE_MEDIA=1 + ], + [ + OPUS_ARM_PRESUME_MEDIA=0 + OPUS_ARM_MAY_HAVE_MEDIA=0 + ]) + AS_IF([test x"$OPUS_ARM_INLINE_NEON" = x"1"], [ + OPUS_ARM_PRESUME_NEON=1 + OPUS_ARM_MAY_HAVE_NEON=1 + ], + [ + OPUS_ARM_PRESUME_NEON=0 + OPUS_ARM_MAY_HAVE_NEON=0 + ]) + AS_IF([test x"$enable_rtcd" = x"yes"],[ + AS_IF([test x"$OPUS_ARM_MAY_HAVE_EDSP" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable armv5e EDSP instructions...]) + AS_ASM_ARM_EDSP_FORCE([OPUS_ARM_MAY_HAVE_EDSP=1]) + ]) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_MEDIA" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable ARMv6 media instructions...]) + AS_ASM_ARM_MEDIA_FORCE([OPUS_ARM_MAY_HAVE_MEDIA=1]) + ]) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable NEON instructions...]) + AS_ASM_ARM_NEON_FORCE([OPUS_ARM_MAY_HAVE_NEON=1]) + ]) + ]) + rtcd_support= + AS_IF([test x"$OPUS_ARM_MAY_HAVE_EDSP" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_EDSP, 1, + [Define if assembler supports EDSP instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_EDSP" = x"1"],[ + AC_DEFINE(OPUS_ARM_PRESUME_EDSP, 1, + [Define if binary requires EDSP instruction support]) + asm_optimization="$asm_optimization (EDSP)" + ], + [rtcd_support="$rtcd_support (EDSP)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_EDSP) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_MEDIA" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_MEDIA, 1, + [Define if assembler supports ARMv6 media instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_MEDIA" = x"1"],[ + AC_DEFINE(OPUS_ARM_PRESUME_MEDIA, 1, + [Define if binary requires ARMv6 media instruction support]) + asm_optimization="$asm_optimization (Media)" + ], + [rtcd_support="$rtcd_support (Media)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_MEDIA) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_NEON, 1, + [Define if compiler supports NEON instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_NEON" = x"1"], [ + AC_DEFINE(OPUS_ARM_PRESUME_NEON, 1, + [Define if binary requires NEON instruction support]) + asm_optimization="$asm_optimization (NEON)" + ], + [rtcd_support="$rtcd_support (NEON)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_NEON) + dnl Make sure turning on RTCD gets us at least one + dnl instruction set. + AS_IF([test x"$rtcd_support" != x""], + [rtcd_support=ARM"$rtcd_support"], + [rtcd_support="no"] + ) + AC_MSG_CHECKING([for apple style tools]) + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([ +#ifndef __APPLE__ +#error 1 +#endif],[])], + [AC_MSG_RESULT([yes]); ARM2GNU_PARAMS="--apple"], + [AC_MSG_RESULT([no]); ARM2GNU_PARAMS=""]) + AC_SUBST(ARM2GNU_PARAMS) + ], + [ + AC_MSG_WARN( + [*** ARM assembly requires perl -- disabling optimizations]) + asm_optimization="(missing perl dependency for ARM)" + ]) + ]) + ;; + esac +],[ + inline_optimization="disabled" + asm_optimization="disabled" +]) + +AM_CONDITIONAL([OPUS_ARM_INLINE_ASM], + [test x"${inline_optimization%% *}" = x"ARM"]) +AM_CONDITIONAL([OPUS_ARM_EXTERNAL_ASM], + [test x"${asm_optimization%% *}" = x"ARM"]) + +AM_CONDITIONAL([HAVE_SSE], [false]) +AM_CONDITIONAL([HAVE_SSE2], [false]) +AM_CONDITIONAL([HAVE_SSE4_1], [false]) +AM_CONDITIONAL([HAVE_AVX], [false]) + +m4_define([DEFAULT_X86_SSE_CFLAGS], [-msse]) +m4_define([DEFAULT_X86_SSE2_CFLAGS], [-msse2]) +m4_define([DEFAULT_X86_SSE4_1_CFLAGS], [-msse4.1]) +m4_define([DEFAULT_X86_AVX_CFLAGS], [-mavx]) +m4_define([DEFAULT_ARM_NEON_INTR_CFLAGS], [-mfpu=neon]) +# With GCC on ARM32 softfp architectures (e.g. Android, or older Ubuntu) you need to specify +# -mfloat-abi=softfp for -mfpu=neon to work. However, on ARM32 hardfp architectures (e.g. newer Ubuntu), +# this option will break things. + +# As a heuristic, if host matches arm*eabi* but not arm*hf*, it's probably soft-float. +m4_define([DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS], [-mfpu=neon -mfloat-abi=softfp]) + +AS_CASE([$host], + [arm*hf*], [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_INTR_CFLAGS")], + [arm*eabi*], [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS")], + [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_INTR_CFLAGS")]) + +AC_ARG_VAR([X86_SSE_CFLAGS], [C compiler flags to compile SSE intrinsics @<:@default=]DEFAULT_X86_SSE_CFLAGS[@:>@]) +AC_ARG_VAR([X86_SSE2_CFLAGS], [C compiler flags to compile SSE2 intrinsics @<:@default=]DEFAULT_X86_SSE2_CFLAGS[@:>@]) +AC_ARG_VAR([X86_SSE4_1_CFLAGS], [C compiler flags to compile SSE4.1 intrinsics @<:@default=]DEFAULT_X86_SSE4_1_CFLAGS[@:>@]) +AC_ARG_VAR([X86_AVX_CFLAGS], [C compiler flags to compile AVX intrinsics @<:@default=]DEFAULT_X86_AVX_CFLAGS[@:>@]) +AC_ARG_VAR([ARM_NEON_INTR_CFLAGS], [C compiler flags to compile ARM NEON intrinsics @<:@default=]DEFAULT_ARM_NEON_INTR_CFLAGS / DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS[@:>@]) + +AS_VAR_SET_IF([X86_SSE_CFLAGS], [], [AS_VAR_SET([X86_SSE_CFLAGS], "DEFAULT_X86_SSE_CFLAGS")]) +AS_VAR_SET_IF([X86_SSE2_CFLAGS], [], [AS_VAR_SET([X86_SSE2_CFLAGS], "DEFAULT_X86_SSE2_CFLAGS")]) +AS_VAR_SET_IF([X86_SSE4_1_CFLAGS], [], [AS_VAR_SET([X86_SSE4_1_CFLAGS], "DEFAULT_X86_SSE4_1_CFLAGS")]) +AS_VAR_SET_IF([X86_AVX_CFLAGS], [], [AS_VAR_SET([X86_AVX_CFLAGS], "DEFAULT_X86_AVX_CFLAGS")]) +AS_VAR_SET_IF([ARM_NEON_INTR_CFLAGS], [], [AS_VAR_SET([ARM_NEON_INTR_CFLAGS], ["$RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS"])]) + +AC_DEFUN([OPUS_PATH_NE10], + [ + AC_ARG_WITH(NE10, + AC_HELP_STRING([--with-NE10=PFX],[Prefix where libNE10 is installed (optional)]), + NE10_prefix="$withval", NE10_prefix="") + AC_ARG_WITH(NE10-libraries, + AC_HELP_STRING([--with-NE10-libraries=DIR], + [Directory where libNE10 library is installed (optional)]), + NE10_libraries="$withval", NE10_libraries="") + AC_ARG_WITH(NE10-includes, + AC_HELP_STRING([--with-NE10-includes=DIR], + [Directory where libNE10 header files are installed (optional)]), + NE10_includes="$withval", NE10_includes="") + + if test "x$NE10_libraries" != "x" ; then + NE10_LIBS="-L$NE10_libraries" + elif test "x$NE10_prefix" = "xno" || test "x$NE10_prefix" = "xyes" ; then + NE10_LIBS="" + elif test "x$NE10_prefix" != "x" ; then + NE10_LIBS="-L$NE10_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + NE10_LIBS="-L$prefix/lib" + fi + + if test "x$NE10_prefix" != "xno" ; then + NE10_LIBS="$NE10_LIBS -lNE10" + fi + + if test "x$NE10_includes" != "x" ; then + NE10_CFLAGS="-I$NE10_includes" + elif test "x$NE10_prefix" = "xno" || test "x$NE10_prefix" = "xyes" ; then + NE10_CFLAGS="" + elif test "x$NE10_prefix" != "x" ; then + NE10_CFLAGS="-I$NE10_prefix/include" + elif test "x$prefix" != "xNONE"; then + NE10_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for NE10) + save_CFLAGS="$CFLAGS"; CFLAGS="$CFLAGS $NE10_CFLAGS" + save_LIBS="$LIBS"; LIBS="$LIBS $NE10_LIBS $LIBM" + AC_LINK_IFELSE( + [ + AC_LANG_PROGRAM( + [[#include + ]], + [[ + ne10_fft_cfg_float32_t cfg; + cfg = ne10_fft_alloc_c2c_float32_neon(480); + ]] + ) + ],[ + HAVE_ARM_NE10=1 + AC_MSG_RESULT([yes]) + ],[ + HAVE_ARM_NE10=0 + AC_MSG_RESULT([no]) + NE10_CFLAGS="" + NE10_LIBS="" + ] + ) + CFLAGS="$save_CFLAGS"; LIBS="$save_LIBS" + #Now we know if libNE10 is installed or not + AS_IF([test x"$HAVE_ARM_NE10" = x"1"], + [ + AC_DEFINE([HAVE_ARM_NE10], 1, [NE10 library is installed on host. Make sure it is on target!]) + AC_SUBST(HAVE_ARM_NE10) + AC_SUBST(NE10_CFLAGS) + AC_SUBST(NE10_LIBS) + ] + ) + ] +) + +AS_IF([test x"$enable_intrinsics" = x"yes"],[ + intrinsics_support="" + AS_CASE([$host_cpu], + [arm*|aarch64*], + [ + cpu_arm=yes + OPUS_CHECK_INTRINSICS( + [ARM Neon], + [$ARM_NEON_INTR_CFLAGS], + [OPUS_ARM_MAY_HAVE_NEON_INTR], + [OPUS_ARM_PRESUME_NEON_INTR], + [[#include + ]], + [[ + static float32x4_t A0, A1, SUMM; + SUMM = vmlaq_f32(SUMM, A0, A1); + return (int)vgetq_lane_f32(SUMM, 0); + ]] + ) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1" && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [ + OPUS_ARM_NEON_INTR_CFLAGS="$ARM_NEON_INTR_CFLAGS" + AC_SUBST([OPUS_ARM_NEON_INTR_CFLAGS]) + ] + ) + + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1"], + [ + AC_DEFINE([OPUS_ARM_MAY_HAVE_NEON_INTR], 1, [Compiler supports ARMv7/Aarch64 Neon Intrinsics]) + intrinsics_support="$intrinsics_support (NEON)" + + AS_IF([test x"$enable_rtcd" != x"no" && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [AS_IF([test x"$rtcd_support" = x"no"], + [rtcd_support="ARM (NEON Intrinsics)"], + [rtcd_support="$rtcd_support (NEON Intrinsics)"])]) + + AS_IF([test x"$OPUS_ARM_PRESUME_NEON_INTR" = x"1"], + [AC_DEFINE([OPUS_ARM_PRESUME_NEON_INTR], 1, [Define if binary requires NEON intrinsics support])]) + + OPUS_PATH_NE10() + AS_IF([test x"$NE10_LIBS" != x""], + [ + intrinsics_support="$intrinsics_support (NE10)" + AS_IF([test x"enable_rtcd" != x"" \ + && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [rtcd_support="$rtcd_support (NE10)"]) + ]) + + OPUS_CHECK_INTRINSICS( + [Aarch64 Neon], + [$ARM_NEON_INTR_CFLAGS], + [OPUS_ARM_MAY_HAVE_AARCH64_NEON_INTR], + [OPUS_ARM_PRESUME_AARCH64_NEON_INTR], + [[#include + ]], + [[ + static int32_t IN; + static int16_t OUT; + OUT = vqmovns_s32(IN); + ]] + ) + + AS_IF([test x"$OPUS_ARM_PRESUME_AARCH64_NEON_INTR" = x"1"], + [ + AC_DEFINE([OPUS_ARM_PRESUME_AARCH64_NEON_INTR], 1, [Define if binary requires Aarch64 Neon Intrinsics]) + intrinsics_support="$intrinsics_support (NEON [Aarch64])" + ]) + + AS_IF([test x"$intrinsics_support" = x""], + [intrinsics_support=no], + [intrinsics_support="ARM$intrinsics_support"]) + ], + [ + AC_MSG_WARN([Compiler does not support ARM intrinsics]) + intrinsics_support=no + ]) + ], + [i?86|x86_64], + [ + OPUS_CHECK_INTRINSICS( + [SSE], + [$X86_SSE_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE], + [OPUS_X86_PRESUME_SSE], + [[#include + #include + ]], + [[ + __m128 mtest; + mtest = _mm_set1_ps((float)time(NULL)); + mtest = _mm_mul_ps(mtest, mtest); + return _mm_cvtss_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE" = x"1" && test x"$OPUS_X86_PRESUME_SSE" != x"1"], + [ + OPUS_X86_SSE_CFLAGS="$X86_SSE_CFLAGS" + AC_SUBST([OPUS_X86_SSE_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [SSE2], + [$X86_SSE2_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE2], + [OPUS_X86_PRESUME_SSE2], + [[#include + #include + ]], + [[ + __m128i mtest; + mtest = _mm_set1_epi32((int)time(NULL)); + mtest = _mm_mul_epu32(mtest, mtest); + return _mm_cvtsi128_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1" && test x"$OPUS_X86_PRESUME_SSE2" != x"1"], + [ + OPUS_X86_SSE2_CFLAGS="$X86_SSE2_CFLAGS" + AC_SUBST([OPUS_X86_SSE2_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [SSE4.1], + [$X86_SSE4_1_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE4_1], + [OPUS_X86_PRESUME_SSE4_1], + [[#include + #include + ]], + [[ + __m128i mtest; + mtest = _mm_set1_epi32((int)time(NULL)); + mtest = _mm_mul_epi32(mtest, mtest); + return _mm_cvtsi128_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1" && test x"$OPUS_X86_PRESUME_SSE4_1" != x"1"], + [ + OPUS_X86_SSE4_1_CFLAGS="$X86_SSE4_1_CFLAGS" + AC_SUBST([OPUS_X86_SSE4_1_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [AVX], + [$X86_AVX_CFLAGS], + [OPUS_X86_MAY_HAVE_AVX], + [OPUS_X86_PRESUME_AVX], + [[#include + #include + ]], + [[ + __m256 mtest; + mtest = _mm256_set1_ps((float)time(NULL)); + mtest = _mm256_addsub_ps(mtest, mtest); + return _mm_cvtss_si32(_mm256_extractf128_ps(mtest, 0)); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_AVX" = x"1" && test x"$OPUS_X86_PRESUME_AVX" != x"1"], + [ + OPUS_X86_AVX_CFLAGS="$X86_AVX_CFLAGS" + AC_SUBST([OPUS_X86_AVX_CFLAGS]) + ] + ) + AS_IF([test x"$rtcd_support" = x"no"], [rtcd_support=""]) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE], 1, [Compiler supports X86 SSE Intrinsics]) + intrinsics_support="$intrinsics_support SSE" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE], 1, [Define if binary requires SSE intrinsics support])], + [rtcd_support="$rtcd_support SSE"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE intrinsics]) + ]) + + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE2], 1, [Compiler supports X86 SSE2 Intrinsics]) + intrinsics_support="$intrinsics_support SSE2" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE2" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE2], 1, [Define if binary requires SSE2 intrinsics support])], + [rtcd_support="$rtcd_support SSE2"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE2 intrinsics]) + ]) + + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE4_1], 1, [Compiler supports X86 SSE4.1 Intrinsics]) + intrinsics_support="$intrinsics_support SSE4.1" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE4_1" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE4_1], 1, [Define if binary requires SSE4.1 intrinsics support])], + [rtcd_support="$rtcd_support SSE4.1"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE4.1 intrinsics]) + ]) + AS_IF([test x"$OPUS_X86_MAY_HAVE_AVX" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_AVX], 1, [Compiler supports X86 AVX Intrinsics]) + intrinsics_support="$intrinsics_support AVX" + + AS_IF([test x"$OPUS_X86_PRESUME_AVX" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_AVX], 1, [Define if binary requires AVX intrinsics support])], + [rtcd_support="$rtcd_support AVX"]) + ], + [ + AC_MSG_WARN([Compiler does not support AVX intrinsics]) + ]) + + AS_IF([test x"$intrinsics_support" = x""], + [intrinsics_support=no], + [intrinsics_support="x86$intrinsics_support"] + ) + AS_IF([test x"$rtcd_support" = x""], + [rtcd_support=no], + [rtcd_support="x86$rtcd_support"], + ) + + AS_IF([test x"$enable_rtcd" = x"yes" && test x"$rtcd_support" != x""],[ + get_cpuid_by_asm="no" + AC_MSG_CHECKING([How to get X86 CPU Info]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]],[[ + unsigned int CPUInfo0; + unsigned int CPUInfo1; + unsigned int CPUInfo2; + unsigned int CPUInfo3; + unsigned int InfoType; + __asm__ __volatile__ ( + "cpuid": + "=a" (CPUInfo0), + "=b" (CPUInfo1), + "=c" (CPUInfo2), + "=d" (CPUInfo3) : + "a" (InfoType), "c" (0) + ); + ]])], + [get_cpuid_by_asm="yes" + AC_MSG_RESULT([Inline Assembly]) + AC_DEFINE([CPU_INFO_BY_ASM], [1], [Get CPU Info by asm method])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]],[[ + unsigned int CPUInfo0; + unsigned int CPUInfo1; + unsigned int CPUInfo2; + unsigned int CPUInfo3; + unsigned int InfoType; + __get_cpuid(InfoType, &CPUInfo0, &CPUInfo1, &CPUInfo2, &CPUInfo3); + ]])], + [AC_MSG_RESULT([C method]) + AC_DEFINE([CPU_INFO_BY_C], [1], [Get CPU Info by c method])], + [AC_MSG_ERROR([no supported Get CPU Info method, please disable run-time CPU capabilities detection or intrinsics])])])]) + ], + [ + AC_MSG_WARN([No intrinsics support for your architecture]) + intrinsics_support="no" + ]) +], +[ + intrinsics_support="no" +]) + +AM_CONDITIONAL([CPU_ARM], [test "$cpu_arm" = "yes"]) +AM_CONDITIONAL([HAVE_ARM_NEON_INTR], + [test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1"]) +AM_CONDITIONAL([HAVE_ARM_NE10], + [test x"$HAVE_ARM_NE10" = x"1"]) +AM_CONDITIONAL([HAVE_SSE], + [test x"$OPUS_X86_MAY_HAVE_SSE" = x"1"]) +AM_CONDITIONAL([HAVE_SSE2], + [test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1"]) +AM_CONDITIONAL([HAVE_SSE4_1], + [test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1"]) +AM_CONDITIONAL([HAVE_AVX], + [test x"$OPUS_X86_MAY_HAVE_AVX" = x"1"]) + +AS_IF([test x"$enable_rtcd" = x"yes"],[ + AS_IF([test x"$rtcd_support" != x"no"],[ + AC_DEFINE([OPUS_HAVE_RTCD], [1], + [Use run-time CPU capabilities detection]) + OPUS_HAVE_RTCD=1 + AC_SUBST(OPUS_HAVE_RTCD) + ]) +],[ + rtcd_support="disabled" +]) + +AC_ARG_ENABLE([assertions], + [AS_HELP_STRING([--enable-assertions],[enable additional software error checking])],, + [enable_assertions=no]) + +AS_IF([test "$enable_assertions" = "yes"], [ + AC_DEFINE([ENABLE_ASSERTIONS], [1], [Assertions]) +]) + +AC_ARG_ENABLE([hardening], + [AS_HELP_STRING([--disable-hardening],[disable run-time checks that are cheap and safe for use in production])],, + [enable_hardening=yes]) + +AS_IF([test "$enable_hardening" = "yes"], [ + AC_DEFINE([ENABLE_HARDENING], [1], [Hardening]) +]) + +AC_ARG_ENABLE([fuzzing], + [AS_HELP_STRING([--enable-fuzzing],[causes the encoder to make random decisions (do not use in production)])],, + [enable_fuzzing=no]) + +AS_IF([test "$enable_fuzzing" = "yes"], [ + AC_DEFINE([FUZZING], [1], [Fuzzing]) +]) + +AC_ARG_ENABLE([check-asm], + [AS_HELP_STRING([--enable-check-asm], + [enable bit-exactness checks between optimized and c implementations])],, + [enable_check_asm=no]) + +AS_IF([test "$enable_check_asm" = "yes"], [ + AC_DEFINE([OPUS_CHECK_ASM], [1], [Run bit-exactness checks between optimized and c implementations]) +]) + +AC_ARG_ENABLE([doc], + [AS_HELP_STRING([--disable-doc], [Do not build API documentation])],, + [enable_doc=yes]) + +AS_IF([test "$enable_doc" = "yes"], [ + AC_CHECK_PROG(HAVE_DOXYGEN, [doxygen], [yes], [no]) + AC_CHECK_PROG(HAVE_DOT, [dot], [yes], [no]) +],[ + HAVE_DOXYGEN=no +]) + +AM_CONDITIONAL([HAVE_DOXYGEN], [test "$HAVE_DOXYGEN" = "yes"]) + +AC_ARG_ENABLE([extra-programs], + [AS_HELP_STRING([--disable-extra-programs], [Do not build extra programs (demo and tests)])],, + [enable_extra_programs=yes]) + +AM_CONDITIONAL([EXTRA_PROGRAMS], [test "$enable_extra_programs" = "yes"]) + + +AC_ARG_ENABLE([rfc8251], + AS_HELP_STRING([--disable-rfc8251], [Disable bitstream fixes from RFC 8251]),, + [enable_rfc8251=yes]) + +AS_IF([test "$enable_rfc8251" = "no"], [ + AC_DEFINE([DISABLE_UPDATE_DRAFT], [1], [Disable bitstream fixes from RFC 8251]) +]) + + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +on_x86=no +case "$host_cpu" in +i[[3456]]86 | x86_64) + on_x86=yes + ;; +esac + +on_windows=no +case $host in +*cygwin*|*mingw*) + on_windows=yes + ;; +esac + +dnl Enable stack-protector-all only on x86 where it's well supported. +dnl on some platforms it causes crashes. Hopefully the OS's default's +dnl include this on platforms that work but have been missed here. +AC_ARG_ENABLE([stack-protector], + [AS_HELP_STRING([--disable-stack-protector],[Disable compiler stack hardening])],, + [ + AS_IF([test "$ac_cv_c_compiler_gnu" = "yes" && test "$on_x86" = "yes" && test "$on_windows" = "no"], + [enable_stack_protector=yes],[enable_stack_protector=no]) + ]) + +AS_IF([test "$enable_stack_protector" = "yes"], + [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fstack-protector-strong" + AC_MSG_CHECKING([if ${CC} supports -fstack-protector-strong]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ + AC_MSG_RESULT([no]) + enable_stack_protector=no + CFLAGS="$saved_CFLAGS" + ]) + ]) + +AS_IF([test x$ac_cv_c_compiler_gnu = xyes], + [AX_ADD_FORTIFY_SOURCE] +) + +CFLAGS="$CFLAGS -W" + +warn_CFLAGS="-Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes" +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $warn_CFLAGS" +AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +saved_LIBS="$LIBS" +LIBS="$LIBS $LIBM" +AC_CHECK_FUNCS([lrintf]) +AC_CHECK_FUNCS([lrint]) +LIBS="$saved_LIBS" + +AC_CHECK_FUNCS([__malloc_hook]) + +AC_SUBST([PC_BUILD]) + +AC_CONFIG_FILES([ + Makefile + opus.pc + opus-uninstalled.pc + celt/arm/armopts.s + doc/Makefile + doc/Doxyfile +]) +AC_CONFIG_HEADERS([config.h]) + +AC_OUTPUT + +AC_MSG_NOTICE([ +------------------------------------------------------------------------ + $PACKAGE_NAME $PACKAGE_VERSION: Automatic configuration OK. + + Compiler support: + + C99 var arrays: ................ ${has_var_arrays} + C99 lrintf: .................... ${ac_cv_func_lrintf} + Use alloca: .................... ${use_alloca} + + General configuration: + + Floating point support: ........ ${enable_float} + Fast float approximations: ..... ${enable_float_approx} + Fixed point debugging: ......... ${enable_fixed_point_debug} + Inline Assembly Optimizations: . ${inline_optimization} + External Assembly Optimizations: ${asm_optimization} + Intrinsics Optimizations: ...... ${intrinsics_support} + Run-time CPU detection: ........ ${rtcd_support} + Custom modes: .................. ${enable_custom_modes} + Assertion checking: ............ ${enable_assertions} + Hardening: ..................... ${enable_hardening} + Fuzzing: ....................... ${enable_fuzzing} + Check ASM: ..................... ${enable_check_asm} + + API documentation: ............. ${enable_doc} + Extra programs: ................ ${enable_extra_programs} +------------------------------------------------------------------------ + + Type "make; make install" to compile and install + Type "make check" to run the test suite +]) + diff --git a/native/codec/libraries/opus/doc/Doxyfile.in b/native/codec/libraries/opus/doc/Doxyfile.in new file mode 100644 index 0000000..36eee0b --- /dev/null +++ b/native/codec/libraries/opus/doc/Doxyfile.in @@ -0,0 +1,335 @@ +# Doxyfile 1.8.10 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +# Only non-default options are included below to improve portability +# between doxygen versions. +# +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Opus + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = @VERSION@ + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Opus audio codec (RFC 6716): API and operations manual" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = @top_srcdir@/include/opus.h \ + @top_srcdir@/include/opus_types.h \ + @top_srcdir@/include/opus_defines.h \ + @top_srcdir@/include/opus_multistream.h \ + @top_srcdir@/include/opus_custom.h + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = @top_srcdir@/doc/header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = @top_srcdir@/doc/footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = @top_srcdir@/doc/customdoxygen.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = @top_srcdir@/doc/opus_logo.svg + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 0 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://www.mathjax.org/mathjax + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = letter + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = OPUS_EXPORT= \ + OPUS_CUSTOM_EXPORT= \ + OPUS_CUSTOM_EXPORT_STATIC= \ + OPUS_WARN_UNUSED_RESULT= \ + OPUS_ARG_NONNULL(_x)= + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. + +# Debian defaults to YES here, while Fedora and Homebrew default to NO. +# So we set this based on whether the graphviz package is available at +# configure time. +# +HAVE_DOT = @HAVE_DOT@ diff --git a/native/codec/libraries/opus/doc/Makefile.am b/native/codec/libraries/opus/doc/Makefile.am new file mode 100644 index 0000000..31fddab --- /dev/null +++ b/native/codec/libraries/opus/doc/Makefile.am @@ -0,0 +1,45 @@ +## Process this file with automake to produce Makefile.in + +DOCINPUTS = $(top_srcdir)/include/opus.h \ + $(top_srcdir)/include/opus_multistream.h \ + $(top_srcdir)/include/opus_defines.h \ + $(top_srcdir)/include/opus_types.h \ + $(top_srcdir)/include/opus_custom.h \ + $(top_srcdir)/doc/header.html \ + $(top_srcdir)/doc/footer.html \ + $(top_srcdir)/doc/customdoxygen.css + +EXTRA_DIST = customdoxygen.css Doxyfile.in footer.html header.html \ + opus_logo.svg trivial_example.c + + +if HAVE_DOXYGEN + +all-local: doxygen-build.stamp + +doxygen-build.stamp: Doxyfile $(DOCINPUTS) + doxygen + touch $@ + +install-data-local: + $(INSTALL) -d $(DESTDIR)$(docdir)/html/search + for f in `find html -type f \! -name "installdox"`; do \ + $(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f; \ + done + + $(INSTALL) -d $(DESTDIR)$(mandir)/man3 + cd man && find man3 -type f -name opus_*.3 \ + -exec $(INSTALL_DATA) \{} $(DESTDIR)$(mandir)/man3 \; + +clean-local: + $(RM) -r html + $(RM) -r latex + $(RM) -r man + $(RM) doxygen-build.stamp + $(RM) doxygen_sqlite3.db + +uninstall-local: + $(RM) -r $(DESTDIR)$(docdir)/html + $(RM) $(DESTDIR)$(mandir)/man3/opus_*.3 $(DESTDIR)$(mandir)/man3/opus.h.3 + +endif diff --git a/native/codec/libraries/opus/doc/build_draft.sh b/native/codec/libraries/opus/doc/build_draft.sh new file mode 100755 index 0000000..d15b22a --- /dev/null +++ b/native/codec/libraries/opus/doc/build_draft.sh @@ -0,0 +1,104 @@ +#!/bin/sh + +# Copyright (c) 2011-2012 Xiph.Org Foundation and Mozilla Corporation +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of Internet Society, IETF or IETF Trust, nor the +# names of specific contributors, may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +toplevel=".." +destdir="opus_source" + +echo packaging source code +rm -rf "${destdir}" +mkdir "${destdir}" +mkdir "${destdir}/src" +mkdir "${destdir}/silk" +mkdir "${destdir}/silk/float" +mkdir "${destdir}/silk/fixed" +mkdir "${destdir}/celt" +mkdir "${destdir}/include" +for f in `cat "${toplevel}"/opus_sources.mk "${toplevel}"/celt_sources.mk \ + "${toplevel}"/silk_sources.mk "${toplevel}"/opus_headers.mk \ + "${toplevel}"/celt_headers.mk "${toplevel}"/silk_headers.mk \ + | grep '\.[ch]' | sed -e 's/^.*=//' -e 's/\\\\//'` ; do + cp -a "${toplevel}/${f}" "${destdir}/${f}" +done +cp -a "${toplevel}"/src/opus_demo.c "${destdir}"/src/ +cp -a "${toplevel}"/src/opus_compare.c "${destdir}"/src/ +cp -a "${toplevel}"/celt/opus_custom_demo.c "${destdir}"/celt/ +cp -a "${toplevel}"/Makefile.unix "${destdir}"/Makefile +cp -a "${toplevel}"/opus_sources.mk "${destdir}"/ +cp -a "${toplevel}"/celt_sources.mk "${destdir}"/ +cp -a "${toplevel}"/silk_sources.mk "${destdir}"/ +cp -a "${toplevel}"/README.draft "${destdir}"/README +cp -a "${toplevel}"/COPYING "${destdir}"/COPYING +cp -a "${toplevel}"/tests/run_vectors.sh "${destdir}"/ + +GZIP=-9 tar --owner=root --group=root --format=v7 -czf opus_source.tar.gz "${destdir}" +echo building base64 version +cat opus_source.tar.gz| base64 | tr -d '\n' | fold -w 64 | \ + sed -e 's/^/\###/' -e 's/$/\<\/spanx\>\/' > \ + opus_source.base64 + + +#echo '
    ' > opus_compare_escaped.c +#echo '' >> opus_compare_escaped.c +#echo '> opus_compare_escaped.c +#cat opus_compare.c >> opus_compare_escaped.c +#echo ']]>' >> opus_compare_escaped.c +#echo '' >> opus_compare_escaped.c +#echo '
    ' >> opus_compare_escaped.c + +if [[ ! -d ../opus_testvectors ]] ; then + echo "Downloading test vectors..." + wget 'http://opus-codec.org/testvectors/opus_testvectors.tar.gz' + tar -C .. -xvzf opus_testvectors.tar.gz +fi +echo '
    ' > testvectors_sha1 +echo '' >> testvectors_sha1 +echo '> testvectors_sha1 +(cd ../opus_testvectors; sha1sum *.bit *.dec) >> testvectors_sha1 +#cd opus_testvectors +#sha1sum *.bit *.dec >> ../testvectors_sha1 +#cd .. +echo ']]>' >> testvectors_sha1 +echo '' >> testvectors_sha1 +echo '
    ' >> testvectors_sha1 + +echo running xml2rfc +xml2rfc draft-ietf-codec-opus.xml draft-ietf-codec-opus.html & +xml2rfc draft-ietf-codec-opus.xml +wait diff --git a/native/codec/libraries/opus/doc/build_isobmff.sh b/native/codec/libraries/opus/doc/build_isobmff.sh new file mode 100755 index 0000000..95ea202 --- /dev/null +++ b/native/codec/libraries/opus/doc/build_isobmff.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +# Copyright (c) 2014 Xiph.Org Foundation and Mozilla Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +HTML=opus_in_isobmff.html + +echo downloading updates... +CSS=${HTML%%.html}.css +wget -q http://vfrmaniac.fushizen.eu/contents/${HTML} -O ${HTML} +wget -q http://vfrmaniac.fushizen.eu/style.css -O ${CSS} + +echo updating links... +cat ${HTML} | sed -e "s/\\.\\.\\/style.css/${CSS}/" > ${HTML}+ && mv ${HTML}+ ${HTML} + +echo stripping... +cat ${HTML} | sed -e 's///g' > ${HTML}+ && mv ${HTML}+ ${HTML} +cat ${HTML} | sed -e 's/ *$//g' > ${HTML}+ && mv ${HTML}+ ${HTML} +cat ${CSS} | sed -e 's/ *$//g' > ${CSS}+ && mv ${CSS}+ ${CSS} + + +VERSION=$(fgrep Version ${HTML} | sed 's/.*Version \([0-9]\.[0-9]\.[0-9]\).*/\1/') +echo Now at version ${VERSION} diff --git a/native/codec/libraries/opus/doc/build_oggdraft.sh b/native/codec/libraries/opus/doc/build_oggdraft.sh new file mode 100755 index 0000000..30ee534 --- /dev/null +++ b/native/codec/libraries/opus/doc/build_oggdraft.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Copyright (c) 2012 Xiph.Org Foundation and Mozilla Corporation +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of Internet Society, IETF or IETF Trust, nor the +# names of specific contributors, may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +if test -z `which xml2rfc 2> /dev/null`; then + echo "Error: couldn't find xml2rfc." + echo + echo "Please install xml2rfc version 2 or later." + echo "E.g. 'pip install xml2rfc' or follow the instructions" + echo "on http://pypi.python.org/pypi/xml2rfc/ or tools.ietf.org." + exit 1 +fi + +echo running xml2rfc +# version 2 syntax +xml2rfc draft-ietf-codec-oggopus.xml --text --html diff --git a/native/codec/libraries/opus/doc/customdoxygen.css b/native/codec/libraries/opus/doc/customdoxygen.css new file mode 100644 index 0000000..7004778 --- /dev/null +++ b/native/codec/libraries/opus/doc/customdoxygen.css @@ -0,0 +1,1011 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #F1F1F1; + border: 1px solid #BDBDBD; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #646464; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #747474; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #B8B8B8; + color: #ffffff; + border: 1px double #A8A8A8; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #D5D5D5; + background-color: #FCFCFC; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: #F1F1F1; + font-weight: bold; + border: 1px solid #D5D5D5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #F1F1F1; + border: 1px solid #D5D5D5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #F2F2F2; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F9F9F9; + border-left: 2px solid #B8B8B8; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #BDBDBD; +} + +th.dirtab { + background: #F1F1F1; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #7A7A7A; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #FAFAFA; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #D5D5D5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #747474; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #747474; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #F1F1F1; + border: 1px solid #BDBDBD; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #C0C0C0; + border-left: 1px solid #C0C0C0; + border-right: 1px solid #C0C0C0; + padding: 6px 0px 6px 0px; + color: #3D3D3D; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #EAEAEA; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #C0C0C0; + border-left: 1px solid #C0C0C0; + border-right: 1px solid #C0C0C0; + padding: 2px 5px; + background-color: #FCFCFC; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F9F9F9 95%, #F2F2F2); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F9F9F9), to(#F2F2F2)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #464646; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #4A4A4A; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #5B5B5B; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #C0C0C0; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #C0C0C0; + border-bottom: 1px solid #C0C0C0; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #C0C0C0; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #EAEAEA; + font-size: 90%; + color: #3D3D3D; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #C0C0C0; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#ABABAB; + border:solid 1px #D3D3D3; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#595959; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#929292; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#595959; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #FAFAFA; + margin: 0px; + border-bottom: 1px solid #D5D5D5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 100% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #848484; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #AFAFAF; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#545454; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F7F7F7; + border: 1px solid #E3E3E3; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #747474; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} diff --git a/native/codec/libraries/opus/doc/draft-ietf-codec-oggopus.xml b/native/codec/libraries/opus/doc/draft-ietf-codec-oggopus.xml new file mode 100644 index 0000000..128816e --- /dev/null +++ b/native/codec/libraries/opus/doc/draft-ietf-codec-oggopus.xml @@ -0,0 +1,1873 @@ + + + + + + + + + + + + +]> + + + + + +Ogg Encapsulation for the Opus Audio Codec + +Mozilla Corporation +
    + +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +tterribe@xiph.org +
    +
    + + +Voicetronix +
    + +246 Pulteney Street, Level 1 +Adelaide +SA +5000 +Australia + ++61 8 8232 9112 +ron@debian.org +
    +
    + + +Mozilla Corporation +
    + +163 West Hastings Street +Vancouver +BC +V6B 1H5 +Canada + ++1 778 785 1540 +giles@xiph.org +
    +
    + + +RAI +codec + + + +This document defines the Ogg encapsulation for the Opus interactive speech and + audio codec. +This allows data encoded in the Opus format to be stored in an Ogg logical + bitstream. + + +
    + + +
    + +The IETF Opus codec is a low-latency audio codec optimized for both voice and + general-purpose audio. +See for technical details. +This document defines the encapsulation of Opus in a continuous, logical Ogg + bitstream . +Ogg encapsulation provides Opus with a long-term storage format supporting + all of the essential features, including metadata, fast and accurate seeking, + corruption detection, recapture after errors, low overhead, and the ability to + multiplex Opus with other codecs (including video) with minimal buffering. +It also provides a live streamable format, capable of delivery over a reliable + stream-oriented transport, without requiring all the data, or even the total + length of the data, up-front, in a form that is identical to the on-disk + storage format. + + +Ogg bitstreams are made up of a series of 'pages', each of which contains data + from one or more 'packets'. +Pages are the fundamental unit of multiplexing in an Ogg stream. +Each page is associated with a particular logical stream and contains a capture + pattern and checksum, flags to mark the beginning and end of the logical + stream, and a 'granule position' that represents an absolute position in the + stream, to aid seeking. +A single page can contain up to 65,025 octets of packet data from up to 255 + different packets. +Packets can be split arbitrarily across pages, and continued from one page to + the next (allowing packets much larger than would fit on a single page). +Each page contains 'lacing values' that indicate how the data is partitioned + into packets, allowing a demultiplexer (demuxer) to recover the packet + boundaries without examining the encoded data. +A packet is said to 'complete' on a page when the page contains the final + lacing value corresponding to that packet. + + +This encapsulation defines the contents of the packet data, including + the necessary headers, the organization of those packets into a logical + stream, and the interpretation of the codec-specific granule position field. +It does not attempt to describe or specify the existing Ogg container format. +Readers unfamiliar with the basic concepts mentioned above are encouraged to + review the details in . + + +
    + +
    + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", + "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in . + + +
    + +
    + +An Ogg Opus stream is organized as follows (see + for an example). + + +
    + +
    + + +There are two mandatory header packets. +The first packet in the logical Ogg bitstream MUST contain the identification + (ID) header, which uniquely identifies a stream as Opus audio. +The format of this header is defined in . +It is placed alone (without any other packet data) on the first page of + the logical Ogg bitstream, and completes on that page. +This page has its 'beginning of stream' flag set. + + +The second packet in the logical Ogg bitstream MUST contain the comment header, + which contains user-supplied metadata. +The format of this header is defined in . +It MAY span multiple pages, beginning on the second page of the logical + stream. +However many pages it spans, the comment header packet MUST finish the page on + which it completes. + + +All subsequent pages are audio data pages, and the Ogg packets they contain are + audio data packets. +Each audio data packet contains one Opus packet for each of N different + streams, where N is typically one for mono or stereo, but MAY be greater than + one for multichannel audio. +The value N is specified in the ID header (see + ), and is fixed over the entire length of the + logical Ogg bitstream. + + +The first (N - 1) Opus packets, if any, are packed one after another + into the Ogg packet, using the self-delimiting framing from Appendix B of + . +The remaining Opus packet is packed at the end of the Ogg packet using the + regular, undelimited framing from Section 3 of . +All of the Opus packets in a single Ogg packet MUST be constrained to have the + same duration. +An implementation of this specification SHOULD treat any Opus packet whose + duration is different from that of the first Opus packet in an Ogg packet as + if it were a malformed Opus packet with an invalid Table Of Contents (TOC) + sequence. + + +The TOC sequence at the beginning of each Opus packet indicates the coding + mode, audio bandwidth, channel count, duration (frame size), and number of + frames per packet, as described in Section 3.1 + of . +The coding mode is one of SILK, Hybrid, or Constrained Energy Lapped Transform + (CELT). +The combination of coding mode, audio bandwidth, and frame size is referred to + as the configuration of an Opus packet. + + +Packets are placed into Ogg pages in order until the end of stream. +Audio data packets might span page boundaries. +The first audio data page could have the 'continued packet' flag set + (indicating the first audio data packet is continued from a previous page) if, + for example, it was a live stream joined mid-broadcast, with the headers + pasted on the front. +If a page has the 'continued packet' flag set and one of the following + conditions is also true: + +the previous page with packet data does not end in a continued packet (does + not end with a lacing value of 255) OR +the page sequence numbers are not consecutive, + + then a demuxer MUST NOT attempt to decode the data for the first packet on the + page unless the demuxer has some special knowledge that would allow it to + interpret this data despite the missing pieces. +An implementation MUST treat a zero-octet audio data packet as if it were a + malformed Opus packet as described in + Section 3.4 of . + + +A logical stream ends with a page with the 'end of stream' flag set, but + implementations need to be prepared to deal with truncated streams that do not + have a page marked 'end of stream'. +There is no reason for the final packet on the last page to be a continued + packet, i.e., for the final lacing value to be 255. +However, demuxers might encounter such streams, possibly as the result of a + transfer that did not complete or of corruption. +If a packet continues onto a subsequent page (i.e., when the page ends with a + lacing value of 255) and one of the following conditions is also true: + +the next page with packet data does not have the 'continued packet' flag + set OR +there is no next page with packet data OR +the page sequence numbers are not consecutive, + + then a demuxer MUST NOT attempt to decode the data from that packet unless the + demuxer has some special knowledge that would allow it to interpret this data + despite the missing pieces. +There MUST NOT be any more pages in an Opus logical bitstream after a page + marked 'end of stream'. + +
    + +
    + +The granule position MUST be zero for the ID header page and the + page where the comment header completes. +That is, the first page in the logical stream, and the last header + page before the first audio data page both have a granule position of zero. + + +The granule position of an audio data page encodes the total number of PCM + samples in the stream up to and including the last fully-decodable sample from + the last packet completed on that page. +The granule position of the first audio data page will usually be larger than + zero, as described in . + + + +A page that is entirely spanned by a single packet (that completes on a + subsequent page) has no granule position, and the granule position field is + set to the special value '-1' in two's complement. + + + +The granule position of an audio data page is in units of PCM audio samples at + a fixed rate of 48 kHz (per channel; a stereo stream's granule position + does not increment at twice the speed of a mono stream). +It is possible to run an Opus decoder at other sampling rates, + but all Opus packets encode samples at a sampling rate that evenly divides + 48 kHz. +Therefore, the value in the granule position field always counts samples + assuming a 48 kHz decoding rate, and the rest of this specification makes + the same assumption. + + + +The duration of an Opus packet as defined in can be + any multiple of 2.5 ms, up to a maximum of 120 ms. +This duration is encoded in the TOC sequence at the beginning of each packet. +The number of samples returned by a decoder corresponds to this duration + exactly, even for the first few packets. +For example, a 20 ms packet fed to a decoder running at 48 kHz will + always return 960 samples. +A demuxer can parse the TOC sequence at the beginning of each Ogg packet to + work backwards or forwards from a packet with a known granule position (i.e., + the last packet completed on some page) in order to assign granule positions + to every packet, or even every individual sample. +The one exception is the last page in the stream, as described below. + + + +All other pages with completed packets after the first MUST have a granule + position equal to the number of samples contained in packets that complete on + that page plus the granule position of the most recent page with completed + packets. +This guarantees that a demuxer can assign individual packets the same granule + position when working forwards as when working backwards. +For this to work, there cannot be any gaps. + + +
    + +In order to support capturing a real-time stream that has lost or not + transmitted packets, a multiplexer (muxer) SHOULD emit packets that explicitly + request the use of Packet Loss Concealment (PLC) in place of the missing + packets. +Implementations that fail to do so still MUST NOT increment the granule + position for a page by anything other than the number of samples contained in + packets that actually complete on that page. + + +Only gaps that are a multiple of 2.5 ms are repairable, as these are the + only durations that can be created by packet loss or discontinuous + transmission. +Muxers need not handle other gap sizes. +Creating the necessary packets involves synthesizing a TOC byte (defined in +Section 3.1 of )—and whatever + additional internal framing is needed—to indicate the packet duration + for each stream. +The actual length of each missing Opus frame inside the packet is zero bytes, + as defined in Section 3.2.1 of . + + + +Zero-byte frames MAY be packed into packets using any of codes 0, 1, + 2, or 3. +When successive frames have the same configuration, the higher code packings + reduce overhead. +Likewise, if the TOC configuration matches, the muxer MAY further combine the + empty frames with previous or subsequent non-zero-length frames (using + code 2 or VBR code 3). + + + + does not impose any requirements on the PLC, but this + section outlines choices that are expected to have a positive influence on + most PLC implementations, including the reference implementation. +Synthesized TOC sequences SHOULD maintain the same mode, audio bandwidth, + channel count, and frame size as the previous packet (if any). +This is the simplest and usually the most well-tested case for the PLC to + handle and it covers all losses that do not include a configuration switch, + as defined in Section 4.5 of . + + + +When a previous packet is available, keeping the audio bandwidth and channel + count the same allows the PLC to provide maximum continuity in the concealment + data it generates. +However, if the size of the gap is not a multiple of the most recent frame + size, then the frame size will have to change for at least some frames. +Such changes SHOULD be delayed as long as possible to simplify + things for PLC implementations. + + + +As an example, a 95 ms gap could be encoded as nineteen 5 ms frames + in two bytes with a single CBR code 3 packet. +If the previous frame size was 20 ms, using four 20 ms frames + followed by three 5 ms frames requires 4 bytes (plus an extra byte + of Ogg lacing overhead), but allows the PLC to use its well-tested steady + state behavior for as long as possible. +The total bitrate of the latter approach, including Ogg overhead, is about + 0.4 kbps, so the impact on file size is minimal. + + + +Changing modes is discouraged, since this causes some decoder implementations + to reset their PLC state. +However, SILK and Hybrid mode frames cannot fill gaps that are not a multiple + of 10 ms. +If switching to CELT mode is needed to match the gap size, a muxer SHOULD do + so at the end of the gap to allow the PLC to function for as long as possible. + + + +In the example above, if the previous frame was a 20 ms SILK mode frame, + the better solution is to synthesize a packet describing four 20 ms SILK + frames, followed by a packet with a single 10 ms SILK + frame, and finally a packet with a 5 ms CELT frame, to fill the 95 ms + gap. +This also requires four bytes to describe the synthesized packet data (two + bytes for a CBR code 3 and one byte each for two code 0 packets) but three + bytes of Ogg lacing overhead are needed to mark the packet boundaries. +At 0.6 kbps, this is still a minimal bitrate impact over a naive, low quality + solution. + + + +Since medium-band audio is an option only in the SILK mode, wideband frames + SHOULD be generated if switching from that configuration to CELT mode, to + ensure that any PLC implementation which does try to migrate state between + the modes will be able to preserve all of the available audio bandwidth. + + +
    + +
    + +There is some amount of latency introduced during the decoding process, to + allow for overlap in the CELT mode, stereo mixing in the SILK mode, and + resampling. +The encoder might have introduced additional latency through its own resampling + and analysis (though the exact amount is not specified). +Therefore, the first few samples produced by the decoder do not correspond to + real input audio, but are instead composed of padding inserted by the encoder + to compensate for this latency. +These samples need to be stored and decoded, as Opus is an asymptotically + convergent predictive codec, meaning the decoded contents of each frame depend + on the recent history of decoder inputs. +However, a player will want to skip these samples after decoding them. + + + +A 'pre-skip' field in the ID header (see ) signals + the number of samples that SHOULD be skipped (decoded but discarded) at the + beginning of the stream, though some specific applications might have a reason + for looking at that data. +This amount need not be a multiple of 2.5 ms, MAY be smaller than a single + packet, or MAY span the contents of several packets. +These samples are not valid audio. + + + +For example, if the first Opus frame uses the CELT mode, it will always + produce 120 samples of windowed overlap-add data. +However, the overlap data is initially all zeros (since there is no prior + frame), meaning this cannot, in general, accurately represent the original + audio. +The SILK mode requires additional delay to account for its analysis and + resampling latency. +The encoder delays the original audio to avoid this problem. + + + +The pre-skip field MAY also be used to perform sample-accurate cropping of + already encoded streams. +In this case, a value of at least 3840 samples (80 ms) provides + sufficient history to the decoder that it will have converged + before the stream's output begins. + + +
    + +
    + +The PCM sample position is determined from the granule position using the + formula + +
    + +
    + + +For example, if the granule position of the first audio data page is 59,971, + and the pre-skip is 11,971, then the PCM sample position of the last decoded + sample from that page is 48,000. + + +This can be converted into a playback time using the formula + +
    + +
    + + +The initial PCM sample position before any samples are played is normally '0'. +In this case, the PCM sample position of the first audio sample to be played + starts at '1', because it marks the time on the clock + after that sample has been played, and a stream + that is exactly one second long has a final PCM sample position of '48000', + as in the example here. + + + +Vorbis streams use a granule position smaller than the number of audio samples + contained in the first audio data page to indicate that some of those samples + are trimmed from the output (see ). +However, to do so, Vorbis requires that the first audio data page contains + exactly two packets, in order to allow the decoder to perform PCM position + adjustments before needing to return any PCM data. +Opus uses the pre-skip mechanism for this purpose instead, since the encoder + might introduce more than a single packet's worth of latency, and since very + large packets in streams with a very large number of channels might not fit + on a single page. + +
    + +
    + +The page with the 'end of stream' flag set MAY have a granule position that + indicates the page contains less audio data than would normally be returned by + decoding up through the final packet. +This is used to end the stream somewhere other than an even frame boundary. +The granule position of the most recent audio data page with completed packets + is used to make this determination, or '0' is used if there were no previous + audio data pages with a completed packet. +The difference between these granule positions indicates how many samples to + keep after decoding the packets that completed on the final page. +The remaining samples are discarded. +The number of discarded samples SHOULD be no larger than the number decoded + from the last packet. + +
    + +
    + +The granule position of the first audio data page with a completed packet MAY + be larger than the number of samples contained in packets that complete on + that page, however it MUST NOT be smaller, unless that page has the 'end of + stream' flag set. +Allowing a granule position larger than the number of samples allows the + beginning of a stream to be cropped or a live stream to be joined without + rewriting the granule position of all the remaining pages. +This means that the PCM sample position just before the first sample to be + played MAY be larger than '0'. +Synchronization when multiplexing with other logical streams still uses the PCM + sample position relative to '0' to compute sample times. +This does not affect the behavior of pre-skip: exactly 'pre-skip' samples + SHOULD be skipped from the beginning of the decoded output, even if the + initial PCM sample position is greater than zero. + + + +On the other hand, a granule position that is smaller than the number of + decoded samples prevents a demuxer from working backwards to assign each + packet or each individual sample a valid granule position, since granule + positions are non-negative. +An implementation MUST treat any stream as invalid if the granule position + is smaller than the number of samples contained in packets that complete on + the first audio data page with a completed packet, unless that page has the + 'end of stream' flag set. +It MAY defer this action until it decodes the last packet completed on that + page. + + + +If that page has the 'end of stream' flag set, a demuxer MUST treat any stream + as invalid if its granule position is smaller than the 'pre-skip' amount. +This would indicate that there are more samples to be skipped from the initial + decoded output than exist in the stream. +If the granule position is smaller than the number of decoded samples produced + by the packets that complete on that page, then a demuxer MUST use an initial + granule position of '0', and can work forwards from '0' to timestamp + individual packets. +If the granule position is larger than the number of decoded samples available, + then the demuxer MUST still work backwards as described above, even if the + 'end of stream' flag is set, to determine the initial granule position, and + thus the initial PCM sample position. +Both of these will be greater than '0' in this case. + +
    + +
    + +Seeking in Ogg files is best performed using a bisection search for a page + whose granule position corresponds to a PCM position at or before the seek + target. +With appropriately weighted bisection, accurate seeking can be performed in + just one or two bisections on average, even in multi-gigabyte files. +See for an example of general implementation guidance. + + + +When seeking within an Ogg Opus stream, an implementation SHOULD start decoding + (and discarding the output) at least 3840 samples (80 ms) prior to + the seek target in order to ensure that the output audio is correct by the + time it reaches the seek target. +This 'pre-roll' is separate from, and unrelated to, the 'pre-skip' used at the + beginning of the stream. +If the point 80 ms prior to the seek target comes before the initial PCM + sample position, an implementation SHOULD start decoding from the beginning of + the stream, applying pre-skip as normal, regardless of whether the pre-skip is + larger or smaller than 80 ms, and then continue to discard samples + to reach the seek target (if any). + +
    + +
    + +
    + +An Ogg Opus logical stream contains exactly two mandatory header packets: + an identification header and a comment header. + + +
    + +
    + +
    + + +The fields in the identification (ID) header have the following meaning: + +Magic Signature: + +This is an 8-octet (64-bit) field that allows codec identification and is + human-readable. +It contains, in order, the magic numbers: + +0x4F 'O' +0x70 'p' +0x75 'u' +0x73 's' +0x48 'H' +0x65 'e' +0x61 'a' +0x64 'd' + +Starting with "Op" helps distinguish it from audio data packets, as this is an + invalid TOC sequence. + + +Version (8 bits, unsigned): + +The version number MUST always be '1' for this version of the encapsulation + specification. +Implementations SHOULD treat streams where the upper four bits of the version + number match that of a recognized specification as backwards-compatible with + that specification. +That is, the version number can be split into "major" and "minor" version + sub-fields, with changes to the "minor" sub-field (in the lower four bits) + signaling compatible changes. +For example, an implementation of this specification SHOULD accept any stream + with a version number of '15' or less, and SHOULD assume any stream with a + version number '16' or greater is incompatible. +The initial version '1' was chosen to keep implementations from relying on this + octet as a null terminator for the "OpusHead" string. + + +Output Channel Count 'C' (8 bits, unsigned): + +This is the number of output channels. +This might be different than the number of encoded channels, which can change + on a packet-by-packet basis. +This value MUST NOT be zero. +The maximum allowable value depends on the channel mapping family, and might be + as large as 255. +See for details. + + +Pre-skip (16 bits, unsigned, little + endian): + +This is the number of samples (at 48 kHz) to discard from the decoder + output when starting playback, and also the number to subtract from a page's + granule position to calculate its PCM sample position. +When cropping the beginning of existing Ogg Opus streams, a pre-skip of at + least 3,840 samples (80 ms) is RECOMMENDED to ensure complete + convergence in the decoder. + + +Input Sample Rate (32 bits, unsigned, little + endian): + +This is the sample rate of the original input (before encoding), in Hz. +This field is not the sample rate to use for + playback of the encoded data. + +Opus can switch between internal audio bandwidths of 4, 6, 8, 12, and + 20 kHz. +Each packet in the stream can have a different audio bandwidth. +Regardless of the audio bandwidth, the reference decoder supports decoding any + stream at a sample rate of 8, 12, 16, 24, or 48 kHz. +The original sample rate of the audio passed to the encoder is not preserved + by the lossy compression. + +An Ogg Opus player SHOULD select the playback sample rate according to the + following procedure: + +If the hardware supports 48 kHz playback, decode at 48 kHz. +Otherwise, if the hardware's highest available sample rate is a supported + rate, decode at this sample rate. +Otherwise, if the hardware's highest available sample rate is less than + 48 kHz, decode at the next higher Opus supported rate above the highest + available hardware rate and resample. +Otherwise, decode at 48 kHz and resample. + +However, the 'Input Sample Rate' field allows the muxer to pass the sample + rate of the original input stream as metadata. +This is useful when the user requires the output sample rate to match the + input sample rate. +For example, when not playing the output, an implementation writing PCM format + samples to disk might choose to resample the audio back to the original input + sample rate to reduce surprise to the user, who might reasonably expect to get + back a file with the same sample rate. + +A value of zero indicates 'unspecified'. +Muxers SHOULD write the actual input sample rate or zero, but implementations + which do something with this field SHOULD take care to behave sanely if given + crazy values (e.g., do not actually upsample the output to 10 MHz if + requested). +Implementations SHOULD support input sample rates between 8 kHz and + 192 kHz (inclusive). +Rates outside this range MAY be ignored by falling back to the default rate of + 48 kHz instead. + + +Output Gain (16 bits, signed, little endian): + +This is a gain to be applied when decoding. +It is 20*log10 of the factor by which to scale the decoder output to achieve + the desired playback volume, stored in a 16-bit, signed, two's complement + fixed-point value with 8 fractional bits (i.e., + Q7.8 ). + +To apply the gain, an implementation could use +
    + +
    + where output_gain is the raw 16-bit value from the header. + +Players and media frameworks SHOULD apply it by default. +If a player chooses to apply any volume adjustment or gain modification, such + as the R128_TRACK_GAIN (see ), the adjustment + MUST be applied in addition to this output gain in order to achieve playback + at the normalized volume. + +A muxer SHOULD set this field to zero, and instead apply any gain prior to + encoding, when this is possible and does not conflict with the user's wishes. +A nonzero output gain indicates the gain was adjusted after encoding, or that + a user wished to adjust the gain for playback while preserving the ability + to recover the original signal amplitude. + +Although the output gain has enormous range (+/- 128 dB, enough to amplify + inaudible sounds to the threshold of physical pain), most applications can + only reasonably use a small portion of this range around zero. +The large range serves in part to ensure that gain can always be losslessly + transferred between OpusHead and R128 gain tags (see below) without + saturating. + +
    +Channel Mapping Family (8 bits, unsigned): + +This octet indicates the order and semantic meaning of the output channels. + +Each currently specified value of this octet indicates a mapping family, which + defines a set of allowed channel counts, and the ordered set of channel names + for each allowed channel count. +The details are described in . + +Channel Mapping Table: +This table defines the mapping from encoded streams to output channels. +Its contents are specified in . + +
    +
    + + +All fields in the ID headers are REQUIRED, except for the channel mapping + table, which MUST be omitted when the channel mapping family is 0, but + is REQUIRED otherwise. +Implementations SHOULD treat a stream as invalid if it contains an ID header + that does not have enough data for these fields, even if it contain a valid + Magic Signature. +Future versions of this specification, even backwards-compatible versions, + might include additional fields in the ID header. +If an ID header has a compatible major version, but a larger minor version, + an implementation MUST NOT treat it as invalid for containing additional data + not specified here, provided it still completes on the first page. + + +
    + +An Ogg Opus stream allows mapping one number of Opus streams (N) to a possibly + larger number of decoded channels (M + N) to yet another number of + output channels (C), which might be larger or smaller than the number of + decoded channels. +The order and meaning of these channels are defined by a channel mapping, + which consists of the 'channel mapping family' octet and, for channel mapping + families other than family 0, a channel mapping table, as illustrated in + . + + +
    + +
    + + +The fields in the channel mapping table have the following meaning: + +Stream Count 'N' (8 bits, unsigned): + +This is the total number of streams encoded in each Ogg packet. +This value is necessary to correctly parse the packed Opus packets inside an + Ogg packet, as described in . +This value MUST NOT be zero, as without at least one Opus packet with a valid + TOC sequence, a demuxer cannot recover the duration of an Ogg packet. + +For channel mapping family 0, this value defaults to 1, and is not coded. + + +Coupled Stream Count 'M' (8 bits, unsigned): +This is the number of streams whose decoders are to be configured to produce + two channels (stereo). +This MUST be no larger than the total number of streams, N. + +Each packet in an Opus stream has an internal channel count of 1 or 2, which + can change from packet to packet. +This is selected by the encoder depending on the bitrate and the audio being + encoded. +The original channel count of the audio passed to the encoder is not + necessarily preserved by the lossy compression. + +Regardless of the internal channel count, any Opus stream can be decoded as + mono (a single channel) or stereo (two channels) by appropriate initialization + of the decoder. +The 'coupled stream count' field indicates that the decoders for the first M + Opus streams are to be initialized for stereo (two-channel) output, and the + remaining (N - M) decoders are to be initialized for mono (a single + channel) only. +The total number of decoded channels, (M + N), MUST be no larger than + 255, as there is no way to index more channels than that in the channel + mapping. + +For channel mapping family 0, this value defaults to (C - 1) + (i.e., 0 for mono and 1 for stereo), and is not coded. + + +Channel Mapping (8*C bits): +This contains one octet per output channel, indicating which decoded channel + is to be used for each one. +Let 'index' be the value of this octet for a particular output channel. +This value MUST either be smaller than (M + N), or be the special + value 255. +If 'index' is less than 2*M, the output MUST be taken from decoding stream + ('index'/2) as stereo and selecting the left channel if 'index' is even, and + the right channel if 'index' is odd. +If 'index' is 2*M or larger, but less than 255, the output MUST be taken from + decoding stream ('index' - M) as mono. +If 'index' is 255, the corresponding output channel MUST contain pure silence. + +The number of output channels, C, is not constrained to match the number of + decoded channels (M + N). +A single index value MAY appear multiple times, i.e., the same decoded channel + might be mapped to multiple output channels. +Some decoded channels might not be assigned to any output channel, as well. + +For channel mapping family 0, the first index defaults to 0, and if + C == 2, the second index defaults to 1. +Neither index is coded. + + + + + +After producing the output channels, the channel mapping family determines the + semantic meaning of each one. +There are three defined mapping families in this specification. + + +
    + +Allowed numbers of channels: 1 or 2. +RTP mapping. +This is the same channel interpretation as . + + + +1 channel: monophonic (mono). +2 channels: stereo (left, right). + +Special mapping: This channel mapping value also + indicates that the contents consists of a single Opus stream that is stereo if + and only if C == 2, with stream index 0 mapped to output + channel 0 (mono, or left channel) and stream index 1 mapped to + output channel 1 (right channel) if stereo. +When the 'channel mapping family' octet has this value, the channel mapping + table MUST be omitted from the ID header packet. + +
    + +
    + +Allowed numbers of channels: 1...8. +Vorbis channel order (see below). + + +Each channel is assigned to a speaker location in a conventional surround + arrangement. +Specific locations depend on the number of channels, and are given below + in order of the corresponding channel indices. + + 1 channel: monophonic (mono). + 2 channels: stereo (left, right). + 3 channels: linear surround (left, center, right) + 4 channels: quadraphonic (front left, front right, rear left, rear right). + 5 channels: 5.0 surround (front left, front center, front right, rear left, rear right). + 6 channels: 5.1 surround (front left, front center, front right, rear left, rear right, LFE). + 7 channels: 6.1 surround (front left, front center, front right, side left, side right, rear center, LFE). + 8 channels: 7.1 surround (front left, front center, front right, side left, side right, rear left, rear right, LFE) + + + +This set of surround options and speaker location orderings is the same + as those used by the Vorbis codec . +The ordering is different from the one used by the + WAVE and + Free Lossless Audio Codec (FLAC) formats, + so correct ordering requires permutation of the output channels when decoding + to or encoding from those formats. +'LFE' here refers to a Low Frequency Effects channel, often mapped to a + subwoofer with no particular spatial position. +Implementations SHOULD identify 'side' or 'rear' speaker locations with + 'surround' and 'back' as appropriate when interfacing with audio formats + or systems which prefer that terminology. + +
    + +
    + +Allowed numbers of channels: 1...255. +No defined channel meaning. + + +Channels are unidentified. +General-purpose players SHOULD NOT attempt to play these streams. +Offline implementations MAY deinterleave the output into separate PCM files, + one per channel. +Implementations SHOULD NOT produce output for channels mapped to stream index + 255 (pure silence) unless they have no other way to indicate the index of + non-silent channels. + +
    + +
    + +The remaining channel mapping families (2...254) are reserved. +A demuxer implementation encountering a reserved channel mapping family value + SHOULD act as though the value is 255. + +
    + +
    + +An Ogg Opus player MUST support any valid channel mapping with a channel + mapping family of 0 or 1, even if the number of channels does not match the + physically connected audio hardware. +Players SHOULD perform channel mixing to increase or reduce the number of + channels as needed. + + + +Implementations MAY use the matrices in + Figures  + through  to implement + downmixing from multichannel files using + Channel Mapping Family 1, which are + known to give acceptable results for stereo. +Matrices for 3 and 4 channels are normalized so each coefficient row sums + to 1 to avoid clipping. +For 5 or more channels they are normalized to 2 as a compromise between + clipping and dynamic range reduction. + + +In these matrices the front left and front right channels are generally +passed through directly. +When a surround channel is split between both the left and right stereo + channels, coefficients are chosen so their squares sum to 1, which + helps preserve the perceived intensity. +Rear channels are mixed more diffusely or attenuated to maintain focus + on the front channels. + + +
    + + +Exact coefficient values are 1 and 1/sqrt(2), multiplied by + 1/(1 + 1/sqrt(2)) for normalization. + +
    + +
    + + +Exact coefficient values are 1, sqrt(3)/2 and 1/2, multiplied by + 1/(1 + sqrt(3)/2 + 1/2) for normalization. + +
    + +
    + + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by + 2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2) + for normalization. + +
    + +
    + + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by +2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2 + 1/sqrt(2)) + for normalization. + +
    + +
    + + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2, 1/2 and + sqrt(3)/2/sqrt(2), multiplied by + 2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2 + + sqrt(3)/2/sqrt(2) + 1/sqrt(2)) for normalization. +The coefficients are in the same order as in , + and the matrices above. + +
    + +
    + + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by + 2/(2 + 2/sqrt(2) + sqrt(3)) for normalization. +The coefficients are in the same order as in , + and the matrices above. + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + +The comment header consists of a 64-bit magic signature, followed by data in + the same format as the header used in Ogg + Vorbis, except (like Ogg Theora and Speex) the final "framing bit" specified + in the Vorbis spec is not present. + +Magic Signature: + +This is an 8-octet (64-bit) field that allows codec identification and is + human-readable. +It contains, in order, the magic numbers: + +0x4F 'O' +0x70 'p' +0x75 'u' +0x73 's' +0x54 'T' +0x61 'a' +0x67 'g' +0x73 's' + +Starting with "Op" helps distinguish it from audio data packets, as this is an + invalid TOC sequence. + + +Vendor String Length (32 bits, unsigned, little endian): + +This field gives the length of the following vendor string, in octets. +It MUST NOT indicate that the vendor string is longer than the rest of the + packet. + + +Vendor String (variable length, UTF-8 vector): + +This is a simple human-readable tag for vendor information, encoded as a UTF-8 + string . +No terminating null octet is necessary. + +This tag is intended to identify the codec encoder and encapsulation + implementations, for tracing differences in technical behavior. +User-facing applications can use the 'ENCODER' user comment tag to identify + themselves. + + +User Comment List Length (32 bits, unsigned, little endian): + +This field indicates the number of user-supplied comments. +It MAY indicate there are zero user-supplied comments, in which case there are + no additional fields in the packet. +It MUST NOT indicate that there are so many comments that the comment string + lengths would require more data than is available in the rest of the packet. + + +User Comment #i String Length (32 bits, unsigned, little endian): + +This field gives the length of the following user comment string, in octets. +There is one for each user comment indicated by the 'user comment list length' + field. +It MUST NOT indicate that the string is longer than the rest of the packet. + + +User Comment #i String (variable length, UTF-8 vector): + +This field contains a single user comment encoded as a UTF-8 + string . +There is one for each user comment indicated by the 'user comment list length' + field. + + + + + +The vendor string length and user comment list length are REQUIRED, and + implementations SHOULD treat a stream as invalid if it contains a comment + header that does not have enough data for these fields, or that does not + contain enough data for the corresponding vendor string or user comments they + describe. +Making this check before allocating the associated memory to contain the data + helps prevent a possible Denial-of-Service (DoS) attack from small comment + headers that claim to contain strings longer than the entire packet or more + user comments than than could possibly fit in the packet. + + + +Immediately following the user comment list, the comment header MAY + contain zero-padding or other binary data which is not specified here. +If the least-significant bit of the first byte of this data is 1, then editors + SHOULD preserve the contents of this data when updating the tags, but if this + bit is 0, all such data MAY be treated as padding, and truncated or discarded + as desired. +This allows informal experimentation with the format of this binary data until + it can be specified later. + + + +The comment header can be arbitrarily large and might be spread over a large + number of Ogg pages. +Implementations MUST avoid attempting to allocate excessive amounts of memory + when presented with a very large comment header. +To accomplish this, implementations MAY treat a stream as invalid if it has a + comment header larger than 125,829,120 octets (120 MB), and MAY + ignore individual comments that are not fully contained within the first + 61,440 octets of the comment header. + + +
    + +The user comment strings follow the NAME=value format described by + with the same recommended tag names: + ARTIST, TITLE, DATE, ALBUM, and so on. + + +Two new comment tags are introduced here: + + +First, an optional gain for track normalization: +
    + +
    + + representing the volume shift needed to normalize the track's volume + during isolated playback, in random shuffle, and so on. +The gain is a Q7.8 fixed point number in dB, as in the ID header's 'output + gain' field. +This tag is similar to the REPLAYGAIN_TRACK_GAIN tag in + Vorbis , except that the normal volume + reference is the standard. + +Second, an optional gain for album normalization: +
    + +
    + + representing the volume shift needed to normalize the overall volume when + played as part of a particular collection of tracks. +The gain is also a Q7.8 fixed point number in dB, as in the ID header's + 'output gain' field. +The values '-573' and '111' given here are just examples. + + +An Ogg Opus stream MUST NOT have more than one of each of these tags, and if + present their values MUST be an integer from -32768 to 32767, inclusive, + represented in ASCII as a base 10 number with no whitespace. +A leading '+' or '-' character is valid. +Leading zeros are also permitted, but the value MUST be represented by + no more than 6 characters. +Other non-digit characters MUST NOT be present. + + +If present, R128_TRACK_GAIN and R128_ALBUM_GAIN MUST correctly represent + the R128 normalization gain relative to the 'output gain' field specified + in the ID header. +If a player chooses to make use of the R128_TRACK_GAIN tag or the + R128_ALBUM_GAIN tag, it MUST apply those gains + in addition to the 'output gain' value. +If a tool modifies the ID header's 'output gain' field, it MUST also update or + remove the R128_TRACK_GAIN and R128_ALBUM_GAIN comment tags if present. +A muxer SHOULD place the gain it wants other tools to use by default into the + 'output gain' field, and not the comment tag. + + +To avoid confusion with multiple normalization schemes, an Opus comment header + SHOULD NOT contain any of the REPLAYGAIN_TRACK_GAIN, REPLAYGAIN_TRACK_PEAK, + REPLAYGAIN_ALBUM_GAIN, or REPLAYGAIN_ALBUM_PEAK tags, unless they are only + to be used in some context where there is guaranteed to be no such confusion. + normalization is preferred to the earlier + REPLAYGAIN schemes because of its clear definition and adoption by industry. +Peak normalizations are difficult to calculate reliably for lossy codecs + because of variation in excursion heights due to decoder differences. +In the authors' investigations they were not applied consistently or broadly + enough to merit inclusion here. + +
    +
    + +
    + +
    + +Technically, valid Opus packets can be arbitrarily large due to the padding + format, although the amount of non-padding data they can contain is bounded. +These packets might be spread over a similarly enormous number of Ogg pages. +When encoding, implementations SHOULD limit the use of padding in audio data + packets to no more than is necessary to make a variable bitrate (VBR) stream + constant bitrate (CBR), unless they have no reasonable way to determine what + is necessary. +Demuxers SHOULD treat audio data packets as invalid (treat them as if they were + malformed Opus packets with an invalid TOC sequence) if they are larger than + 61,440 octets per Opus stream, unless they have a specific reason for + allowing extra padding. +Such packets necessarily contain more padding than needed to make a stream CBR. +Demuxers MUST avoid attempting to allocate excessive amounts of memory when + presented with a very large packet. +Demuxers MAY treat audio data packets as invalid or partially process them if + they are larger than 61,440 octets in an Ogg Opus stream with channel + mapping families 0 or 1. +Demuxers MAY treat audio data packets as invalid or partially process them in + any Ogg Opus stream if the packet is larger than 61,440 octets and also + larger than 7,680 octets per Opus stream. +The presence of an extremely large packet in the stream could indicate a + memory exhaustion attack or stream corruption. + + +In an Ogg Opus stream, the largest possible valid packet that does not use + padding has a size of (61,298*N - 2) octets. +With 255 streams, this is 15,630,988 octets and can + span up to 61,298 Ogg pages, all but one of which will have a granule + position of -1. +This is of course a very extreme packet, consisting of 255 streams, each + containing 120 ms of audio encoded as 2.5 ms frames, each frame + using the maximum possible number of octets (1275) and stored in the least + efficient manner allowed (a VBR code 3 Opus packet). +Even in such a packet, most of the data will be zeros as 2.5 ms frames + cannot actually use all 1275 octets. + + +The largest packet consisting of entirely useful data is + (15,326*N - 2) octets. +This corresponds to 120 ms of audio encoded as 10 ms frames in either + SILK or Hybrid mode, but at a data rate of over 1 Mbps, which makes little + sense for the quality achieved. + + +A more reasonable limit is (7,664*N - 2) octets. +This corresponds to 120 ms of audio encoded as 20 ms stereo CELT mode + frames, with a total bitrate just under 511 kbps (not counting the Ogg + encapsulation overhead). +For channel mapping family 1, N=8 provides a reasonable upper bound, as it + allows for each of the 8 possible output channels to be decoded from a + separate stereo Opus stream. +This gives a size of 61,310 octets, which is rounded up to a multiple of + 1,024 octets to yield the audio data packet size of 61,440 octets + that any implementation is expected to be able to process successfully. + +
    + +
    + +When encoding Opus streams, Ogg muxers SHOULD take into account the + algorithmic delay of the Opus encoder. + + +In encoders derived from the reference + implementation , the number of samples can be + queried with: + +
    + +
    + +To achieve good quality in the very first samples of a stream, implementations + MAY use linear predictive coding (LPC) extrapolation to generate at least 120 + extra samples at the beginning to avoid the Opus encoder having to encode a + discontinuous signal. +For more information on linear prediction, see + . +For an input file containing 'length' samples, the implementation SHOULD set + the pre-skip header value to (delay_samples + extra_samples), encode + at least (length + delay_samples + extra_samples) + samples, and set the granule position of the last page to + (length + delay_samples + extra_samples). +This ensures that the encoded file has the same duration as the original, with + no time offset. The best way to pad the end of the stream is to also use LPC + extrapolation, but zero-padding is also acceptable. + + +
    + +The first step in LPC extrapolation is to compute linear prediction + coefficients. +When extending the end of the signal, order-N (typically with N ranging from 8 + to 40) LPC analysis is performed on a window near the end of the signal. +The last N samples are used as memory to an infinite impulse response (IIR) + filter. + + +The filter is then applied on a zero input to extrapolate the end of the signal. +Let a(k) be the kth LPC coefficient and x(n) be the nth sample of the signal, + each new sample past the end of the signal is computed as: + +
    + +
    + +The process is repeated independently for each channel. +It is possible to extend the beginning of the signal by applying the same + process backward in time. +When extending the beginning of the signal, it is best to apply a "fade in" to + the extrapolated signal, e.g. by multiplying it by a half-Hanning window + . + + +
    + +
    + +In some applications, such as Internet radio, it is desirable to cut a long + stream into smaller chains, e.g. so the comment header can be updated. +This can be done simply by separating the input streams into segments and + encoding each segment independently. +The drawback of this approach is that it creates a small discontinuity + at the boundary due to the lossy nature of Opus. +A muxer MAY avoid this discontinuity by using the following procedure: + +Encode the last frame of the first segment as an independent frame by + turning off all forms of inter-frame prediction. +De-emphasis is allowed. +Set the granule position of the last page to a point near the end of the + last frame. +Begin the second segment with a copy of the last frame of the first + segment. +Set the pre-skip value of the second stream in such a way as to properly + join the two streams. +Continue the encoding process normally from there, without any reset to + the encoder. + + + +In encoders derived from the reference implementation, inter-frame prediction + can be turned off by calling: + +
    + +
    + +For best results, this implementation requires that prediction be explicitly + enabled again before resuming normal encoding, even after a reset. + + +
    + +
    + +
    + +A brief summary of major implementations of this draft is available + at , + along with their status. + + +[Note to RFC Editor: please remove this entire section before + final publication per , along with + its references.] + +
    + +
    + +Implementations of the Opus codec need to take appropriate security + considerations into account, as outlined in . +This is just as much a problem for the container as it is for the codec itself. +Malicious payloads and/or input streams can be used to attack codec + implementations. +Implementations MUST NOT overrun their allocated memory nor consume excessive + resources when decoding payloads or processing input streams. +Although problems in encoding applications are typically rarer, this still + applies to a muxer, as vulnerabilities would allow an attacker to attack + transcoding gateways. + + + +Header parsing code contains the most likely area for potential overruns. +It is important for implementations to ensure their buffers contain enough + data for all of the required fields before attempting to read it (for example, + for all of the channel map data in the ID header). +Implementations would do well to validate the indices of the channel map, also, + to ensure they meet all of the restrictions outlined in + , in order to avoid attempting to read data + from channels that do not exist. + + + +To avoid excessive resource usage, we advise implementations to be especially + wary of streams that might cause them to process far more data than was + actually transmitted. +For example, a relatively small comment header may contain values for the + string lengths or user comment list length that imply that it is many + gigabytes in size. +Even computing the size of the required buffer could overflow a 32-bit integer, + and actually attempting to allocate such a buffer before verifying it would be + a reasonable size is a bad idea. +After reading the user comment list length, implementations might wish to + verify that the header contains at least the minimum amount of data for that + many comments (4 additional octets per comment, to indicate each has a + length of zero) before proceeding any further, again taking care to avoid + overflow in these calculations. +If allocating an array of pointers to point at these strings, the size of the + pointers may be larger than 4 octets, potentially requiring a separate + overflow check. + + + +Another bug in this class we have observed more than once involves the handling + of invalid data at the end of a stream. +Often, implementations will seek to the end of a stream to locate the last + timestamp in order to compute its total duration. +If they do not find a valid capture pattern and Ogg page from the desired + logical stream, they will back up and try again. +If care is not taken to avoid re-scanning data that was already scanned, this + search can quickly devolve into something with a complexity that is quadratic + in the amount of invalid data. + + + +In general when seeking, implementations will wish to be cautious about the + effects of invalid granule position values, and ensure all algorithms will + continue to make progress and eventually terminate, even if these are missing + or out-of-order. + + + +Like most other container formats, Ogg Opus streams SHOULD NOT be used with + insecure ciphers or cipher modes that are vulnerable to known-plaintext + attacks. +Elements such as the Ogg page capture pattern and the magic signatures in the + ID header and the comment header all have easily predictable values, in + addition to various elements of the codec data itself. + +
    + +
    + +An "Ogg Opus file" consists of one or more sequentially multiplexed segments, + each containing exactly one Ogg Opus stream. +The RECOMMENDED mime-type for Ogg Opus files is "audio/ogg". + + + +If more specificity is desired, one MAY indicate the presence of Opus streams + using the codecs parameter defined in and + , e.g., + +
    + +
    + + for an Ogg Opus file. + + + +The RECOMMENDED filename extension for Ogg Opus files is '.opus'. + + + +When Opus is concurrently multiplexed with other streams in an Ogg container, + one SHOULD use one of the "audio/ogg", "video/ogg", or "application/ogg" + mime-types, as defined in . +Such streams are not strictly "Ogg Opus files" as described above, + since they contain more than a single Opus stream per sequentially + multiplexed segment, e.g. video or multiple audio tracks. +In such cases the the '.opus' filename extension is NOT RECOMMENDED. + + + +In either case, this document updates + to add 'opus' as a codecs parameter value with char[8]: 'OpusHead' + as Codec Identifier. + +
    + +
    + +This document updates the IANA Media Types registry to add .opus + as a file extension for "audio/ogg", and to add itself as a reference + alongside for "audio/ogg", "video/ogg", and + "application/ogg" Media Types. + + +This document defines a new registry "Opus Channel Mapping Families" to + indicate how the semantic meanings of the channels in a multi-channel Opus + stream are described. +IANA is requested to create a new name space of "Opus Channel Mapping + Families". +This will be a new registry on the IANA Matrix, and not a subregistry of an + existing registry. +Modifications to this registry follow the "Specification Required" registration + policy as defined in . +Each registry entry consists of a Channel Mapping Family Number, which is + specified in decimal in the range 0 to 255, inclusive, and a Reference (or + list of references) +Each Reference must point to sufficient documentation to describe what + information is coded in the Opus identification header for this channel + mapping family, how a demuxer determines the Stream Count ('N') and Coupled + Stream Count ('M') from this information, and how it determines the proper + interpretation of each of the decoded channels. + + +This document defines three initial assignments for this registry. + + +ValueReference +0[RFCXXXX] +1[RFCXXXX] +255[RFCXXXX] + + +The designated expert will determine if the Reference points to a specification + that meets the requirements for permanence and ready availability laid out + in  and that it specifies the information + described above with sufficient clarity to allow interoperable + implementations. + +
    + +
    + +Thanks to Ben Campbell, Joel M. Halpern, Mark Harris, Greg Maxwell, + Christopher "Monty" Montgomery, Jean-Marc Valin, Stephan Wenger, and Mo Zanaty + for their valuable contributions to this document. +Additional thanks to Andrew D'Addesio, Greg Maxwell, and Vincent Penquerc'h for + their feedback based on early implementations. + +
    + +
    + +In , "RFCXXXX" is to be replaced with the RFC number + assigned to this draft. + +
    + +
    + + + &rfc2119; + &rfc3533; + &rfc3629; + &rfc5226; + &rfc5334; + &rfc6381; + &rfc6716; + + + + Loudness Recommendation EBU R128 + + EBU Technical Committee + + + + + + + +Ogg Vorbis I Format Specification: Comment Field and Header + Specification + + + + + + + + + + + &rfc4732; + &rfc6982; + &rfc7587; + + + + FLAC - Free Lossless Audio Codec Format Description + + + + + + + + Hann window + + Wikipedia + + + + + + + + Linear Predictive Coding + + Wikipedia + + + + + + + + Autocorrelation LPC coeff generation algorithm + (Vorbis source code) + + + + + + + + +Q (number format) +Wikipedia + + + + + + +VorbisComment: Replay Gain + + + + + + + + +Granulepos Encoding and How Seeking Really Works + + + + + + + + + +The Vorbis I Specification, Section 4.3.9 Output Channel Order + + + + + + + + The Vorbis I Specification, Appendix A: Embedding Vorbis + into an Ogg stream + + + + + + + + Multiple Channel Audio Data and WAVE Files + + Microsoft Corporation + + + + + + + + +
    diff --git a/native/codec/libraries/opus/doc/draft-ietf-codec-opus-update.xml b/native/codec/libraries/opus/doc/draft-ietf-codec-opus-update.xml new file mode 100644 index 0000000..3124e22 --- /dev/null +++ b/native/codec/libraries/opus/doc/draft-ietf-codec-opus-update.xml @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + Updates to the Opus Audio Codec + + +Mozilla Corporation +
    + +331 E. Evelyn Avenue +Mountain View +CA +94041 +USA + ++1 650 903-0800 +jmvalin@jmvalin.ca +
    +
    + + +vocTone +
    + + + + + + + + +koenvos74@gmail.com +
    +
    + + + + + + + This document addresses minor issues that were found in the specification + of the Opus audio codec in RFC 6716. It updates the normative decoder implementation + included in the appendix of RFC 6716. The changes fixes real and potential security-related + issues, as well minor quality-related issues. + +
    + + +
    + This document addresses minor issues that were discovered in the reference + implementation of the Opus codec. Unlike most IETF specifications, Opus is defined + in RFC 6716 in terms of a normative reference + decoder implementation rather than from the associated text description. + That RFC includes the reference decoder implementation as Appendix A. + That's why only issues affecting the decoder are + listed here. An up-to-date implementation of the Opus encoder can be found at + . + + Some of the changes in this document update normative behaviour in a way that requires + new test vectors. The English text of the specification is unaffected, only + the C implementation is. The updated specification remains fully compatible with + the original specification. + + + + Note: due to RFC formatting conventions, lines exceeding the column width + in the patch are split using a backslash character. The backslashes + at the end of a line and the white space at the beginning + of the following line are not part of the patch. A properly formatted patch + including all changes is available at + + and has a SHA-1 hash of 029e3aa88fc342c91e67a21e7bfbc9458661cd5f. + + +
    + +
    + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119. +
    + +
    + The reference implementation does not reinitialize the stereo state + during a mode switch. The old stereo memory can produce a brief impulse + (i.e. single sample) in the decoded audio. This can be fixed by changing + silk/dec_API.c at line 72: + +
    + + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } ++ silk_memset(&((silk_decoder *)decState)->sStereo, 0, ++ sizeof(((silk_decoder *)decState)->sStereo)); ++ /* Not strictly needed, but it's cleaner that way */ ++ ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; + } + +]]> +
    + + This change affects the normative output of the decoder, but the + amount of change is within the tolerance and too small to make the testvector check fail. + +
    + +
    + It was discovered that some invalid packets of very large size could trigger + an out-of-bounds read in the Opus packet parsing code responsible for padding. + This is due to an integer overflow if the signaled padding exceeds 2^31-1 bytes + (the actual packet may be smaller). The code can be fixed by decrementing the + (signed) len value, instead of incrementing a separate padding counter. + This is done by applying the following changes at line 596 of src/opus_decoder.c: + +
    + + /* Padding flag is bit 6 */ + if (ch&0x40) + { +- int padding=0; + int p; + do { + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; +- padding += p==255 ? 254: p; ++ len -= p==255 ? 254: p; + } while (p==255); +- len -= padding; + } + +]]> +
    + This packet parsing issue is limited to reading memory up + to about 60 kB beyond the compressed buffer. This can only be triggered + by a compressed packet more than about 16 MB long, so it's not a problem + for RTP. In theory, it could crash a file + decoder (e.g. Opus in Ogg) if the memory just after the incoming packet + is out-of-range, but our attempts to trigger such a crash in a production + application built using an affected version of the Opus decoder failed. +
    + +
    + The SILK resampler had the following issues: + + The calls to memcpy() were using sizeof(opus_int32), but the type of the + local buffer was opus_int16. + Because the size was wrong, this potentially allowed the source + and destination regions of the memcpy() to overlap on the copy from "buf" to "buf". + We believe that nSamplesIn (number of input samples) is at least fs_in_khZ (sampling rate in kHz), + which is at least 8. + Since RESAMPLER_ORDER_FIR_12 is only 8, that should not be a problem once + the type size is fixed. + The size of the buffer used RESAMPLER_MAX_BATCH_SIZE_IN, but the + data stored in it was actually twice the input batch size + (nSamplesIn<<1). + + The code can be fixed by applying the following changes to line 78 of silk/resampler_private_IIR_FIR.c: + +
    + + ) + { + silk_resampler_state_struct *S = \ +(silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; +- opus_int16 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + \ +RESAMPLER_ORDER_FIR_12 ]; ++ opus_int16 buf[ 2*RESAMPLER_MAX_BATCH_SIZE_IN + \ +RESAMPLER_ORDER_FIR_12 ]; + + /* Copy buffered samples to start of buffer */ +- silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 \ +* sizeof( opus_int32 ) ); ++ silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 \ +* sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ \ +RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 \ +); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL( out, \ +buf, max_index_Q16, index_increment_Q16 ); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of \ +filtered signal to beginning of buffer */ +- silk_memcpy( buf, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memmove( buf, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for \ +the next call */ +- silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } + +]]> +
    +
    + +
    + + It was discovered through decoder fuzzing that some bitstreams could produce + integer values exceeding 32-bits in LPC_inverse_pred_gain_QA(), causing + a wrap-around. The C standard considers + this behavior as undefined. The following patch to line 87 of silk/LPC_inv_pred_gain.c + detects values that do not fit in a 32-bit integer and considers the corresponding filters unstable: + +
    + + /* Update AR coefficient */ + for( n = 0; n < k; n++ ) { +- tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( \ +Aold_QA[ k - n - 1 ], rc_Q31, 31 ); +- Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q ); ++ opus_int64 tmp64; ++ tmp_QA = silk_SUB_SAT32( Aold_QA[ n ], MUL32_FRAC_Q( \ +Aold_QA[ k - n - 1 ], rc_Q31, 31 ) ); ++ tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( tmp_QA, \ +rc_mult2 ), mult2Q); ++ if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { ++ return 0; ++ } ++ Anew_QA[ n ] = ( opus_int32 )tmp64; + } + +]]> +
    +
    + +
    + + It was discovered -- also from decoder fuzzing -- that an integer wrap-around could + occur when decoding bitstreams with extremely large values for the high LSF parameters. + The end result of the wrap-around is an illegal read access on the stack, which + the authors do not believe is exploitable but should nonetheless be fixed. The following + patch to line 137 of silk/NLSF_stabilize.c prevents the problem: + +
    + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) +- NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], \ +NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); ++ NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], \ +silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + +]]> +
    + +
    + +
    + On extreme bit-streams, it is possible for log-domain band energy levels + to exceed the maximum single-precision floating point value once converted + to a linear scale. This would later cause the decoded values to be NaN (not a number), + possibly causing problems in the software using the PCM values. This can be + avoided with the following patch to line 552 of celt/quant_bands.c: + +
    + + { + opus_val16 lg = ADD16(oldEBands[i+c*m->nbEBands], + SHL16((opus_val16)eMeans[i],6)); ++ lg = MIN32(QCONST32(32.f, 16), lg); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) + +]]> +
    +
    + +
    + When encoding in hybrid mode at low bitrate, we sometimes only have + enough bits to code a single CELT band (8 - 9.6 kHz). When that happens, + the second band (CELT band 18, from 9.6 to 12 kHz) cannot use folding + because it is wider than the amount already coded, and falls back to + white noise. Because it can also happen on transients (e.g. stops), it + can cause audible pre-echo. + + + To address the issue, we change the folding behavior so that it is + never forced to fall back to LCG due to the first band not containing + enough coefficients to fold onto the second band. This + is achieved by simply repeating part of the first band in the folding + of the second band. This changes the code in celt/bands.c around line 1237: + +
    + + b = 0; + } + +- if (resynth && M*eBands[i]-N >= M*eBands[start] && \ +(update_lowband || lowband_offset==0)) ++ if (resynth && (M*eBands[i]-N >= M*eBands[start] || \ +i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + ++ if (i == start+1) ++ { ++ int n1, n2; ++ int offset; ++ n1 = M*(eBands[start+1]-eBands[start]); ++ n2 = M*(eBands[start+2]-eBands[start+1]); ++ offset = M*eBands[start]; ++ /* Duplicate enough of the first band folding data to \ +be able to fold the second band. ++ Copies no data for CELT-only mode. */ ++ OPUS_COPY(&norm[offset+n1], &norm[offset+2*n1 - n2], n2-n1); ++ if (C==2) ++ OPUS_COPY(&norm2[offset+n1], &norm2[offset+2*n1 - n2], \ +n2-n1); ++ } ++ + tf_change = tf_res[i]; + if (i>=m->effEBands) + { + +]]> +
    + + + as well as line 1260: + + +
    + + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; +- while(M*eBands[++fold_end] < effective_lowband+N); ++ while(++fold_end < i && M*eBands[fold_end] < \ +effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + + +]]> +
    + + The fix does not impact compatibility, because the improvement does + not depend on the encoder doing anything special. There is also no + reasonable way for an encoder to use the original behavior to + improve quality over the proposed change. + +
    + +
    + The last issue is not strictly a bug, but it is an issue that has been reported + when downmixing an Opus decoded stream to mono, whether this is done inside the decoder + or as a post-processing step on the stereo decoder output. Opus intensity stereo allows + optionally coding the two channels 180-degrees out of phase on a per-band basis. + This provides better stereo quality than forcing the two channels to be in phase, + but when the output is downmixed to mono, the energy in the affected bands is cancelled + sometimes resulting in audible artifacts. + + As a work-around for this issue, the decoder MAY choose not to apply the 180-degree + phase shift. This can be useful when downmixing to mono inside or + outside of the decoder (e.g. user-controllable). + +
    + + +
    + Changes in and have + sufficient impact on the testvectors to make them fail. For this reason, + this document also updates the Opus test vectors. The new test vectors now + include two decoded outputs for the same bitstream. The outputs with + suffix 'm' do not apply the CELT 180-degree phase shift as allowed in + , while the outputs without the suffix do. An + implementation is compliant as long as it passes either set of vectors. + + + Any Opus implementation + that passes either the original test vectors from RFC 6716 + or one of the new sets of test vectors is compliant with the Opus specification. However, newer implementations + SHOULD be based on the new test vectors rather than the old ones. + + The new test vectors are located at + . + The SHA-1 hashes of the test vectors are: +
    + + + +
    + Note that the decoder input bitstream files (.bit) are unchanged. +
    +
    + +
    + This document fixes two security issues reported on Opus and that affect the + reference implementation in RFC 6716: CVE-2013-0899 + + and CVE-2017-0381 . + CVE- 2013-0899 theoretically could have caused an information leak. The leaked + information would have gone through the decoder process before being accessible + to the attacker. It is fixed by . + CVE-2017-0381 could have resulted in a 16-bit out-of-bounds read from a fixed + location. It is fixed in . + Beyond the two fixed CVEs, this document adds no new security considerations on top of + RFC 6716. + +
    + +
    + This document makes no request of IANA. + + Note to RFC Editor: this section may be removed on publication as an + RFC. +
    + +
    + We would like to thank Juri Aedla for reporting the issue with the parsing of + the Opus padding. Thanks to Felicia Lim for reporting the LSF integer overflow issue. + Also, thanks to Tina le Grand, Jonathan Lennox, and Mark Harris for their + feedback on this document. +
    +
    + + + + + + + + + +
    diff --git a/native/codec/libraries/opus/doc/draft-ietf-codec-opus.xml b/native/codec/libraries/opus/doc/draft-ietf-codec-opus.xml new file mode 100644 index 0000000..334cad9 --- /dev/null +++ b/native/codec/libraries/opus/doc/draft-ietf-codec-opus.xml @@ -0,0 +1,8276 @@ + + + + + + + +Definition of the Opus Audio Codec + + + +Mozilla Corporation +
    + +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +jmvalin@jmvalin.ca +
    +
    + + +Skype Technologies S.A. +
    + +Soder Malarstrand 43 +Stockholm + +11825 +SE + ++46 73 085 7619 +koen.vos@skype.net +
    +
    + + +Mozilla Corporation +
    + +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +tterriberry@mozilla.com +
    +
    + + + +General + + + + + +This document defines the Opus interactive speech and audio codec. +Opus is designed to handle a wide range of interactive audio applications, + including Voice over IP, videoconferencing, in-game chat, and even live, + distributed music performances. +It scales from low bitrate narrowband speech at 6 kb/s to very high quality + stereo music at 510 kb/s. +Opus uses both linear prediction (LP) and the Modified Discrete Cosine + Transform (MDCT) to achieve good compression of both speech and music. + + +
    + + + +
    + +The Opus codec is a real-time interactive audio codec designed to meet the requirements +described in . +It is composed of a linear + prediction (LP)-based layer and a Modified Discrete Cosine Transform + (MDCT)-based layer. +The main idea behind using two layers is that in speech, linear prediction + techniques (such as Code-Excited Linear Prediction, or CELP) code low frequencies more efficiently than transform + (e.g., MDCT) domain techniques, while the situation is reversed for music and + higher speech frequencies. +Thus a codec with both layers available can operate over a wider range than + either one alone and, by combining them, achieve better quality than either + one individually. + + + +The primary normative part of this specification is provided by the source code + in . +Only the decoder portion of this software is normative, though a + significant amount of code is shared by both the encoder and decoder. + provides a decoder conformance test. +The decoder contains a great deal of integer and fixed-point arithmetic which + needs to be performed exactly, including all rounding considerations, so any + useful specification requires domain-specific symbolic language to adequately + define these operations. +Additionally, any +conflict between the symbolic representation and the included reference +implementation must be resolved. For the practical reasons of compatibility and +testability it would be advantageous to give the reference implementation +priority in any disagreement. The C language is also one of the most +widely understood human-readable symbolic representations for machine +behavior. +For these reasons this RFC uses the reference implementation as the sole + symbolic representation of the codec. + + +While the symbolic representation is unambiguous and complete it is not +always the easiest way to understand the codec's operation. For this reason +this document also describes significant parts of the codec in English and +takes the opportunity to explain the rationale behind many of the more +surprising elements of the design. These descriptions are intended to be +accurate and informative, but the limitations of common English sometimes +result in ambiguity, so it is expected that the reader will always read +them alongside the symbolic representation. Numerous references to the +implementation are provided for this purpose. The descriptions sometimes +differ from the reference in ordering or through mathematical simplification +wherever such deviation makes an explanation easier to understand. +For example, the right shift and left shift operations in the reference +implementation are often described using division and multiplication in the text. +In general, the text is focused on the "what" and "why" while the symbolic +representation most clearly provides the "how". + + +
    + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", + "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be + interpreted as described in RFC 2119 . + + +Various operations in the codec require bit-exact fixed-point behavior, even + when writing a floating point implementation. +The notation "Q<n>", where n is an integer, denotes the number of binary + digits to the right of the decimal point in a fixed-point number. +For example, a signed Q14 value in a 16-bit word can represent values from + -2.0 to 1.99993896484375, inclusive. +This notation is for informational purposes only. +Arithmetic, when described, always operates on the underlying integer. +E.g., the text will explicitly indicate any shifts required after a + multiplication. + + +Expressions, where included in the text, follow C operator rules and + precedence, with the exception that the syntax "x**y" indicates x raised to + the power y. +The text also makes use of the following functions: + + +
    + +The smallest of two values x and y. + +
    + +
    + +The largest of two values x and y. + +
    + +
    +
    + +
    + +With this definition, if lo > hi, the lower bound is the one that + is enforced. + +
    + +
    + +The sign of x, i.e., +
    + 0 . +]]> +
    +
    +
    + +
    + +The absolute value of x, i.e., +
    + +
    +
    +
    + +
    + +The largest integer z such that z <= f. + +
    + +
    + +The smallest integer z such that z >= f. + +
    + +
    + +The integer z nearest to f, with ties rounded towards negative infinity, + i.e., +
    + +
    +
    +
    + +
    + +The base-two logarithm of f. + +
    + +
    + +The minimum number of bits required to store a positive integer n in two's + complement notation, or 0 for a non-positive integer n. +
    + 0 +]]> +
    +Examples: + +ilog(-1) = 0 +ilog(0) = 0 +ilog(1) = 1 +ilog(2) = 2 +ilog(3) = 2 +ilog(4) = 3 +ilog(7) = 3 + +
    +
    + +
    + +
    + +
    + + +The Opus codec scales from 6 kb/s narrowband mono speech to 510 kb/s + fullband stereo music, with algorithmic delays ranging from 5 ms to + 65.2 ms. +At any given time, either the LP layer, the MDCT layer, or both, may be active. +It can seamlessly switch between all of its various operating modes, giving it + a great deal of flexibility to adapt to varying content and network + conditions without renegotiating the current session. +The codec allows input and output of various audio bandwidths, defined as + follows: + + +Abbreviation +Audio Bandwidth +Sample Rate (Effective) +NB (narrowband) 4 kHz 8 kHz +MB (medium-band) 6 kHz 12 kHz +WB (wideband) 8 kHz 16 kHz +SWB (super-wideband) 12 kHz 24 kHz +FB (fullband) 20 kHz (*) 48 kHz + + +(*) Although the sampling theorem allows a bandwidth as large as half the + sampling rate, Opus never codes audio above 20 kHz, as that is the + generally accepted upper limit of human hearing. + + + +Opus defines super-wideband (SWB) with an effective sample rate of 24 kHz, + unlike some other audio coding standards that use 32 kHz. +This was chosen for a number of reasons. +The band layout in the MDCT layer naturally allows skipping coefficients for + frequencies over 12 kHz, but does not allow cleanly dropping just those + frequencies over 16 kHz. +A sample rate of 24 kHz also makes resampling in the MDCT layer easier, + as 24 evenly divides 48, and when 24 kHz is sufficient, it can save + computation in other processing, such as Acoustic Echo Cancellation (AEC). +Experimental changes to the band layout to allow a 16 kHz cutoff + (32 kHz effective sample rate) showed potential quality degradations at + other sample rates, and at typical bitrates the number of bits saved by using + such a cutoff instead of coding in fullband (FB) mode is very small. +Therefore, if an application wishes to process a signal sampled at 32 kHz, + it should just use FB. + + + +The LP layer is based on the SILK codec + . +It supports NB, MB, or WB audio and frame sizes from 10 ms to 60 ms, + and requires an additional 5 ms look-ahead for noise shaping estimation. +A small additional delay (up to 1.5 ms) may be required for sampling rate + conversion. +Like Vorbis and many other modern codecs, SILK is inherently designed for + variable-bitrate (VBR) coding, though the encoder can also produce + constant-bitrate (CBR) streams. +The version of SILK used in Opus is substantially modified from, and not + compatible with, the stand-alone SILK codec previously deployed by Skype. +This document does not serve to define that format, but those interested in the + original SILK codec should see instead. + + + +The MDCT layer is based on the CELT codec . +It supports NB, WB, SWB, or FB audio and frame sizes from 2.5 ms to + 20 ms, and requires an additional 2.5 ms look-ahead due to the + overlapping MDCT windows. +The CELT codec is inherently designed for CBR coding, but unlike many CBR + codecs it is not limited to a set of predetermined rates. +It internally allocates bits to exactly fill any given target budget, and an + encoder can produce a VBR stream by varying the target on a per-frame basis. +The MDCT layer is not used for speech when the audio bandwidth is WB or less, + as it is not useful there. +On the other hand, non-speech signals are not always adequately coded using + linear prediction, so for music only the MDCT layer should be used. + + + +A "Hybrid" mode allows the use of both layers simultaneously with a frame size + of 10 or 20 ms and a SWB or FB audio bandwidth. +The LP layer codes the low frequencies by resampling the signal down to WB. +The MDCT layer follows, coding the high frequency portion of the signal. +The cutoff between the two lies at 8 kHz, the maximum WB audio bandwidth. +In the MDCT layer, all bands below 8 kHz are discarded, so there is no + coding redundancy between the two layers. + + + +The sample rate (in contrast to the actual audio bandwidth) can be chosen + independently on the encoder and decoder side, e.g., a fullband signal can be + decoded as wideband, or vice versa. +This approach ensures a sender and receiver can always interoperate, regardless + of the capabilities of their actual audio hardware. +Internally, the LP layer always operates at a sample rate of twice the audio + bandwidth, up to a maximum of 16 kHz, which it continues to use for SWB + and FB. +The decoder simply resamples its output to support different sample rates. +The MDCT layer always operates internally at a sample rate of 48 kHz. +Since all the supported sample rates evenly divide this rate, and since the + the decoder may easily zero out the high frequency portion of the spectrum in + the frequency domain, it can simply decimate the MDCT layer output to achieve + the other supported sample rates very cheaply. + + + +After conversion to the common, desired output sample rate, the decoder simply + adds the output from the two layers together. +To compensate for the different look-ahead required by each layer, the CELT + encoder input is delayed by an additional 2.7 ms. +This ensures that low frequencies and high frequencies arrive at the same time. +This extra delay may be reduced by an encoder by using less look-ahead for noise + shaping or using a simpler resampler in the LP layer, but this will reduce + quality. +However, the base 2.5 ms look-ahead in the CELT layer cannot be reduced in + the encoder because it is needed for the MDCT overlap, whose size is fixed by + the decoder. + + + +Both layers use the same entropy coder, avoiding any waste from "padding bits" + between them. +The hybrid approach makes it easy to support both CBR and VBR coding. +Although the LP layer is VBR, the bit allocation of the MDCT layer can produce + a final stream that is CBR by using all the bits left unused by the LP layer. + + +
    + +The Opus codec includes a number of control parameters which can be changed dynamically during +regular operation of the codec, without interrupting the audio stream from the encoder to the decoder. +These parameters only affect the encoder since any impact they have on the bit-stream is signaled +in-band such that a decoder can decode any Opus stream without any out-of-band signaling. Any Opus +implementation can add or modify these control parameters without affecting interoperability. The most +important encoder control parameters in the reference encoder are listed below. + + +
    + +Opus supports all bitrates from 6 kb/s to 510 kb/s. All other parameters being +equal, higher bitrate results in higher quality. For a frame size of 20 ms, these +are the bitrate "sweet spots" for Opus in various configurations: + +8-12 kb/s for NB speech, +16-20 kb/s for WB speech, +28-40 kb/s for FB speech, +48-64 kb/s for FB mono music, and +64-128 kb/s for FB stereo music. + + +
    + +
    + +Opus can transmit either mono or stereo frames within a single stream. +When decoding a mono frame in a stereo decoder, the left and right channels are + identical, and when decoding a stereo frame in a mono decoder, the mono output + is the average of the left and right channels. +In some cases, it is desirable to encode a stereo input stream in mono (e.g., + because the bitrate is too low to encode stereo with sufficient quality). +The number of channels encoded can be selected in real-time, but by default the + reference encoder attempts to make the best decision possible given the + current bitrate. + +
    + +
    + +The audio bandwidths supported by Opus are listed in + . +Just like for the number of channels, any decoder can decode audio encoded at + any bandwidth. +For example, any Opus decoder operating at 8 kHz can decode a FB Opus + frame, and any Opus decoder operating at 48 kHz can decode a NB frame. +Similarly, the reference encoder can take a 48 kHz input signal and + encode it as NB. +The higher the audio bandwidth, the higher the required bitrate to achieve + acceptable quality. +The audio bandwidth can be explicitly specified in real-time, but by default + the reference encoder attempts to make the best bandwidth decision possible + given the current bitrate. + +
    + + +
    + +Opus can encode frames of 2.5, 5, 10, 20, 40 or 60 ms. +It can also combine multiple frames into packets of up to 120 ms. +For real-time applications, sending fewer packets per second reduces the + bitrate, since it reduces the overhead from IP, UDP, and RTP headers. +However, it increases latency and sensitivity to packet losses, as losing one + packet constitutes a loss of a bigger chunk of audio. +Increasing the frame duration also slightly improves coding efficiency, but the + gain becomes small for frame sizes above 20 ms. +For this reason, 20 ms frames are a good choice for most applications. + +
    + +
    + +There are various aspects of the Opus encoding process where trade-offs +can be made between CPU complexity and quality/bitrate. In the reference +encoder, the complexity is selected using an integer from 0 to 10, where +0 is the lowest complexity and 10 is the highest. Examples of +computations for which such trade-offs may occur are: + +The order of the pitch analysis whitening filter , +The order of the short-term noise shaping filter, +The number of states in delayed decision quantization of the +residual signal, and +The use of certain bit-stream features such as variable time-frequency +resolution and the pitch post-filter. + + +
    + +
    + +Audio codecs often exploit inter-frame correlations to reduce the +bitrate at a cost in error propagation: after losing one packet +several packets need to be received before the decoder is able to +accurately reconstruct the speech signal. The extent to which Opus +exploits inter-frame dependencies can be adjusted on the fly to +choose a trade-off between bitrate and amount of error propagation. + +
    + +
    + + Another mechanism providing robustness against packet loss is the in-band + Forward Error Correction (FEC). Packets that are determined to + contain perceptually important speech information, such as onsets or + transients, are encoded again at a lower bitrate and this re-encoded + information is added to a subsequent packet. + +
    + +
    + +Opus is more efficient when operating with variable bitrate (VBR), which is +the default. However, in some (rare) applications, constant bitrate (CBR) +is required. There are two main reasons to operate in CBR mode: + +When the transport only supports a fixed size for each compressed frame +When encryption is used for an audio stream that is either highly constrained + (e.g. yes/no, recorded prompts) or highly sensitive + + +When low-latency transmission is required over a relatively slow connection, then +constrained VBR can also be used. This uses VBR in a way that simulates a +"bit reservoir" and is equivalent to what MP3 (MPEG 1, Layer 3) and +AAC (Advanced Audio Coding) call CBR (i.e., not true +CBR due to the bit reservoir). + +
    + +
    + + Discontinuous Transmission (DTX) reduces the bitrate during silence + or background noise. When DTX is enabled, only one frame is encoded + every 400 milliseconds. + +
    + +
    + +
    + +
    + + +The Opus encoder produces "packets", which are each a contiguous set of bytes + meant to be transmitted as a single unit. +The packets described here do not include such things as IP, UDP, or RTP + headers which are normally found in a transport-layer packet. +A single packet may contain multiple audio frames, so long as they share a + common set of parameters, including the operating mode, audio bandwidth, frame + size, and channel count (mono vs. stereo). +This section describes the possible combinations of these parameters and the + internal framing used to pack multiple frames into a single packet. +This framing is not self-delimiting. +Instead, it assumes that a higher layer (such as UDP or RTP +or Ogg or Matroska ) + will communicate the length, in bytes, of the packet, and it uses this + information to reduce the framing overhead in the packet itself. +A decoder implementation MUST support the framing described in this section. +An alternative, self-delimiting variant of the framing is described in + . +Support for that variant is OPTIONAL. + + + +All bit diagrams in this document number the bits so that bit 0 is the most + significant bit of the first byte, and bit 7 is the least significant. +Bit 8 is thus the most significant bit of the second byte, etc. +Well-formed Opus packets obey certain requirements, marked [R1] through [R7] + below. +These are summarized in along with + appropriate means of handling malformed packets. + + +
    + +A well-formed Opus packet MUST contain at least one byte [R1]. +This byte forms a table-of-contents (TOC) header that signals which of the + various modes and configurations a given packet uses. +It is composed of a configuration number, "config", a stereo flag, "s", and a + frame count code, "c", arranged as illustrated in + . +A description of each of these fields follows. + + +
    + +
    + + +The top five bits of the TOC byte, labeled "config", encode one of 32 possible + configurations of operating mode, audio bandwidth, and frame size. +As described, the LP (SILK) layer and MDCT (CELT) layer can be combined in three possible + operating modes: + +A SILK-only mode for use in low bitrate connections with an audio bandwidth + of WB or less, +A Hybrid (SILK+CELT) mode for SWB or FB speech at medium bitrates, and +A CELT-only mode for very low delay speech transmission as well as music + transmission (NB to FB). + +The 32 possible configurations each identify which one of these operating modes + the packet uses, as well as the audio bandwidth and the frame size. + lists the parameters for each configuration. + + +Configuration Number(s) +Mode +Bandwidth +Frame Sizes +0...3 SILK-only NB 10, 20, 40, 60 ms +4...7 SILK-only MB 10, 20, 40, 60 ms +8...11 SILK-only WB 10, 20, 40, 60 ms +12...13 Hybrid SWB 10, 20 ms +14...15 Hybrid FB 10, 20 ms +16...19 CELT-only NB 2.5, 5, 10, 20 ms +20...23 CELT-only WB 2.5, 5, 10, 20 ms +24...27 CELT-only SWB 2.5, 5, 10, 20 ms +28...31 CELT-only FB 2.5, 5, 10, 20 ms + + +The configuration numbers in each range (e.g., 0...3 for NB SILK-only) + correspond to the various choices of frame size, in the same order. +For example, configuration 0 has a 10 ms frame size and configuration 3 + has a 60 ms frame size. + + + +One additional bit, labeled "s", signals mono vs. stereo, with 0 indicating + mono and 1 indicating stereo. + + + +The remaining two bits of the TOC byte, labeled "c", code the number of frames + per packet (codes 0 to 3) as follows: + +0: 1 frame in the packet +1: 2 frames in the packet, each with equal compressed size +2: 2 frames in the packet, with different compressed sizes +3: an arbitrary number of frames in the packet + +This draft refers to a packet as a code 0 packet, code 1 packet, etc., based on + the value of "c". + + +
    + +
    + + +This section describes how frames are packed according to each possible value + of "c" in the TOC byte. + + +
    + +When a packet contains multiple VBR frames (i.e., code 2 or 3), the compressed + length of one or more of these frames is indicated with a one- or two-byte + sequence, with the meaning of the first byte as follows: + +0: No frame (discontinuous transmission (DTX) or lost packet) +1...251: Length of the frame in bytes +252...255: A second byte is needed. The total length is (second_byte*4)+first_byte + + + + +The special length 0 indicates that no frame is available, either because it + was dropped during transmission by some intermediary or because the encoder + chose not to transmit it. +Any Opus frame in any mode MAY have a length of 0. + + + +The maximum representable length is 255*4+255=1275 bytes. +For 20 ms frames, this represents a bitrate of 510 kb/s, which is + approximately the highest useful rate for lossily compressed fullband stereo + music. +Beyond this point, lossless codecs are more appropriate. +It is also roughly the maximum useful rate of the MDCT layer, as shortly + thereafter quality no longer improves with additional bits due to limitations + on the codebook sizes. + + + +No length is transmitted for the last frame in a VBR packet, or for any of the + frames in a CBR packet, as it can be inferred from the total size of the + packet and the size of all other data in the packet. +However, the length of any individual frame MUST NOT exceed + 1275 bytes [R2], to allow for repacketization by gateways, + conference bridges, or other software. + +
    + +
    + + +For code 0 packets, the TOC byte is immediately followed by N-1 bytes + of compressed data for a single frame (where N is the size of the packet), + as illustrated in . + +
    + +
    +
    + +
    + +For code 1 packets, the TOC byte is immediately followed by the + (N-1)/2 bytes of compressed data for the first frame, followed by + (N-1)/2 bytes of compressed data for the second frame, as illustrated in + . +The number of payload bytes available for compressed data, N-1, MUST be even + for all code 1 packets [R3]. + +
    + +
    +
    + +
    + +For code 2 packets, the TOC byte is followed by a one- or two-byte sequence + indicating the length of the first frame (marked N1 in ), + followed by N1 bytes of compressed data for the first frame. +The remaining N-N1-2 or N-N1-3 bytes are the compressed data for the + second frame. +This is illustrated in . +A code 2 packet MUST contain enough bytes to represent a valid length. +For example, a 1-byte code 2 packet is always invalid, and a 2-byte code 2 + packet whose second byte is in the range 252...255 is also invalid. +The length of the first frame, N1, MUST also be no larger than the size of the + payload remaining after decoding that length for all code 2 packets [R4]. +This makes, for example, a 2-byte code 2 packet with a second byte in the range + 1...251 invalid as well (the only valid 2-byte code 2 packet is one where the + length of both frames is zero). + +
    + +
    +
    + +
    + +Code 3 packets signal the number of frames, as well as additional + padding, called "Opus padding" to indicate that this padding is added at the + Opus layer, rather than at the transport layer. +Code 3 packets MUST have at least 2 bytes [R6,R7]. +The TOC byte is followed by a byte encoding the number of frames in the packet + in bits 2 to 7 (marked "M" in ), with bit 1 indicating whether + or not Opus padding is inserted (marked "p" in ), and bit 0 + indicating VBR (marked "v" in ). +M MUST NOT be zero, and the audio duration contained within a packet MUST NOT + exceed 120 ms [R5]. +This limits the maximum frame count for any frame size to 48 (for 2.5 ms + frames), with lower limits for longer frame sizes. + illustrates the layout of the frame count + byte. + +
    + +
    + +When Opus padding is used, the number of bytes of padding is encoded in the + bytes following the frame count byte. +Values from 0...254 indicate that 0...254 bytes of padding are included, + in addition to the byte(s) used to indicate the size of the padding. +If the value is 255, then the size of the additional padding is 254 bytes, + plus the padding value encoded in the next byte. +There MUST be at least one more byte in the packet in this case [R6,R7]. +The additional padding bytes appear at the end of the packet, and MUST be set + to zero by the encoder to avoid creating a covert channel. +The decoder MUST accept any value for the padding bytes, however. + + +Although this encoding provides multiple ways to indicate a given number of + padding bytes, each uses a different number of bytes to indicate the padding + size, and thus will increase the total packet size by a different amount. +For example, to add 255 bytes to a packet, set the padding bit, p, to 1, insert + a single byte after the frame count byte with a value of 254, and append 254 + padding bytes with the value zero to the end of the packet. +To add 256 bytes to a packet, set the padding bit to 1, insert two bytes after + the frame count byte with the values 255 and 0, respectively, and append 254 + padding bytes with the value zero to the end of the packet. +By using the value 255 multiple times, it is possible to create a packet of any + specific, desired size. +Let P be the number of header bytes used to indicate the padding size plus the + number of padding bytes themselves (i.e., P is the total number of bytes added + to the packet). +Then P MUST be no more than N-2 [R6,R7]. + + +In the CBR case, let R=N-2-P be the number of bytes remaining in the packet + after subtracting the (optional) padding. +Then the compressed length of each frame in bytes is equal to R/M. +The value R MUST be a non-negative integer multiple of M [R6]. +The compressed data for all M frames follows, each of size + R/M bytes, as illustrated in . + + +
    + +
    + + +In the VBR case, the (optional) padding length is followed by M-1 frame + lengths (indicated by "N1" to "N[M-1]" in ), each encoded in a + one- or two-byte sequence as described above. +The packet MUST contain enough data for the M-1 lengths after removing the + (optional) padding, and the sum of these lengths MUST be no larger than the + number of bytes remaining in the packet after decoding them [R7]. +The compressed data for all M frames follows, each frame consisting of the + indicated number of bytes, with the final frame consuming any remaining bytes + before the final padding, as illustrated in . +The number of header bytes (TOC byte, frame count byte, padding length bytes, + and frame length bytes), plus the signaled length of the first M-1 frames themselves, + plus the signaled length of the padding MUST be no larger than N, the total size of the + packet. + + +
    + +
    +
    +
    + +
    + +Simplest case, one NB mono 20 ms SILK frame: + + +
    + +
    + + +Two FB mono 5 ms CELT frames of the same compressed size: + + +
    + +
    + + +Two FB mono 20 ms Hybrid frames of different compressed size: + + +
    + +
    + + +Four FB stereo 20 ms CELT frames of the same compressed size: + + +
    + +
    +
    + +
    + +A receiver MUST NOT process packets which violate any of the rules above as + normal Opus packets. +They are reserved for future applications, such as in-band headers (containing + metadata, etc.). +Packets which violate these constraints may cause implementations of + this specification to treat them as malformed, and + discard them. + + +These constraints are summarized here for reference: + +Packets are at least one byte. +No implicit frame length is larger than 1275 bytes. +Code 1 packets have an odd total length, N, so that (N-1)/2 is an + integer. +Code 2 packets have enough bytes after the TOC for a valid frame + length, and that length is no larger than the number of bytes remaining in the + packet. +Code 3 packets contain at least one frame, but no more than 120 ms + of audio total. +The length of a CBR code 3 packet, N, is at least two bytes, the number of + bytes added to indicate the padding size plus the trailing padding bytes + themselves, P, is no more than N-2, and the frame count, M, satisfies + the constraint that (N-2-P) is a non-negative integer multiple of M. +VBR code 3 packets are large enough to contain all the header bytes (TOC + byte, frame count byte, any padding length bytes, and any frame length bytes), + plus the length of the first M-1 frames, plus any trailing padding bytes. + + +
    + +
    + +
    + +The Opus decoder consists of two main blocks: the SILK decoder and the CELT + decoder. +At any given time, one or both of the SILK and CELT decoders may be active. +The output of the Opus decode is the sum of the outputs from the SILK and CELT + decoders with proper sample rate conversion and delay compensation on the SILK + side, and optional decimation (when decoding to sample rates less than + 48 kHz) on the CELT side, as illustrated in the block diagram below. + +
    + +| Decoder |--->| Rate |----+ +Bit- +---------+ | | | | Conversion | v +stream | Range |---+ +---------+ +------------+ /---\ Audio +------->| Decoder | | + |------> + | |---+ +---------+ +------------+ \---/ + +---------+ | | CELT | | Decimation | ^ + +->| Decoder |--->| (Optional) |----+ + | | | | + +---------+ +------------+ +]]> + +
    + +
    + +Opus uses an entropy coder based on range coding +, +which is itself a rediscovery of the FIFO arithmetic code introduced by . +It is very similar to arithmetic encoding, except that encoding is done with +digits in any base instead of with bits, +so it is faster when using larger bases (i.e., a byte). All of the +calculations in the range coder must use bit-exact integer arithmetic. + + +Symbols may also be coded as "raw bits" packed directly into the bitstream, + bypassing the range coder. +These are packed backwards starting at the end of the frame, as illustrated in + . +This reduces complexity and makes the stream more resilient to bit errors, as + corruption in the raw bits will not desynchronize the decoding process, unlike + corruption in the input to the range decoder. +Raw bits are only used in the CELT layer. + + +
    + : ++ + +: : ++ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +: | <- Boundary occurs at an arbitrary bit position : ++-+-+-+ + +: <- Raw bits data (packed LSB to MSB) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +]]> +
    + + +Each symbol coded by the range coder is drawn from a finite alphabet and coded + in a separate "context", which describes the size of the alphabet and the + relative frequency of each symbol in that alphabet. + + +Suppose there is a context with n symbols, identified with an index that ranges + from 0 to n-1. +The parameters needed to encode or decode symbol k in this context are + represented by a three-tuple (fl[k], fh[k], ft), with + 0 <= fl[k] < fh[k] <= ft <= 65535. +The values of this tuple are derived from the probability model for the + symbol, represented by traditional "frequency counts". +Because Opus uses static contexts these are not updated as symbols are decoded. +Let f[i] be the frequency of symbol i. +Then the three-tuple corresponding to symbol k is given by + +
    + +
    + +The range decoder extracts the symbols and integers encoded using the range + encoder in . +The range decoder maintains an internal state vector composed of the two-tuple + (val, rng), representing the difference between the high end of the + current range and the actual coded value, minus one, and the size of the + current range, respectively. +Both val and rng are 32-bit unsigned integer values. + + +
    + +Let b0 be the first input byte (or zero if there are no bytes in this Opus + frame). +The decoder initializes rng to 128 and initializes val to + (127 - (b0>>1)), where (b0>>1) is the top 7 bits of the + first input byte. +It saves the remaining bit, (b0&1), for use in the renormalization + procedure described in , which the + decoder invokes immediately after initialization to read additional bits and + establish the invariant that rng > 2**23. + +
    + +
    + +Decoding a symbol is a two-step process. +The first step determines a 16-bit unsigned value fs, which lies within the + range of some symbol in the current context. +The second step updates the range decoder state with the three-tuple + (fl[k], fh[k], ft) corresponding to that symbol. + + +The first step is implemented by ec_decode() (entdec.c), which computes +
    + +
    +The divisions here are integer division. +
    + +The decoder then identifies the symbol in the current context corresponding to + fs; i.e., the value of k whose three-tuple (fl[k], fh[k], ft) + satisfies fl[k] <= fs < fh[k]. +It uses this tuple to update val according to +
    + +
    +If fl[k] is greater than zero, then the decoder updates rng using +
    + +
    +Otherwise, it updates rng using +
    + +
    +
    + +Using a special case for the first symbol (rather than the last symbol, as is + commonly done in other arithmetic coders) ensures that all the truncation + error from the finite precision arithmetic accumulates in symbol 0. +This makes the cost of coding a 0 slightly smaller, on average, than its + estimated probability indicates and makes the cost of coding any other symbol + slightly larger. +When contexts are designed so that 0 is the most probable symbol, which is + often the case, this strategy minimizes the inefficiency introduced by the + finite precision. +It also makes some of the special-case decoding routines in + particularly simple. + + +After the updates, implemented by ec_dec_update() (entdec.c), the decoder + normalizes the range using the procedure in the next section, and returns the + index k. + + +
    + +To normalize the range, the decoder repeats the following process, implemented + by ec_dec_normalize() (entdec.c), until rng > 2**23. +If rng is already greater than 2**23, the entire process is skipped. +First, it sets rng to (rng<<8). +Then it reads the next byte of the Opus frame and forms an 8-bit value sym, + using the left-over bit buffered from the previous byte as the high bit + and the top 7 bits of the byte just read as the other 7 bits of sym. +The remaining bit in the byte just read is buffered for use in the next + iteration. +If no more input bytes remain, it uses zero bits instead. +See for the initialization used to process + the first byte. +Then, it sets +
    + +
    +
    + +It is normal and expected that the range decoder will read several bytes + into the raw bits data (if any) at the end of the packet by the time the frame + is completely decoded, as illustrated in . +This same data MUST also be returned as raw bits when requested. +The encoder is expected to terminate the stream in such a way that the decoder + will decode the intended values regardless of the data contained in the raw + bits. + describes a procedure for doing this. +If the range decoder consumes all of the bytes belonging to the current frame, + it MUST continue to use zero when any further input bytes are required, even + if there is additional data in the current packet from padding or other + frames. + + +
    + | : ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ^ ^ + | End of data buffered by the range coder | +...-----------------------------------------------+ + | + | End of data consumed by raw bits + +-------------------------------------------------------... +]]> +
    +
    +
    + +
    + +The reference implementation uses three additional decoding methods that are + exactly equivalent to the above, but make assumptions and simplifications that + allow for a more efficient implementation. + +
    + +The first is ec_decode_bin() (entdec.c), defined using the parameter ftb + instead of ft. +It is mathematically equivalent to calling ec_decode() with + ft = (1<<ftb), but avoids one of the divisions. + +
    +
    + +The next is ec_dec_bit_logp() (entdec.c), which decodes a single binary symbol, + replacing both the ec_decode() and ec_dec_update() steps. +The context is described by a single parameter, logp, which is the absolute + value of the base-2 logarithm of the probability of a "1". +It is mathematically equivalent to calling ec_decode() with + ft = (1<<logp), followed by ec_dec_update() with + the 3-tuple (fl[k] = 0, + fh[k] = (1<<logp) - 1, + ft = (1<<logp)) if the returned value + of fs is less than (1<<logp) - 1 (a "0" was decoded), and with + (fl[k] = (1<<logp) - 1, + fh[k] = ft = (1<<logp)) otherwise (a "1" was + decoded). +The implementation requires no multiplications or divisions. + +
    +
    + +The last is ec_dec_icdf() (entdec.c), which decodes a single symbol with a + table-based context of up to 8 bits, also replacing both the ec_decode() and + ec_dec_update() steps, as well as the search for the decoded symbol in between. +The context is described by two parameters, an icdf + ("inverse" cumulative distribution function) table and ftb. +As with ec_decode_bin(), (1<<ftb) is equivalent to ft. +idcf[k], on the other hand, stores (1<<ftb)-fh[k], which is equal to + (1<<ftb) - fl[k+1]. +fl[0] is assumed to be 0, and the table is terminated by a value of 0 (where + fh[k] == ft). + + +The function is mathematically equivalent to calling ec_decode() with + ft = (1<<ftb), using the returned value fs to search the table + for the first entry where fs < (1<<ftb)-icdf[k], and + calling ec_dec_update() with + fl[k] = (1<<ftb) - icdf[k-1] (or 0 + if k == 0), fh[k] = (1<<ftb) - idcf[k], + and ft = (1<<ftb). +Combining the search with the update allows the division to be replaced by a + series of multiplications (which are usually much cheaper), and using an + inverse CDF allows the use of an ftb as large as 8 in an 8-bit table without + any special cases. +This is the primary interface with the range decoder in the SILK layer, though + it is used in a few places in the CELT layer as well. + + +Although icdf[k] is more convenient for the code, the frequency counts, f[k], + are a more natural representation of the probability distribution function + (PDF) for a given symbol. +Therefore this draft lists the latter, not the former, when describing the + context in which a symbol is coded as a list, e.g., {4, 4, 4, 4}/16 for a + uniform context with four possible values and ft = 16. +The value of ft after the slash is always the sum of the entries in the PDF, + but is included for convenience. +Contexts with identical probabilities, f[k]/ft, but different values of ft + (or equivalently, ftb) are not the same, and cannot, in general, be used in + place of one another. +An icdf table is also not capable of representing a PDF where the first symbol + has 0 probability. +In such contexts, ec_dec_icdf() can decode the symbol by using a table that + drops the entries for any initial zero-probability values and adding the + constant offset of the first value with a non-zero probability to its return + value. + +
    +
    + +
    + +The raw bits used by the CELT layer are packed at the end of the packet, with + the least significant bit of the first value packed in the least significant + bit of the last byte, filling up to the most significant bit in the last byte, + continuing on to the least significant bit of the penultimate byte, and so on. +The reference implementation reads them using ec_dec_bits() (entdec.c). +Because the range decoder must read several bytes ahead in the stream, as + described in , the input consumed by the + raw bits may overlap with the input consumed by the range coder, and a decoder + MUST allow this. +The format should render it impossible to attempt to read more raw bits than + there are actual bits in the frame, though a decoder may wish to check for + this and report an error. + +
    + +
    + +The function ec_dec_uint() (entdec.c) decodes one of ft equiprobable values in + the range 0 to (ft - 1), inclusive, each with a frequency of 1, + where ft may be as large as (2**32 - 1). +Because ec_decode() is limited to a total frequency of (2**16 - 1), + it splits up the value into a range coded symbol representing up to 8 of the + high bits, and, if necessary, raw bits representing the remainder of the + value. +The limit of 8 bits in the range coded symbol is a trade-off between + implementation complexity, modeling error (since the symbols no longer truly + have equal coding cost), and rounding error introduced by the range coder + itself (which gets larger as more bits are included). +Using raw bits reduces the maximum number of divisions required in the worst + case, but means that it may be possible to decode a value outside the range + 0 to (ft - 1), inclusive. + + + +ec_dec_uint() takes a single, positive parameter, ft, which is not necessarily + a power of two, and returns an integer, t, whose value lies between 0 and + (ft - 1), inclusive. +Let ftb = ilog(ft - 1), i.e., the number of bits required + to store (ft - 1) in two's complement notation. +If ftb is 8 or less, then t is decoded with t = ec_decode(ft), and + the range coder state is updated using the three-tuple (t, t + 1, + ft). + + +If ftb is greater than 8, then the top 8 bits of t are decoded using +
    +> (ftb - 8)) + 1) , +]]> +
    + the decoder state is updated using the three-tuple + (t, t + 1, + ((ft - 1) >> (ftb - 8)) + 1), + and the remaining bits are decoded as raw bits, setting +
    + +
    +If, at this point, t >= ft, then the current frame is corrupt. +In that case, the decoder should assume there has been an error in the coding, + decoding, or transmission and SHOULD take measures to conceal the + error and/or report to the application that the error has occurred. +
    + +
    + +
    + +The bit allocation routines in the CELT decoder need a conservative upper bound + on the number of bits that have been used from the current frame thus far, + including both range coder bits and raw bits. +This drives allocation decisions that must match those made in the encoder. +The upper bound is computed in the reference implementation to whole-bit + precision by the function ec_tell() (entcode.h) and to fractional 1/8th bit + precision by the function ec_tell_frac() (entcode.c). +Like all operations in the range coder, it must be implemented in a bit-exact + manner, and must produce exactly the same value returned by the same functions + in the encoder after encoding the same symbols. + + +ec_tell() is guaranteed to return ceil(ec_tell_frac()/8.0). +In various places the codec will check to ensure there is enough room to + contain a symbol before attempting to decode it. +In practice, although the number of bits used so far is an upper bound, + decoding a symbol whose probability model suggests it has a worst-case cost of + p 1/8th bits may actually advance the return value of ec_tell_frac() by + p-1, p, or p+1 1/8th bits, due to approximation error in that upper bound, + truncation error in the range coder, and for large values of ft, modeling + error in ec_dec_uint(). + + +However, this error is bounded, and periodic calls to ec_tell() or + ec_tell_frac() at precisely defined points in the decoding process prevent it + from accumulating. +For a range coder symbol that requires a whole number of bits (i.e., + for which ft/(fh[k] - fl[k]) is a power of two), where there are at + least p 1/8th bits available, decoding the symbol will never cause ec_tell() or + ec_tell_frac() to exceed the size of the frame ("bust the budget"). +In this case the return value of ec_tell_frac() will only advance by more than + p 1/8th bits if there was an additional, fractional number of bits remaining, + and it will never advance beyond the next whole-bit boundary, which is safe, + since frames always contain a whole number of bits. +However, when p is not a whole number of bits, an extra 1/8th bit is required + to ensure that decoding the symbol will not bust the budget. + + +The reference implementation keeps track of the total number of whole bits that + have been processed by the decoder so far in the variable nbits_total, + including the (possibly fractional) number of bits that are currently + buffered, but not consumed, inside the range coder. +nbits_total is initialized to 9 just before the initial range renormalization + process completes (or equivalently, it can be initialized to 33 after the + first renormalization). +The extra two bits over the actual amount buffered by the range coder + guarantees that it is an upper bound and that there is enough room for the + encoder to terminate the stream. +Each iteration through the range coder's renormalization loop increases + nbits_total by 8. +Reading raw bits increases nbits_total by the number of raw bits read. + + +
    + +The whole number of bits buffered in rng may be estimated via lg = ilog(rng). +ec_tell() then becomes a simple matter of removing these bits from the total. +It returns (nbits_total - lg). + + +In a newly initialized decoder, before any symbols have been read, this reports + that 1 bit has been used. +This is the bit reserved for termination of the encoder. + +
    + +
    + +ec_tell_frac() estimates the number of bits buffered in rng to fractional + precision. +Since rng must be greater than 2**23 after renormalization, lg must be at least + 24. +Let +
    + +> (lg-16) , +]]> +
    + so that 32768 <= r_Q15 < 65536, an unsigned Q15 value representing the + fractional part of rng. +Then the following procedure can be used to add one bit of precision to lg. +First, update +
    + +> 15 . +]]> +
    +Then add the 16th bit of r_Q15 to lg via +
    + +> 16) . +]]> +
    +Finally, if this bit was a 1, reduce r_Q15 by a factor of two via +
    + +> 1 , +]]> +
    + so that it once again lies in the range 32768 <= r_Q15 < 65536. +
    + +This procedure is repeated three times to extend lg to 1/8th bit precision. +ec_tell_frac() then returns (nbits_total*8 - lg). + +
    + +
    + +
    + +
    + +The decoder's LP layer uses a modified version of the SILK codec (herein simply + called "SILK"), which runs a decoded excitation signal through adaptive + long-term and short-term prediction synthesis filters. +It runs at NB, MB, and WB sample rates internally. +When used in a SWB or FB Hybrid frame, the LP layer itself still only runs in + WB. + + +
    + +An overview of the decoder is given in . + +
    + +| Range |--->| Decode |---------------------------+ + 1 | Decoder | 2 | Parameters |----------+ 5 | + +---------+ +------------+ 4 | | + 3 | | | + \/ \/ \/ + +------------+ +------------+ +------------+ + | Generate |-->| LTP |-->| LPC | + | Excitation | | Synthesis | | Synthesis | + +------------+ +------------+ +------------+ + ^ | + | | + +-------------------+----------------+ + | 6 + | +------------+ +-------------+ + +-->| Stereo |-->| Sample Rate |--> + | Unmixing | 7 | Conversion | 8 + +------------+ +-------------+ + +1: Range encoded bitstream +2: Coded parameters +3: Pulses, LSBs, and signs +4: Pitch lags, Long-Term Prediction (LTP) coefficients +5: Linear Predictive Coding (LPC) coefficients and gains +6: Decoded signal (mono or mid-side stereo) +7: Unmixed signal (mono or left-right stereo) +8: Resampled signal +]]> + +
    + + +The decoder feeds the bitstream (1) to the range decoder from + , and then decodes the parameters in it (2) + using the procedures detailed in + Sections  + through . +These parameters (3, 4, 5) are used to generate an excitation signal (see + ), which is fed to an optional + long-term prediction (LTP) filter (voiced frames only, see + ) and then a short-term prediction filter + (see ), producing the decoded signal (6). +For stereo streams, the mid-side representation is converted to separate left + and right channels (7). +The result is finally resampled to the desired output sample rate (e.g., + 48 kHz) so that the resampled signal (8) can be mixed with the CELT + layer. + + +
    + +
    + + +Internally, the LP layer of a single Opus frame is composed of either a single + 10 ms regular SILK frame or between one and three 20 ms regular SILK + frames. +A stereo Opus frame may double the number of regular SILK frames (up to a total + of six), since it includes separate frames for a mid channel and, optionally, + a side channel. +Optional Low Bit-Rate Redundancy (LBRR) frames, which are reduced-bitrate + encodings of previous SILK frames, may be included to aid in recovery from + packet loss. +If present, these appear before the regular SILK frames. +They are in most respects identical to regular, active SILK frames, except that + they are usually encoded with a lower bitrate. +This draft uses "SILK frame" to refer to either one and "regular SILK frame" if + it needs to draw a distinction between the two. + + +Logically, each SILK frame is in turn composed of either two or four 5 ms + subframes. +Various parameters, such as the quantization gain of the excitation and the + pitch lag and filter coefficients can vary on a subframe-by-subframe basis. +Physically, the parameters for each subframe are interleaved in the bitstream, + as described in the relevant sections for each parameter. + + +All of these frames and subframes are decoded from the same range coder, with + no padding between them. +Thus packing multiple SILK frames in a single Opus frame saves, on average, + half a byte per SILK frame. +It also allows some parameters to be predicted from prior SILK frames in the + same Opus frame, since this does not degrade packet loss robustness (beyond + any penalty for merely using fewer, larger packets to store multiple frames). + + + +Stereo support in SILK uses a variant of mid-side coding, allowing a mono + decoder to simply decode the mid channel. +However, the data for the two channels is interleaved, so a mono decoder must + still unpack the data for the side channel. +It would be required to do so anyway for Hybrid Opus frames, or to support + decoding individual 20 ms frames. + + + + summarizes the overall grouping of the contents of + the LP layer. +Figures  + and  illustrate + the ordering of the various SILK frames for a 60 ms Opus frame, for both + mono and stereo, respectively. + + + +Symbol(s) +PDF(s) +Condition + +Voice Activity Detection (VAD) flags +{1, 1}/2 + + +LBRR flag +{1, 1}/2 + + +Per-frame LBRR flags + + + +LBRR Frame(s) + + + +Regular SILK Frame(s) + + + + + +
    + +
    + +
    + +
    + +
    + +
    + +The LP layer begins with two to eight header bits, decoded in silk_Decode() + (dec_API.c). +These consist of one Voice Activity Detection (VAD) bit per frame (up to 3), + followed by a single flag indicating the presence of LBRR frames. +For a stereo packet, these first flags correspond to the mid channel, and a + second set of flags is included for the side channel. + + +Because these are the first symbols decoded by the range coder and because they + are coded as binary values with uniform probability, they can be extracted + directly from the most significant bits of the first byte of compressed data. +Thus, a receiver can determine if an Opus frame contains any active SILK frames + without the overhead of using the range decoder. + +
    + +
    + +For Opus frames longer than 20 ms, a set of LBRR flags is + decoded for each channel that has its LBRR flag set. +Each set contains one flag per 20 ms SILK frame. +40 ms Opus frames use the 2-frame LBRR flag PDF from + , and 60 ms Opus frames use the + 3-frame LBRR flag PDF. +For each channel, the resulting 2- or 3-bit integer contains the corresponding + LBRR flag for each frame, packed in order from the LSB to the MSB. + + + +Frame Size +PDF +40 ms {0, 53, 53, 150}/256 +60 ms {0, 41, 20, 29, 41, 15, 28, 82}/256 + + + +A 10 or 20 ms Opus frame does not contain any per-frame LBRR flags, + as there may be at most one LBRR frame per channel. +The global LBRR flag in the header bits (see ) + is already sufficient to indicate the presence of that single LBRR frame. + + +
    + +
    + +The LBRR frames, if present, contain an encoded representation of the signal + immediately prior to the current Opus frame as if it were encoded with the + current mode, frame size, audio bandwidth, and channel count, even if those + differ from the prior Opus frame. +When one of these parameters changes from one Opus frame to the next, this + implies that the LBRR frames of the current Opus frame may not be simple + drop-in replacements for the contents of the previous Opus frame. + + + +For example, when switching from 20 ms to 60 ms, the 60 ms Opus + frame may contain LBRR frames covering up to three prior 20 ms Opus + frames, even if those frames already contained LBRR frames covering some of + the same time periods. +When switching from 20 ms to 10 ms, the 10 ms Opus frame can + contain an LBRR frame covering at most half the prior 20 ms Opus frame, + potentially leaving a hole that needs to be concealed from even a single + packet loss (see ). +When switching from mono to stereo, the LBRR frames in the first stereo Opus + frame MAY contain a non-trivial side channel. + + + +In order to properly produce LBRR frames under all conditions, an encoder might + need to buffer up to 60 ms of audio and re-encode it during these + transitions. +However, the reference implementation opts to disable LBRR frames at the + transition point for simplicity. +Since transitions are relatively infrequent in normal usage, this does not have + a significant impact on packet loss robustness. + + + +The LBRR frames immediately follow the LBRR flags, prior to any regular SILK + frames. + describes their exact contents. +LBRR frames do not include their own separate VAD flags. +LBRR frames are only meant to be transmitted for active speech, thus all LBRR + frames are treated as active. + + + +In a stereo Opus frame longer than 20 ms, although the per-frame LBRR + flags for the mid channel are coded as a unit before the per-frame LBRR flags + for the side channel, the LBRR frames themselves are interleaved. +The decoder parses an LBRR frame for the mid channel of a given 20 ms + interval (if present) and then immediately parses the corresponding LBRR + frame for the side channel (if present), before proceeding to the next + 20 ms interval. + +
    + +
    + +The regular SILK frame(s) follow the LBRR frames (if any). + describes their contents, as well. +Unlike the LBRR frames, a regular SILK frame is coded for each time interval in + an Opus frame, even if the corresponding VAD flags are unset. +For stereo Opus frames longer than 20 ms, the regular mid and side SILK + frames for each 20 ms interval are interleaved, just as with the LBRR + frames. +The side frame may be skipped by coding an appropriate flag, as detailed in + . + +
    + +
    + +Each SILK frame includes a set of side information that encodes + +The frame type and quantization type (), +Quantization gains (), +Short-term prediction filter coefficients (), +A Line Spectral Frequencies (LSF) interpolation weight (), + +Long-term prediction filter lags and gains (), + and + +A linear congruential generator (LCG) seed (). + +The quantized excitation signal (see ) follows + these at the end of the frame. + details the overall organization of a + SILK frame. + + + +Symbol(s) +PDF(s) +Condition + +Stereo Prediction Weights + + + +Mid-only Flag + + + +Frame Type + + + +Subframe Gains + + + +Normalized LSF Stage-1 Index + + + +Normalized LSF Stage-2 Residual + + + +Normalized LSF Interpolation Weight + +20 ms frame + +Primary Pitch Lag + +Voiced frame + +Subframe Pitch Contour + +Voiced frame + +Periodicity Index + +Voiced frame + +LTP Filter + +Voiced frame + +LTP Scaling + + + +LCG Seed + + + +Excitation Rate Level + + + +Excitation Pulse Counts + + + +Excitation Pulse Locations + +Non-zero pulse count + +Excitation LSBs + + + +Excitation Signs + + + + + +
    + +A SILK frame corresponding to the mid channel of a stereo Opus frame begins + with a pair of side channel prediction weights, designed such that zeros + indicate normal mid-side coupling. +Since these weights can change on every frame, the first portion of each frame + linearly interpolates between the previous weights and the current ones, using + zeros for the previous weights if none are available. +These prediction weights are never included in a mono Opus frame, and the + previous weights are reset to zeros on any transition from mono to stereo. +They are also not included in an LBRR frame for the side channel, even if the + LBRR flags indicate the corresponding mid channel was not coded. +In that case, the previous weights are used, again substituting in zeros if no + previous weights are available since the last decoder reset + (see ). + + + +To summarize, these weights are coded if and only if + +This is a stereo Opus frame (), and +The current SILK frame corresponds to the mid channel. + + + + +The prediction weights are coded in three separate pieces, which are decoded + by silk_stereo_decode_pred() (decode_stereo_pred.c). +The first piece jointly codes the high-order part of a table index for both + weights. +The second piece codes the low-order part of each table index. +The third piece codes an offset used to linearly interpolate between table + indices. +The details are as follows. + + + +Let n be an index decoded with the 25-element stage-1 PDF in + . +Then let i0 and i1 be indices decoded with the stage-2 and stage-3 PDFs in + , respectively, and let i2 and i3 + be two more indices decoded with the stage-2 and stage-3 PDFs, all in that + order. + + + +Stage +PDF +Stage 1 +{7, 2, 1, 1, 1, + 10, 24, 8, 1, 1, + 3, 23, 92, 23, 3, + 1, 1, 8, 24, 10, + 1, 1, 1, 2, 7}/256 + +Stage 2 +{85, 86, 85}/256 + +Stage 3 +{51, 51, 52, 51, 51}/256 + + + +Then use n, i0, and i2 to form two table indices, wi0 and wi1, according to +
    + +
    + where the division is integer division. +The range of these indices is 0 to 14, inclusive. +Let w[i] be the i'th weight from . +Then the two prediction weights, w0_Q13 and w1_Q13, are +
    +> 16)*(2*i3 + 1) + +w0_Q13 = w_Q13[wi0] + + ((w_Q13[wi0+1] - w_Q13[wi0])*6554) >> 16)*(2*i1 + 1) + - w1_Q13 +]]> +
    +N.b., w1_Q13 is computed first here, because w0_Q13 depends on it. +The constant 6554 is approximately 0.1 in Q16. +Although wi0 and wi1 only have 15 possible values, + contains 16 entries to allow + interpolation between entry wi0 and (wi0 + 1) (and likewise for wi1). +
    + + +Index +Weight (Q13) + 0 -13732 + 1 -10050 + 2 -8266 + 3 -7526 + 4 -6500 + 5 -5000 + 6 -2950 + 7 -820 + 8 820 + 9 2950 +10 5000 +11 6500 +12 7526 +13 8266 +14 10050 +15 13732 + + +
    + +
    + +A flag appears after the stereo prediction weights that indicates if only the + mid channel is coded for this time interval. +It appears only when + +This is a stereo Opus frame (see ), +The current SILK frame corresponds to the mid channel, and +Either + +This is a regular SILK frame where the VAD flags + (see ) indicate that the corresponding side + channel is not active. + +This is an LBRR frame where the LBRR flags + (see and ) + indicate that the corresponding side channel is not coded. + + + + +It is omitted when there are no stereo weights, for all of the same reasons. +It is also omitted for a regular SILK frame when the VAD flag of the + corresponding side channel frame is set (indicating it is active). +The side channel must be coded in this case, making the mid-only flag + redundant. +It is also omitted for an LBRR frame when the corresponding LBRR flags + indicate the side channel is coded. + + + +When the flag is present, the decoder reads a single value using the PDF in + , as implemented in + silk_stereo_decode_mid_only() (decode_stereo_pred.c). +If the flag is set, then there is no corresponding SILK frame for the side + channel, the entire decoding process for the side channel is skipped, and + zeros are fed to the stereo unmixing process (see + ) instead. +As stated above, LBRR frames still include this flag when the LBRR flag + indicates that the side channel is not coded. +In that case, if this flag is zero (indicating that there should be a side + channel), then Packet Loss Concealment (PLC, see + ) SHOULD be invoked to recover a + side channel signal. +Otherwise, the stereo image will collapse. + + + +PDF +{192, 64}/256 + + +
    + +
    + +Each SILK frame contains a single "frame type" symbol that jointly codes the + signal type and quantization offset type of the corresponding frame. +If the current frame is a regular SILK frame whose VAD bit was not set (an + "inactive" frame), then the frame type symbol takes on a value of either 0 or + 1 and is decoded using the first PDF in . +If the frame is an LBRR frame or a regular SILK frame whose VAD flag was set + (an "active" frame), then the value of the symbol may range from 2 to 5, + inclusive, and is decoded using the second PDF in + . + translates between the value of the + frame type symbol and the corresponding signal type and quantization offset + type. + + + +VAD Flag +PDF +Inactive {26, 230, 0, 0, 0, 0}/256 +Active {0, 0, 24, 74, 148, 10}/256 + + + +Frame Type +Signal Type +Quantization Offset Type +0 Inactive Low +1 Inactive High +2 Unvoiced Low +3 Unvoiced High +4 Voiced Low +5 Voiced High + + +
    + +
    + +A separate quantization gain is coded for each 5 ms subframe. +These gains control the step size between quantization levels of the excitation + signal and, therefore, the quality of the reconstruction. +They are independent of and unrelated to the pitch contours coded for voiced + frames. +The quantization gains are themselves uniformly quantized to 6 bits on a + log scale, giving them a resolution of approximately 1.369 dB and a range + of approximately 1.94 dB to 88.21 dB. + + +The subframe gains are either coded independently, or relative to the gain from + the most recent coded subframe in the same channel. +Independent coding is used if and only if + + +This is the first subframe in the current SILK frame, and + +Either + + +This is the first SILK frame of its type (LBRR or regular) for this channel in + the current Opus frame, or + + +The previous SILK frame of the same type (LBRR or regular) for this channel in + the same Opus frame was not coded. + + + + + + + +In an independently coded subframe gain, the 3 most significant bits of the + quantization gain are decoded using a PDF selected from + based on the decoded signal + type (see ). + + + +Signal Type +PDF +Inactive {32, 112, 68, 29, 12, 1, 1, 1}/256 +Unvoiced {2, 17, 45, 60, 62, 47, 19, 4}/256 +Voiced {1, 3, 26, 71, 94, 50, 9, 2}/256 + + + +The 3 least significant bits are decoded using a uniform PDF: + + +PDF +{32, 32, 32, 32, 32, 32, 32, 32}/256 + + + +These 6 bits are combined to form a value, gain_index, between 0 and 63. +When the gain for the previous subframe is available, then the current gain is + limited as follows: +
    + +
    +This may help some implementations limit the change in precision of their + internal LTP history. +The indices which this clamp applies to cannot simply be removed from the + codebook, because previous_log_gain will not be available after packet loss. +The clamping is skipped after a decoder reset, and in the side channel if the + previous frame in the side channel was not coded, since there is no value for + previous_log_gain available. +It MAY also be skipped after packet loss. +
    + + +For subframes which do not have an independent gain (including the first + subframe of frames not listed as using independent coding above), the + quantization gain is coded relative to the gain from the previous subframe (in + the same channel). +The PDF in yields a delta_gain_index value + between 0 and 40, inclusive. + + +PDF +{6, 5, 11, 31, 132, 21, 8, 4, + 3, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 + + +The following formula translates this index into a quantization gain for the + current subframe using the gain from the previous subframe: +
    + +
    +
    + +silk_gains_dequant() (gain_quant.c) dequantizes log_gain for the k'th subframe + and converts it into a linear Q16 scale factor via +
    +>16) + 2090) +]]> +
    +
    + +The function silk_log2lin() (log2lin.c) computes an approximation of + 2**(inLog_Q7/128.0), where inLog_Q7 is its Q7 input. +Let i = inLog_Q7>>7 be the integer part of inLogQ7 and + f = inLog_Q7&127 be the fractional part. +Then +
    +>16)+f)*((1<>7) +]]> +
    + yields the approximate exponential. +The final Q16 gain values lies between 81920 and 1686110208, inclusive + (representing scale factors of 1.25 to 25728, respectively). +
    +
    + +
    + +A set of normalized Line Spectral Frequency (LSF) coefficients follow the + quantization gains in the bitstream, and represent the Linear Predictive + Coding (LPC) coefficients for the current SILK frame. +Once decoded, the normalized LSFs form an increasing list of Q15 values between + 0 and 1. +These represent the interleaved zeros on the upper half of the unit circle + (between 0 and pi, hence "normalized") in the standard decomposition + of the LPC filter into a symmetric part + and an anti-symmetric part (P and Q in ). +Because of non-linear effects in the decoding process, an implementation SHOULD + match the fixed-point arithmetic described in this section exactly. +An encoder SHOULD also use the same process. + + +The normalized LSFs are coded using a two-stage vector quantizer (VQ) + ( and ). +NB and MB frames use an order-10 predictor, while WB frames use an order-16 + predictor, and thus have different sets of tables. +After reconstructing the normalized LSFs + (), the decoder runs them through a + stabilization process (), interpolates + them between frames (), converts them + back into LPC coefficients (), and then runs + them through further processes to limit the range of the coefficients + () and the gain of the filter + (). +All of this is necessary to ensure the reconstruction process is stable. + + +
    + +The first VQ stage uses a 32-element codebook, coded with one of the PDFs in + , depending on the audio bandwidth and + the signal type of the current SILK frame. +This yields a single index, I1, for the entire frame, which + +Indexes an element in a coarse codebook, +Selects the PDFs for the second stage of the VQ, and +Selects the prediction weights used to remove intra-frame redundancy from + the second stage. + +The actual codebook elements are listed in + and + , but they are not needed until the last + stages of reconstructing the LSF coefficients. + + + +Audio Bandwidth +Signal Type +PDF +NB or MB Inactive or unvoiced + +{44, 34, 30, 19, 21, 12, 11, 3, + 3, 2, 16, 2, 2, 1, 5, 2, + 1, 3, 3, 1, 1, 2, 2, 2, + 3, 1, 9, 9, 2, 7, 2, 1}/256 + +NB or MB Voiced + +{1, 10, 1, 8, 3, 8, 8, 14, +13, 14, 1, 14, 12, 13, 11, 11, +12, 11, 10, 10, 11, 8, 9, 8, + 7, 8, 1, 1, 6, 1, 6, 5}/256 + +WB Inactive or unvoiced + +{31, 21, 3, 17, 1, 8, 17, 4, + 1, 18, 16, 4, 2, 3, 1, 10, + 1, 3, 16, 11, 16, 2, 2, 3, + 2, 11, 1, 4, 9, 8, 7, 3}/256 + +WB Voiced + +{1, 4, 16, 5, 18, 11, 5, 14, +15, 1, 3, 12, 13, 14, 14, 6, +14, 12, 2, 6, 1, 12, 12, 11, +10, 3, 10, 5, 1, 1, 1, 3}/256 + + + +
    + +
    + +A total of 16 PDFs are available for the LSF residual in the second stage: the + 8 (a...h) for NB and MB frames given in + , and the 8 (i...p) for WB frames + given in . +Which PDF is used for which coefficient is driven by the index, I1, + decoded in the first stage. + lists the letter of the + corresponding PDF for each normalized LSF coefficient for NB and MB, and + lists the same information for WB. + + + +Codebook +PDF +a {1, 1, 1, 15, 224, 11, 1, 1, 1}/256 +b {1, 1, 2, 34, 183, 32, 1, 1, 1}/256 +c {1, 1, 4, 42, 149, 55, 2, 1, 1}/256 +d {1, 1, 8, 52, 123, 61, 8, 1, 1}/256 +e {1, 3, 16, 53, 101, 74, 6, 1, 1}/256 +f {1, 3, 17, 55, 90, 73, 15, 1, 1}/256 +g {1, 7, 24, 53, 74, 67, 26, 3, 1}/256 +h {1, 1, 18, 63, 78, 58, 30, 6, 1}/256 + + + +Codebook +PDF +i {1, 1, 1, 9, 232, 9, 1, 1, 1}/256 +j {1, 1, 2, 28, 186, 35, 1, 1, 1}/256 +k {1, 1, 3, 42, 152, 53, 2, 1, 1}/256 +l {1, 1, 10, 49, 126, 65, 2, 1, 1}/256 +m {1, 4, 19, 48, 100, 77, 5, 1, 1}/256 +n {1, 1, 14, 54, 100, 72, 12, 1, 1}/256 +o {1, 1, 15, 61, 87, 61, 25, 4, 1}/256 +p {1, 7, 21, 50, 77, 81, 17, 1, 1}/256 + + + +I1 +Coefficient + +0 1 2 3 4 5 6 7 8 9 + 0 +a a a a a a a a a a + 1 +b d b c c b c b b b + 2 +c b b b b b b b b b + 3 +b c c c c b c b b b + 4 +c d d d d c c c c c + 5 +a f d d c c c c b b + g +a c c c c c c c c b + 7 +c d g e e e f e f f + 8 +c e f f e f e g e e + 9 +c e e h e f e f f e +10 +e d d d c d c c c c +11 +b f f g e f e f f f +12 +c h e g f f f f f f +13 +c h f f f f f g f e +14 +d d f e e f e f e e +15 +c d d f f e e e e e +16 +c e e g e f e f f f +17 +c f e g f f f e f e +18 +c h e f e f e f f f +19 +c f e g h g f g f e +20 +d g h e g f f g e f +21 +c h g e e e f e f f +22 +e f f e g g f g f e +23 +c f f g f g e g e e +24 +e f f f d h e f f e +25 +c d e f f g e f f e +26 +c d c d d e c d d d +27 +b b c c c c c d c c +28 +e f f g g g f g e f +29 +d f f e e e e d d c +30 +c f d h f f e e f e +31 +e e f e f g f g f e + + + +I1 +Coefficient + +0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 + 0 +i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i + 1 +k  l  l  l  l  l  k  k  k  k  k  j  j  j  i  l + 2 +k  n  n  l  p  m  m  n  k  n  m  n  n  m  l  l + 3 +i  k  j  k  k  j  j  j  j  j  i  i  i  i  i  j + 4 +i  o  n  m  o  m  p  n  m  m  m  n  n  m  m  l + 5 +i  l  n  n  m  l  l  n  l  l  l  l  l  l  k  m + 6 +i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i + 7 +i  k  o  l  p  k  n  l  m  n  n  m  l  l  k  l + 8 +i  o  k  o  o  m  n  m  o  n  m  m  n  l  l  l + 9 +k  j  i  i  i  i  i  i  i  i  i  i  i  i  i  i +10 +i  j  i  i  i  i  i  i  i  i  i  i  i  i  i  j +11 +k  k  l  m  n  l  l  l  l  l  l  l  k  k  j  l +12 +k  k  l  l  m  l  l  l  l  l  l  l  l  k  j  l +13 +l  m  m  m  o  m  m  n  l  n  m  m  n  m  l  m +14 +i  o  m  n  m  p  n  k  o  n  p  m  m  l  n  l +15 +i  j  i  j  j  j  j  j  j  j  i  i  i  i  j  i +16 +j  o  n  p  n  m  n  l  m  n  m  m  m  l  l  m +17 +j  l  l  m  m  l  l  n  k  l  l  n  n  n  l  m +18 +k  l  l  k  k  k  l  k  j  k  j  k  j  j  j  m +19 +i  k  l  n  l  l  k  k  k  j  j  i  i  i  i  i +20 +l  m  l  n  l  l  k  k  j  j  j  j  j  k  k  m +21 +k  o  l  p  p  m  n  m  n  l  n  l  l  k  l  l +22 +k  l  n  o  o  l  n  l  m  m  l  l  l  l  k  m +23 +j  l  l  m  m  m  m  l  n  n  n  l  j  j  j  j +24 +k  n  l  o  o  m  p  m  m  n  l  m  m  l  l  l +25 +i  o  j  j  i  i  i  i  i  i  i  i  i  i  i  i +26 +i  o  o  l  n  k  n  n  l  m  m  p  p  m  m  m +27 +l  l  p  l  n  m  l  l  l  k  k  l  l  l  k  l +28 +i  i  j  i  i  i  k  j  k  j  j  k  k  k  j  j +29 +i  l  k  n  l  l  k  l  k  j  i  i  j  i  i  j +30 +l  n  n  m  p  n  l  l  k  l  k  k  j  i  j  i +31 +k  l  n  l  m  l  l  l  k  j  k  o  m  i  i  i + + + +Decoding the second stage residual proceeds as follows. +For each coefficient, the decoder reads a symbol using the PDF corresponding to + I1 from either or + , and subtracts 4 from the result + to give an index in the range -4 to 4, inclusive. +If the index is either -4 or 4, it reads a second symbol using the PDF in + , and adds the value of this second symbol + to the index, using the same sign. +This gives the index, I2[k], a total range of -10 to 10, inclusive. + + + +PDF +{156, 60, 24, 9, 4, 2, 1}/256 + + + +The decoded indices from both stages are translated back into normalized LSF + coefficients in silk_NLSF_decode() (NLSF_decode.c). +The stage-2 indices represent residuals after both the first stage of the VQ + and a separate backwards-prediction step. +The backwards prediction process in the encoder subtracts a prediction from + each residual formed by a multiple of the coefficient that follows it. +The decoder must undo this process. + contains lists of prediction weights + for each coefficient. +There are two lists for NB and MB, and another two lists for WB, giving two + possible prediction weights for each coefficient. + + + +Coefficient +A +B +C +D + 0 179 116 175 68 + 1 138 67 148 62 + 2 140 82 160 66 + 3 148 59 176 60 + 4 151 92 178 72 + 5 149 72 173 117 + 6 153 100 174 85 + 7 151 89 164 90 + 8 163 92 177 118 + 9 174 136 +10 196 151 +11 182 142 +12 198 160 +13 192 142 +14 182 155 + + + +The prediction is undone using the procedure implemented in + silk_NLSF_residual_dequant() (NLSF_decode.c), which is as follows. +Each coefficient selects its prediction weight from one of the two lists based + on the stage-1 index, I1. + gives the selections for each + coefficient for NB and MB, and gives + the selections for WB. +Let d_LPC be the order of the codebook, i.e., 10 for NB and MB, and 16 for WB, + and let pred_Q8[k] be the weight for the k'th coefficient selected by this + process for 0 <= k < d_LPC-1. +Then, the stage-2 residual for each coefficient is computed via +
    +>8 : 0) + + ((((I2[k]<<10) - sign(I2[k])*102)*qstep)>>16) , +]]> +
    + where qstep is the Q16 quantization step size, which is 11796 for NB and MB + and 9830 for WB (representing step sizes of approximately 0.18 and 0.15, + respectively). +
    + + +I1 +Coefficient + +0 1 2 3 4 5 6 7 8 + 0 +A B A A A A A A A + 1 +B A A A A A A A A + 2 +A A A A A A A A A + 3 +B B B A A A A B A + 4 +A B A A A A A A A + 5 +A B A A A A A A A + 6 +B A B B A A A B A + 7 +A B B A A B B A A + 8 +A A B B A B A B B + 9 +A A B B A A B B B +10 +A A A A A A A A A +11 +A B A B B B B B A +12 +A B A B B B B B A +13 +A B B B B B B B A +14 +B A B B A B B B B +15 +A B B B B B A B A +16 +A A B B A B A B A +17 +A A B B B A B B B +18 +A B B A A B B B A +19 +A A A B B B A B A +20 +A B B A A B A B A +21 +A B B A A A B B A +22 +A A A A A B B B B +23 +A A B B A A A B B +24 +A A A B A B B B B +25 +A B B B B B B B A +26 +A A A A A A A A A +27 +A A A A A A A A A +28 +A A B A B B A B A +29 +B A A B A A A A A +30 +A A A B B A B A B +31 +B A B B A B B B B + + + +I1 +Coefficient + +0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 + 0 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D + 1 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  C + 2 +C  C  D  C  C  D  D  D  C  D  D  D  D  C  C + 3 +C  C  C  C  C  C  C  C  C  C  C  C  D  C  C + 4 +C  D  D  C  D  C  D  D  C  D  D  D  D  D  C + 5 +C  C  D  C  C  C  C  C  C  C  C  C  C  C  C + 6 +D  C  C  C  C  C  C  C  C  C  C  D  C  D  C + 7 +C  D  D  C  C  C  D  C  D  D  D  C  D  C  D + 8 +C  D  C  D  D  C  D  C  D  C  D  D  D  D  D + 9 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +10 +C  D  C  C  C  C  C  C  C  C  C  C  C  C  C +11 +C  C  D  C  D  D  D  D  D  D  D  C  D  C  C +12 +C  C  D  C  C  D  C  D  C  D  C  C  D  C  C +13 +C  C  C  C  D  D  C  D  C  D  D  D  D  C  C +14 +C  D  C  C  C  D  D  C  D  D  D  C  D  D  D +15 +C  C  D  D  C  C  C  C  C  C  C  C  D  D  C +16 +C  D  D  C  D  C  D  D  D  D  D  C  D  C  C +17 +C  C  D  C  C  C  C  D  C  C  D  D  D  C  C +18 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +19 +C  C  C  C  C  C  C  C  C  C  C  C  D  C  C +20 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  C +21 +C  D  C  D  C  D  D  C  D  C  D  C  D  D  C +22 +C  C  D  D  D  D  C  D  D  C  C  D  D  C  C +23 +C  D  D  C  D  C  D  C  D  C  C  C  C  D  C +24 +C  C  C  D  D  C  D  C  D  D  D  D  D  D  D +25 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +26 +C  D  D  C  C  C  D  D  C  C  D  D  D  D  D +27 +C  C  C  C  C  D  C  D  D  D  D  C  D  D  D +28 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +29 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +30 +D  C  C  C  C  C  C  C  C  C  C  D  C  C  C +31 +C  C  D  C  C  D  D  D  C  C  D  C  C  D  C + + +
    + +
    + +Once the stage-1 index I1 and the stage-2 residual res_Q10[] have been decoded, + the final normalized LSF coefficients can be reconstructed. + + +The spectral distortion introduced by the quantization of each LSF coefficient + varies, so the stage-2 residual is weighted accordingly, using the + low-complexity Inverse Harmonic Mean Weighting (IHMW) function proposed in + . +The weights are derived directly from the stage-1 codebook vector. +Let cb1_Q8[k] be the k'th entry of the stage-1 codebook vector from + or + . +Then for 0 <= k < d_LPC the following expression + computes the square of the weight as a Q18 value: +
    + + + +
    + where cb1_Q8[-1] = 0 and cb1_Q8[d_LPC] = 256, and the + division is integer division. +This is reduced to an unsquared, Q9 value using the following square-root + approximation: +
    +>(i-8)) & 127 +y = ((i&1) ? 32768 : 46214) >> ((32-i)>>1) +w_Q9[k] = y + ((213*f*y)>>16) +]]> +
    +The constant 46214 here is approximately the square root of 2 in Q15. +The cb1_Q8[] vector completely determines these weights, and they may be + tabulated and stored as 13-bit unsigned values (with a range of 1819 to 5227, + inclusive) to avoid computing them when decoding. +The reference implementation already requires code to compute these weights on + unquantized coefficients in the encoder, in silk_NLSF_VQ_weights_laroia() + (NLSF_VQ_weights_laroia.c) and its callers, so it reuses that code in the + decoder instead of using a pre-computed table to reduce the amount of ROM + required. +
    + + +I1 +Codebook (Q8) + + 0   1   2   3   4   5   6   7   8   9 +0 +12  35  60  83 108 132 157 180 206 228 +1 +15  32  55  77 101 125 151 175 201 225 +2 +19  42  66  89 114 137 162 184 209 230 +3 +12  25  50  72  97 120 147 172 200 223 +4 +26  44  69  90 114 135 159 180 205 225 +5 +13  22  53  80 106 130 156 180 205 228 +6 +15  25  44  64  90 115 142 168 196 222 +7 +19  24  62  82 100 120 145 168 190 214 +8 +22  31  50  79 103 120 151 170 203 227 +9 +21  29  45  65 106 124 150 171 196 224 +10 +30  49  75  97 121 142 165 186 209 229 +11 +19  25  52  70  93 116 143 166 192 219 +12 +26  34  62  75  97 118 145 167 194 217 +13 +25  33  56  70  91 113 143 165 196 223 +14 +21  34  51  72  97 117 145 171 196 222 +15 +20  29  50  67  90 117 144 168 197 221 +16 +22  31  48  66  95 117 146 168 196 222 +17 +24  33  51  77 116 134 158 180 200 224 +18 +21  28  70  87 106 124 149 170 194 217 +19 +26  33  53  64  83 117 152 173 204 225 +20 +27  34  65  95 108 129 155 174 210 225 +21 +20  26  72  99 113 131 154 176 200 219 +22 +34  43  61  78  93 114 155 177 205 229 +23 +23  29  54  97 124 138 163 179 209 229 +24 +30  38  56  89 118 129 158 178 200 231 +25 +21  29  49  63  85 111 142 163 193 222 +26 +27  48  77 103 133 158 179 196 215 232 +27 +29  47  74  99 124 151 176 198 220 237 +28 +33  42  61  76  93 121 155 174 207 225 +29 +29  53  87 112 136 154 170 188 208 227 +30 +24  30  52  84 131 150 166 186 203 229 +31 +37  48  64  84 104 118 156 177 201 230 + + + +I1 +Codebook (Q8) + + 0  1  2  3  4   5   6   7   8   9  10  11  12  13  14  15 +0 + 7 23 38 54 69  85 100 116 131 147 162 178 193 208 223 239 +1 +13 25 41 55 69  83  98 112 127 142 157 171 187 203 220 236 +2 +15 21 34 51 61  78  92 106 126 136 152 167 185 205 225 240 +3 +10 21 36 50 63  79  95 110 126 141 157 173 189 205 221 237 +4 +17 20 37 51 59  78  89 107 123 134 150 164 184 205 224 240 +5 +10 15 32 51 67  81  96 112 129 142 158 173 189 204 220 236 +6 + 8 21 37 51 65  79  98 113 126 138 155 168 179 192 209 218 +7 +12 15 34 55 63  78  87 108 118 131 148 167 185 203 219 236 +8 +16 19 32 36 56  79  91 108 118 136 154 171 186 204 220 237 +9 +11 28 43 58 74  89 105 120 135 150 165 180 196 211 226 241 +10 + 6 16 33 46 60  75  92 107 123 137 156 169 185 199 214 225 +11 +11 19 30 44 57  74  89 105 121 135 152 169 186 202 218 234 +12 +12 19 29 46 57  71  88 100 120 132 148 165 182 199 216 233 +13 +17 23 35 46 56  77  92 106 123 134 152 167 185 204 222 237 +14 +14 17 45 53 63  75  89 107 115 132 151 171 188 206 221 240 +15 + 9 16 29 40 56  71  88 103 119 137 154 171 189 205 222 237 +16 +16 19 36 48 57  76  87 105 118 132 150 167 185 202 218 236 +17 +12 17 29 54 71  81  94 104 126 136 149 164 182 201 221 237 +18 +15 28 47 62 79  97 115 129 142 155 168 180 194 208 223 238 +19 + 8 14 30 45 62  78  94 111 127 143 159 175 192 207 223 239 +20 +17 30 49 62 79  92 107 119 132 145 160 174 190 204 220 235 +21 +14 19 36 45 61  76  91 108 121 138 154 172 189 205 222 238 +22 +12 18 31 45 60  76  91 107 123 138 154 171 187 204 221 236 +23 +13 17 31 43 53  70  83 103 114 131 149 167 185 203 220 237 +24 +17 22 35 42 58  78  93 110 125 139 155 170 188 206 224 240 +25 + 8 15 34 50 67  83  99 115 131 146 162 178 193 209 224 239 +26 +13 16 41 66 73  86  95 111 128 137 150 163 183 206 225 241 +27 +17 25 37 52 63  75  92 102 119 132 144 160 175 191 212 231 +28 +19 31 49 65 83 100 117 133 147 161 174 187 200 213 227 242 +29 +18 31 52 68 88 103 117 126 138 149 163 177 192 207 223 239 +30 +16 29 47 61 76  90 106 119 133 147 161 176 193 209 224 240 +31 +15 21 35 50 61  73  86  97 110 119 129 141 175 198 218 237 + + + +Given the stage-1 codebook entry cb1_Q8[], the stage-2 residual res_Q10[], and + their corresponding weights, w_Q9[], the reconstructed normalized LSF + coefficients are +
    + +
    + where the division is integer division. +However, nothing in either the reconstruction process or the + quantization process in the encoder thus far guarantees that the coefficients + are monotonically increasing and separated well enough to ensure a stable + filter . +When using the reference encoder, roughly 2% of frames violate this constraint. +The next section describes a stabilization procedure used to make these + guarantees. +
    + +
    + +
    + +The normalized LSF stabilization procedure is implemented in + silk_NLSF_stabilize() (NLSF_stabilize.c). +This process ensures that consecutive values of the normalized LSF + coefficients, NLSF_Q15[], are spaced some minimum distance apart + (predetermined to be the 0.01 percentile of a large training set). + gives the minimum spacings for NB and MB + and those for WB, where row k is the minimum allowed value of + NLSF_Q[k]-NLSF_Q[k-1]. +For the purposes of computing this spacing for the first and last coefficient, + NLSF_Q15[-1] is taken to be 0, and NLSF_Q15[d_LPC] is taken to be 32768. + + + +Coefficient +NB and MB +WB + 0 250 100 + 1 3 3 + 2 6 40 + 3 3 3 + 4 3 3 + 5 3 3 + 6 4 5 + 7 3 14 + 8 3 14 + 9 3 10 +10 461 11 +11 3 +12 8 +13 9 +14 7 +15 3 +16 347 + + + +The procedure starts off by trying to make small adjustments which attempt to + minimize the amount of distortion introduced. +After 20 such adjustments, it falls back to a more direct method which + guarantees the constraints are enforced but may require large adjustments. + + +Let NDeltaMin_Q15[k] be the minimum required spacing for the current audio + bandwidth from . +First, the procedure finds the index i where + NLSF_Q15[i] - NLSF_Q15[i-1] - NDeltaMin_Q15[i] is the + smallest, breaking ties by using the lower value of i. +If this value is non-negative, then the stabilization stops; the coefficients + satisfy all the constraints. +Otherwise, if i == 0, it sets NLSF_Q15[0] to NDeltaMin_Q15[0], and if + i == d_LPC, it sets NLSF_Q15[d_LPC-1] to + (32768 - NDeltaMin_Q15[d_LPC]). +For all other values of i, both NLSF_Q15[i-1] and NLSF_Q15[i] are updated as + follows: +
    +>1) + \ NDeltaMin_Q15[k] + /_ + k=0 + d_LPC + __ + max_center_Q15 = 32768 - (NDeltaMin_Q15[i]>>1) - \ NDeltaMin_Q15[k] + /_ + k=i+1 +center_freq_Q15 = clamp(min_center_Q15[i], + (NLSF_Q15[i-1] + NLSF_Q15[i] + 1)>>1, + max_center_Q15[i]) + + NLSF_Q15[i-1] = center_freq_Q15 - (NDeltaMin_Q15[i]>>1) + + NLSF_Q15[i] = NLSF_Q15[i-1] + NDeltaMin_Q15[i] . +]]> +
    +Then the procedure repeats again, until it has either executed 20 times or + has stopped because the coefficients satisfy all the constraints. +
    + +After the 20th repetition of the above procedure, the following fallback + procedure executes once. +First, the values of NLSF_Q15[k] for 0 <= k < d_LPC + are sorted in ascending order. +Then for each value of k from 0 to d_LPC-1, NLSF_Q15[k] is set to +
    + +
    +Next, for each value of k from d_LPC-1 down to 0, NLSF_Q15[k] is set to +
    + +
    +
    + +
    + +
    + +For 20 ms SILK frames, the first half of the frame (i.e., the first two + subframes) may use normalized LSF coefficients that are interpolated between + the decoded LSFs for the most recent coded frame (in the same channel) and the + current frame. +A Q2 interpolation factor follows the LSF coefficient indices in the bitstream, + which is decoded using the PDF in . +This happens in silk_decode_indices() (decode_indices.c). +After either + +An uncoded regular SILK frame in the side channel, or +A decoder reset (see ), + + the decoder still decodes this factor, but ignores its value and always uses + 4 instead. +For 10 ms SILK frames, this factor is not stored at all. + + + +PDF +{13, 22, 29, 11, 181}/256 + + + +Let n2_Q15[k] be the normalized LSF coefficients decoded by the procedure in + , n0_Q15[k] be the LSF coefficients + decoded for the prior frame, and w_Q2 be the interpolation factor. +Then the normalized LSF coefficients used for the first half of a 20 ms + frame, n1_Q15[k], are +
    +> 2) . +]]> +
    +This interpolation is performed in silk_decode_parameters() + (decode_parameters.c). +
    +
    + +
    + +Any LPC filter A(z) can be split into a symmetric part P(z) and an + anti-symmetric part Q(z) such that +
    + +
    +with +
    + +
    +The even normalized LSF coefficients correspond to a pair of conjugate roots of + P(z), while the odd coefficients correspond to a pair of conjugate roots of + Q(z), all of which lie on the unit circle. +In addition, P(z) has a root at pi and Q(z) has a root at 0. +Thus, they may be reconstructed mathematically from a set of normalized LSF + coefficients, n[k], as +
    + +
    +
    + +However, SILK performs this reconstruction using a fixed-point approximation so + that all decoders can reproduce it in a bit-exact manner to avoid prediction + drift. +The function silk_NLSF2A() (NLSF2A.c) implements this procedure. + + +To start, it approximates cos(pi*n[k]) using a table lookup with linear + interpolation. +The encoder SHOULD use the inverse of this piecewise linear approximation, + rather than the true inverse of the cosine function, when deriving the + normalized LSF coefficients. +These values are also re-ordered to improve numerical accuracy when + constructing the LPC polynomials. + + + +Coefficient +NB and MB +WB + 0 0 0 + 1 9 15 + 2 6 8 + 3 3 7 + 4 4 4 + 5 5 11 + 6 8 12 + 7 1 3 + 8 2 2 + 9 7 13 +10 10 +11 5 +12 6 +13 9 +14 14 +15 1 + + + +The top 7 bits of each normalized LSF coefficient index a value in the table, + and the next 8 bits interpolate between it and the next value. +Let i = (n[k] >> 8) be the integer index and + f = (n[k] & 255) be the fractional part of a given + coefficient. +Then the re-ordered, approximated cosine, c_Q17[ordering[k]], is +
    +> 3 , +]]> +
    + where ordering[k] is the k'th entry of the column of + corresponding to the current audio + bandwidth and cos_Q12[i] is the i'th entry of . +
    + + +i ++0 ++1 ++2 ++3 +0 + 4096 4095 4091 4085 +4 + 4076 4065 4052 4036 +8 + 4017 3997 3973 3948 +12 + 3920 3889 3857 3822 +16 + 3784 3745 3703 3659 +20 + 3613 3564 3513 3461 +24 + 3406 3349 3290 3229 +28 + 3166 3102 3035 2967 +32 + 2896 2824 2751 2676 +36 + 2599 2520 2440 2359 +40 + 2276 2191 2106 2019 +44 + 1931 1842 1751 1660 +48 + 1568 1474 1380 1285 +52 + 1189 1093 995 897 +56 + 799 700 601 501 +60 + 401 301 201 101 +64 + 0 -101 -201 -301 +68 + -401 -501 -601 -700 +72 + -799 -897 -995 -1093 +76 +-1189-1285-1380-1474 +80 +-1568-1660-1751-1842 +84 +-1931-2019-2106-2191 +88 +-2276-2359-2440-2520 +92 +-2599-2676-2751-2824 +96 +-2896-2967-3035-3102 +100 +-3166-3229-3290-3349 +104 +-3406-3461-3513-3564 +108 +-3613-3659-3703-3745 +112 +-3784-3822-3857-3889 +116 +-3920-3948-3973-3997 +120 +-4017-4036-4052-4065 +124 +-4076-4085-4091-4095 +128 +-4096 + + + +Given the list of cosine values, silk_NLSF2A_find_poly() (NLSF2A.c) + computes the coefficients of P and Q, described here via a simple recurrence. +Let p_Q16[k][j] and q_Q16[k][j] be the coefficients of the products of the + first (k+1) root pairs for P and Q, with j indexing the coefficient number. +Only the first (k+2) coefficients are needed, as the products are symmetric. +Let p_Q16[0][0] = q_Q16[0][0] = 1<<16, + p_Q16[0][1] = -c_Q17[0], q_Q16[0][1] = -c_Q17[1], and + d2 = d_LPC/2. +As boundary conditions, assume + p_Q16[k][j] = q_Q16[k][j] = 0 for all + j < 0. +Also, assume p_Q16[k][k+2] = p_Q16[k][k] and + q_Q16[k][k+2] = q_Q16[k][k] (because of the symmetry). +Then, for 0 < k < d2 and 0 <= j <= k+1, +
    +>16) , + +q_Q16[k][j] = q_Q16[k-1][j] + q_Q16[k-1][j-2] + - ((c_Q17[2*k+1]*q_Q16[k-1][j-1] + 32768)>>16) . +]]> +
    +The use of Q17 values for the cosine terms in an otherwise Q16 expression + implicitly scales them by a factor of 2. +The multiplications in this recurrence may require up to 48 bits of precision + in the result to avoid overflow. +In practice, each row of the recurrence only depends on the previous row, so an + implementation does not need to store all of them. +
    + +silk_NLSF2A() uses the values from the last row of this recurrence to + reconstruct a 32-bit version of the LPC filter (without the leading 1.0 + coefficient), a32_Q17[k], 0 <= k < d2: +
    + +
    +The sum and difference of two terms from each of the p_Q16 and q_Q16 + coefficient lists reflect the (1 + z**-1) and + (1 - z**-1) factors of P and Q, respectively. +The promotion of the expression from Q16 to Q17 implicitly scales the result + by 1/2. +
    +
    + +
    + +The a32_Q17[] coefficients are too large to fit in a 16-bit value, which + significantly increases the cost of applying this filter in fixed-point + decoders. +Reducing them to Q12 precision doesn't incur any significant quality loss, + but still does not guarantee they will fit. +silk_NLSF2A() applies up to 10 rounds of bandwidth expansion to limit + the dynamic range of these coefficients. +Even floating-point decoders SHOULD perform these steps, to avoid mismatch. + + +For each round, the process first finds the index k such that abs(a32_Q17[k]) + is largest, breaking ties by choosing the lowest value of k. +Then, it computes the corresponding Q12 precision value, maxabs_Q12, subject to + an upper bound to avoid overflow in subsequent computations: +
    +> 5, 163838) . +]]> +
    +If this is larger than 32767, the procedure derives the chirp factor, + sc_Q16[0], to use in the bandwidth expansion as +
    +> 2 +]]> +
    + where the division here is integer division. +This is an approximation of the chirp factor needed to reduce the target + coefficient to 32767, though it is both less than 0.999 and, for + k > 0 when maxabs_Q12 is much greater than 32767, still slightly + too large. +The upper bound on maxabs_Q12, 163838, was chosen because it is equal to + ((2**31 - 1) >> 14) + 32767, i.e., the + largest value of maxabs_Q12 that would not overflow the numerator in the + equation above when stored in a signed 32-bit integer. +
    + +silk_bwexpander_32() (bwexpander_32.c) performs the bandwidth expansion (again, + only when maxabs_Q12 is greater than 32767) using the following recurrence: +
    +> 16 + +sc_Q16[k+1] = (sc_Q16[0]*sc_Q16[k] + 32768) >> 16 +]]> +
    +The first multiply may require up to 48 bits of precision in the result to + avoid overflow. +The second multiply must be unsigned to avoid overflow with only 32 bits of + precision. +The reference implementation uses a slightly more complex formulation that + avoids the 32-bit overflow using signed multiplication, but is otherwise + equivalent. +
    + +After 10 rounds of bandwidth expansion are performed, they are simply saturated + to 16 bits: +
    +> 5, 32767) << 5 . +]]> +
    +Because this performs the actual saturation in the Q12 domain, but converts the + coefficients back to the Q17 domain for the purposes of prediction gain + limiting, this step must be performed after the 10th round of bandwidth + expansion, regardless of whether or not the Q12 version of any coefficient + still overflows a 16-bit integer. +This saturation is not performed if maxabs_Q12 drops to 32767 or less prior to + the 10th round. +
    +
    + +
    + +The prediction gain of an LPC synthesis filter is the square-root of the output + energy when the filter is excited by a unit-energy impulse. +Even if the Q12 coefficients would fit, the resulting filter may still have a + significant gain (especially for voiced sounds), making the filter unstable. +silk_NLSF2A() applies up to 18 additional rounds of bandwidth expansion to + limit the prediction gain. +Instead of controlling the amount of bandwidth expansion using the prediction + gain itself (which may diverge to infinity for an unstable filter), + silk_NLSF2A() uses silk_LPC_inverse_pred_gain_QA() (LPC_inv_pred_gain.c) to + compute the reflection coefficients associated with the filter. +The filter is stable if and only if the magnitude of these coefficients is + sufficiently less than one. +The reflection coefficients, rc[k], can be computed using a simple Levinson + recurrence, initialized with the LPC coefficients + a[d_LPC-1][n] = a[n], and then updated via +
    + +
    +
    + +However, silk_LPC_inverse_pred_gain_QA() approximates this using fixed-point + arithmetic to guarantee reproducible results across platforms and + implementations. +Since small changes in the coefficients can make a stable filter unstable, it + takes the real Q12 coefficients that will be used during reconstruction as + input. +Thus, let +
    +> 5 +]]> +
    + be the Q12 version of the LPC coefficients that will eventually be used. +As a simple initial check, the decoder computes the DC response as +
    + +
    + and if DC_resp > 4096, the filter is unstable. +
    + +Increasing the precision of these Q12 coefficients to Q24 for intermediate + computations allows more accurate computation of the reflection coefficients, + so the decoder initializes the recurrence via +
    + +
    +Then for each k from d_LPC-1 down to 0, if + abs(a32_Q24[k][k]) > 16773022, the filter is unstable and the + recurrence stops. +The constant 16773022 here is approximately 0.99975 in Q24. +Otherwise, row k-1 of a32_Q24 is computed from row k as +
    +> 32) , + + b1[k] = ilog(div_Q30[k]) , + + b2[k] = b1[k] - 16 , + + (1<<29) - 1 + inv_Qb2[k] = ----------------------- , + div_Q30[k] >> (b2[k]+1) + + err_Q29[k] = (1<<29) + - ((div_Q30[k]<<(15-b2[k]))*inv_Qb2[k] >> 16) , + + gain_Qb1[k] = ((inv_Qb2[k] << 16) + + (err_Q29[k]*inv_Qb2[k] >> 13)) , + +num_Q24[k-1][n] = a32_Q24[k][n] + - ((a32_Q24[k][k-n-1]*rc_Q31[k] + (1<<30)) >> 31) , + +a32_Q24[k-1][n] = (num_Q24[k-1][n]*gain_Qb1[k] + + (1<<(b1[k]-1))) >> b1[k] , +]]> +
    + where 0 <= n < k. +Here, rc_Q30[k] are the reflection coefficients. +div_Q30[k] is the denominator for each iteration, and gain_Qb1[k] is its + multiplicative inverse (with b1[k] fractional bits, where b1[k] ranges from + 20 to 31). +inv_Qb2[k], which ranges from 16384 to 32767, is a low-precision version of + that inverse (with b2[k] fractional bits). +err_Q29[k] is the residual error, ranging from -32763 to 32392, which is used + to improve the accuracy. +The values t_Q24[k-1][n] for each n are the numerators for the next row of + coefficients in the recursion, and a32_Q24[k-1][n] is the final version of + that row. +Every multiply in this procedure except the one used to compute gain_Qb1[k] + requires more than 32 bits of precision, but otherwise all intermediate + results fit in 32 bits or less. +In practice, because each row only depends on the next one, an implementation + does not need to store them all. +
    + +If abs(a32_Q24[k][k]) <= 16773022 for + 0 <= k < d_LPC, then the filter is considered stable. +However, the problem of determining stability is ill-conditioned when the + filter contains several reflection coefficients whose magnitude is very close + to one. +This fixed-point algorithm is not mathematically guaranteed to correctly + classify filters as stable or unstable in this case, though it does very well + in practice. + + +On round i, 1 <= i <= 18, if the filter passes these + stability checks, then this procedure stops, and the final LPC coefficients to + use for reconstruction in are +
    +> 5 . +]]> +
    +Otherwise, a round of bandwidth expansion is applied using the same procedure + as in , with +
    + +
    +During the 15th round, sc_Q16[0] becomes 0 in the above equation, so a_Q12[k] + is set to 0 for all k, guaranteeing a stable filter. +
    +
    + +
    + +
    + +After the normalized LSF indices and, for 20 ms frames, the LSF + interpolation index, voiced frames (see ) + include additional LTP parameters. +There is one primary lag index for each SILK frame, but this is refined to + produce a separate lag index per subframe using a vector quantizer. +Each subframe also gets its own prediction gain coefficient. + + +
    + +The primary lag index is coded either relative to the primary lag of the prior + frame in the same channel, or as an absolute index. +Absolute coding is used if and only if + + +This is the first SILK frame of its type (LBRR or regular) for this channel in + the current Opus frame, + + +The previous SILK frame of the same type (LBRR or regular) for this channel in + the same Opus frame was not coded, or + + +That previous SILK frame was coded, but was not voiced (see + ). + + + + + +With absolute coding, the primary pitch lag may range from 2 ms + (inclusive) up to 18 ms (exclusive), corresponding to pitches from + 500 Hz down to 55.6 Hz, respectively. +It is comprised of a high part and a low part, where the decoder reads the high + part using the 32-entry codebook in + and the low part using the codebook corresponding to the current audio + bandwidth from . +The final primary pitch lag is then +
    + +
    + where lag_high is the high part, lag_low is the low part, and lag_scale + and lag_min are the values from the "Scale" and "Minimum Lag" columns of + , respectively. +
    + + +PDF +{3, 3, 6, 11, 21, 30, 32, 19, + 11, 10, 12, 13, 13, 12, 11, 9, + 8, 7, 6, 4, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1}/256 + + + +Audio Bandwidth +PDF +Scale +Minimum Lag +Maximum Lag +NB {64, 64, 64, 64}/256 4 16 144 +MB {43, 42, 43, 43, 42, 43}/256 6 24 216 +WB {32, 32, 32, 32, 32, 32, 32, 32}/256 8 32 288 + + + +All frames that do not use absolute coding for the primary lag index use + relative coding instead. +The decoder reads a single delta value using the 21-entry PDF in + . +If the resulting value is zero, it falls back to the absolute coding procedure + from the prior paragraph. +Otherwise, the final primary pitch lag is then +
    + +
    + where previous_lag is the primary pitch lag from the most recent frame in the + same channel and delta_lag_index is the value just decoded. +This allows a per-frame change in the pitch lag of -8 to +11 samples. +The decoder does no clamping at this point, so this value can fall outside the + range of 2 ms to 18 ms, and the decoder must use this unclamped + value when using relative coding in the next SILK frame (if any). +However, because an Opus frame can use relative coding for at most two + consecutive SILK frames, integer overflow should not be an issue. +
    + + +PDF +{46, 2, 2, 3, 4, 6, 10, 15, + 26, 38, 30, 22, 15, 10, 7, 6, + 4, 4, 2, 2, 2}/256 + + + +After the primary pitch lag, a "pitch contour", stored as a single entry from + one of four small VQ codebooks, gives lag offsets for each subframe in the + current SILK frame. +The codebook index is decoded using one of the PDFs in + depending on the current frame size + and audio bandwidth. +Tables  + through  + give the corresponding offsets to apply to the primary pitch lag for each + subframe given the decoded codebook index. + + + +Audio Bandwidth +SILK Frame Size +Codebook Size +PDF +NB 10 ms 3 +{143, 50, 63}/256 +NB 20 ms 11 +{68, 12, 21, 17, 19, 22, 30, 24, + 17, 16, 10}/256 +MB or WB 10 ms 12 +{91, 46, 39, 19, 14, 12, 8, 7, + 6, 5, 5, 4}/256 +MB or WB 20 ms 34 +{33, 22, 18, 16, 15, 14, 14, 13, + 13, 10, 9, 9, 8, 6, 6, 6, + 5, 4, 4, 4, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 1, 1, + 1, 1}/256 + + + +Index +Subframe Offsets +0  0  0 +1  1  0 +2  0  1 + + + +Index +Subframe Offsets + 0  0  0  0  0 + 1  2  1  0 -1 + 2 -1  0  1  2 + 3 -1  0  0  1 + 4 -1  0  0  0 + 5  0  0  0  1 + 6  0  0  1  1 + 7  1  1  0  0 + 8  1  0  0  0 + 9  0  0  0 -1 +10  1  0  0 -1 + + + +Index +Subframe Offsets + 0  0  0 + 1  0  1 + 2  1  0 + 3 -1  1 + 4  1 -1 + 5 -1  2 + 6  2 -1 + 7 -2  2 + 8  2 -2 + 9 -2  3 +10  3 -2 +11 -3  3 + + + +Index +Subframe Offsets + 0  0  0  0  0 + 1  0  0  1  1 + 2  1  1  0  0 + 3 -1  0  0  0 + 4  0  0  0  1 + 5  1  0  0  0 + 6 -1  0  0  1 + 7  0  0  0 -1 + 8 -1  0  1  2 + 9  1  0  0 -1 +10 -2 -1  1  2 +11  2  1  0 -1 +12 -2  0  0  2 +13 -2  0  1  3 +14  2  1 -1 -2 +15 -3 -1  1  3 +16  2  0  0 -2 +17  3  1  0 -2 +18 -3 -1  2  4 +19 -4 -1  1  4 +20  3  1 -1 -3 +21 -4 -1  2  5 +22  4  2 -1 -3 +23  4  1 -1 -4 +24 -5 -1  2  6 +25  5  2 -1 -4 +26 -6 -2  2  6 +27 -5 -2  2  5 +28  6  2 -1 -5 +29 -7 -2  3  8 +30  6  2 -2 -6 +31  5  2 -2 -5 +32  8  3 -2 -7 +33 -9 -3  3  9 + + + +The final pitch lag for each subframe is assembled in silk_decode_pitch() + (decode_pitch.c). +Let lag be the primary pitch lag for the current SILK frame, contour_index be + index of the VQ codebook, and lag_cb[contour_index][k] be the corresponding + entry of the codebook from the appropriate table given above for the k'th + subframe. +Then the final pitch lag for that subframe is +
    + +
    + where lag_min and lag_max are the values from the "Minimum Lag" and + "Maximum Lag" columns of , + respectively. +
    + +
    + +
    + +SILK uses a separate 5-tap pitch filter for each subframe, selected from one + of three codebooks. +The three codebooks each represent different rate-distortion trade-offs, with + average rates of 1.61 bits/subframe, 3.68 bits/subframe, and + 4.85 bits/subframe, respectively. + + + +The importance of the filter coefficients generally depends on two factors: the + periodicity of the signal and relative energy between the current subframe and + the signal from one period earlier. +Greater periodicity and decaying energy both lead to more important filter + coefficients, and thus should be coded with lower distortion and higher rate. +These properties are relatively stable over the duration of a single SILK + frame, hence all of the subframes in a SILK frame choose their filter from the + same codebook. +This is signaled with an explicitly-coded "periodicity index". +This immediately follows the subframe pitch lags, and is coded using the + 3-entry PDF from . + + + +PDF +{77, 80, 99}/256 + + + +The indices of the filters for each subframe follow. +They are all coded using the PDF from + corresponding to the periodicity index. +Tables  + through  + contain the corresponding filter taps as signed Q7 integers. + + + +Periodicity Index +Codebook Size +PDF +0 8 {185, 15, 13, 13, 9, 9, 6, 6}/256 +1 16 {57, 34, 21, 20, 15, 13, 12, 13, + 10, 10, 9, 10, 9, 8, 7, 8}/256 +2 32 {15, 16, 14, 12, 12, 12, 11, 11, + 11, 10, 9, 9, 9, 9, 8, 8, + 8, 8, 7, 7, 6, 6, 5, 4, + 5, 4, 4, 4, 3, 4, 3, 2}/256 + + + +Index +Filter Taps (Q7) + 0 +  4   6  24   7   5 + 1 +  0   0   2   0   0 + 2 + 12  28  41  13  -4 + 3 + -9  15  42  25  14 + 4 +  1  -2  62  41  -9 + 5 +-10  37  65  -4   3 + 6 + -6   4  66   7  -8 + 7 + 16  14  38  -3  33 + + + +Index +Filter Taps (Q7) + + 0 + 13  22  39  23  12 + 1 + -1  36  64  27  -6 + 2 + -7  10  55  43  17 + 3 +  1   1   8   1   1 + 4 +  6 -11  74  53  -9 + 5 +-12  55  76 -12   8 + 6 + -3   3  93  27  -4 + 7 + 26  39  59   3  -8 + 8 +  2   0  77  11   9 + 9 + -8  22  44  -6   7 +10 + 40   9  26   3   9 +11 + -7  20 101  -7   4 +12 +  3  -8  42  26   0 +13 +-15  33  68   2  23 +14 + -2  55  46  -2  15 +15 +  3  -1  21  16  41 + + + +Index +Filter Taps (Q7) + 0 + -6  27  61  39   5 + 1 +-11  42  88   4   1 + 2 + -2  60  65   6  -4 + 3 + -1  -5  73  56   1 + 4 + -9  19  94  29  -9 + 5 +  0  12  99   6   4 + 6 +  8 -19 102  46 -13 + 7 +  3   2  13   3   2 + 8 +  9 -21  84  72 -18 + 9 +-11  46 104 -22   8 +10 + 18  38  48  23   0 +11 +-16  70  83 -21  11 +12 +  5 -11 117  22  -8 +13 + -6  23 117 -12   3 +14 +  3  -8  95  28   4 +15 +-10  15  77  60 -15 +16 + -1   4 124   2  -4 +17 +  3  38  84  24 -25 +18 +  2  13  42  13  31 +19 + 21  -4  56  46  -1 +20 + -1  35  79 -13  19 +21 + -7  65  88  -9 -14 +22 + 20   4  81  49 -29 +23 + 20   0  75   3 -17 +24 +  5  -9  44  92  -8 +25 +  1  -3  22  69  31 +26 + -6  95  41 -12   5 +27 + 39  67  16  -4   1 +28 +  0  -6 120  55 -36 +29 +-13  44 122   4 -24 +30 + 81   5  11   3   7 +31 +  2   0   9  10  88 + + +
    + +
    + +An LTP scaling parameter appears after the LTP filter coefficients if and only + if + +This is a voiced frame (see ), and +Either + + +This SILK frame corresponds to the first time interval of the + current Opus frame for its type (LBRR or regular), or + + +This is an LBRR frame where the LBRR flags (see + ) indicate the previous LBRR frame in the same + channel is not coded. + + + + +This allows the encoder to trade off the prediction gain between + packets against the recovery time after packet loss. +Unlike absolute-coding for pitch lags, regular SILK frames that are not at the + start of an Opus frame (i.e., that do not correspond to the first 20 ms + time interval in Opus frames of 40 or 60 ms) do not include this + field, even if the prior frame was not voiced, or (in the case of the side + channel) not even coded. +After an uncoded frame in the side channel, the LTP buffer (see + ) is cleared to zero, and is thus in a + known state. +In contrast, LBRR frames do include this field when the prior frame was not + coded, since the LTP buffer contains the output of the PLC, which is + non-normative. + + +If present, the decoder reads a value using the 3-entry PDF in + . +The three possible values represent Q14 scale factors of 15565, 12288, and + 8192, respectively (corresponding to approximately 0.95, 0.75, and 0.5). +Frames that do not code the scaling parameter use the default factor of 15565 + (approximately 0.95). + + + +PDF +{128, 64, 64}/256 + + +
    + +
    + +
    + +As described in , SILK uses a + linear congruential generator (LCG) to inject pseudorandom noise into the + quantized excitation. +To ensure synchronization of this process between the encoder and decoder, each + SILK frame stores a 2-bit seed after the LTP parameters (if any). +The encoder may consider the choice of seed during quantization, and the + flexibility of this choice lets it reduce distortion, helping to pay for the + bit cost required to signal it. +The decoder reads the seed using the uniform 4-entry PDF in + , yielding a value between 0 and 3, inclusive. + + + +PDF +{64, 64, 64, 64}/256 + + +
    + +
    + +SILK codes the excitation using a modified version of the Pyramid Vector + Quantization (PVQ) codebook . +The PVQ codebook is designed for Laplace-distributed values and consists of all + sums of K signed, unit pulses in a vector of dimension N, where two pulses at + the same position are required to have the same sign. +Thus the codebook includes all integer codevectors y of dimension N that + satisfy +
    + +
    +Unlike regular PVQ, SILK uses a variable-length, rather than fixed-length, + encoding. +This encoding is better suited to the more Gaussian-like distribution of the + coefficient magnitudes and the non-uniform distribution of their signs (caused + by the quantization offset described below). +SILK also handles large codebooks by coding the least significant bits (LSBs) + of each coefficient directly. +This adds a small coding efficiency loss, but greatly reduces the computation + time and ROM size required for decoding, as implemented in + silk_decode_pulses() (decode_pulses.c). +
    + + +SILK fixes the dimension of the codebook to N = 16. +The excitation is made up of a number of "shell blocks", each 16 samples in + size. + lists the number of shell blocks + required for a SILK frame for each possible audio bandwidth and frame size. +10 ms MB frames nominally contain 120 samples (10 ms at + 12 kHz), which is not a multiple of 16. +This is handled by coding 8 shell blocks (128 samples) and discarding the final + 8 samples of the last block. +The decoder contains no special case that prevents an encoder from placing + pulses in these samples, and they must be correctly parsed from the bitstream + if present, but they are otherwise ignored. + + + +Audio Bandwidth +Frame Size +Number of Shell Blocks +NB 10 ms 5 +MB 10 ms 8 +WB 10 ms 10 +NB 20 ms 10 +MB 20 ms 15 +WB 20 ms 20 + + +
    + +The first symbol in the excitation is a "rate level", which is an index from 0 + to 8, inclusive, coded using the PDF in + corresponding to the signal type of the current frame (from + ). +The rate level selects the PDF used to decode the number of pulses in + the individual shell blocks. +It does not directly convey any information about the bitrate or the number of + pulses itself, but merely changes the probability of the symbols in + . +Level 0 provides a more efficient encoding at low rates generally, and + level 8 provides a more efficient encoding at high rates generally, + though the most efficient level for a particular SILK frame may depend on the + exact distribution of the coded symbols. +An encoder should, but is not required to, use the most efficient rate level. + + + +Signal Type +PDF +Inactive or Unvoiced +{15, 51, 12, 46, 45, 13, 33, 27, 14}/256 +Voiced +{33, 30, 36, 17, 34, 49, 18, 21, 18}/256 + + +
    + +
    + +The total number of pulses in each of the shell blocks follows the rate level. +The pulse counts for all of the shell blocks are coded consecutively, before + the content of any of the blocks. +Each block may have anywhere from 0 to 16 pulses, inclusive, coded using the + 18-entry PDF in corresponding to the + rate level from . +The special value 17 indicates that this block has one or more additional + LSBs to decode for each coefficient. +If the decoder encounters this value, it decodes another value for the actual + pulse count of the block, but uses the PDF corresponding to the special rate + level 9 instead of the normal rate level. +This process repeats until the decoder reads a value less than 17, and it then + sets the number of extra LSBs used to the number of 17's decoded for that + block. +If it reads the value 17 ten times, then the next iteration uses the special + rate level 10 instead of 9. +The probability of decoding a 17 when using the PDF for rate level 10 is + zero, ensuring that the number of LSBs for a block will not exceed 10. +The cumulative distribution for rate level 10 is just a shifted version of + that for 9 and thus does not require any additional storage. + + + +Rate Level +PDF +0 +{131, 74, 25, 8, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +1 +{58, 93, 60, 23, 7, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +2 +{43, 51, 46, 33, 24, 16, 11, 8, 6, 3, 3, 3, 2, 1, 1, 2, 1, 2}/256 +3 +{17, 52, 71, 57, 31, 12, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +4 +{6, 21, 41, 53, 49, 35, 21, 11, 6, 3, 2, 2, 1, 1, 1, 1, 1, 1}/256 +5 +{7, 14, 22, 28, 29, 28, 25, 20, 17, 13, 11, 9, 7, 5, 4, 4, 3, 10}/256 +6 +{2, 5, 14, 29, 42, 46, 41, 31, 19, 11, 6, 3, 2, 1, 1, 1, 1, 1}/256 +7 +{1, 2, 4, 10, 19, 29, 35, 37, 34, 28, 20, 14, 8, 5, 4, 2, 2, 2}/256 +8 +{1, 2, 2, 5, 9, 14, 20, 24, 27, 28, 26, 23, 20, 15, 11, 8, 6, 15}/256 +9 +{1, 1, 1, 6, 27, 58, 56, 39, 25, 14, 10, 6, 3, 3, 2, 1, 1, 2}/256 +10 +{2, 1, 6, 27, 58, 56, 39, 25, 14, 10, 6, 3, 3, 2, 1, 1, 2, 0}/256 + + +
    + +
    + +The locations of the pulses in each shell block follow the pulse counts, + as decoded by silk_shell_decoder() (shell_coder.c). +As with the pulse counts, these locations are coded for all the shell blocks + before any of the remaining information for each block. +Unlike many other codecs, SILK places no restriction on the distribution of + pulses within a shell block. +All of the pulses may be placed in a single location, or each one in a unique + location, or anything in between. + + + +The location of pulses is coded by recursively partitioning each block into + halves, and coding how many pulses fall on the left side of the split. +All remaining pulses must fall on the right side of the split. +The process then recurses into the left half, and after that returns, the + right half (preorder traversal). +The PDF to use is chosen by the size of the current partition (16, 8, 4, or 2) + and the number of pulses in the partition (1 to 16, inclusive). +Tables  + through  list the + PDFs used for each partition size and pulse count. +This process skips partitions without any pulses, i.e., where the initial pulse + count from was zero, or where the split in + the prior level indicated that all of the pulses fell on the other side. +These partitions have nothing to code, so they require no PDF. + + + +Pulse Count +PDF + 1 {126, 130}/256 + 2 {56, 142, 58}/256 + 3 {25, 101, 104, 26}/256 + 4 {12, 60, 108, 64, 12}/256 + 5 {7, 35, 84, 87, 37, 6}/256 + 6 {4, 20, 59, 86, 63, 21, 3}/256 + 7 {3, 12, 38, 72, 75, 42, 12, 2}/256 + 8 {2, 8, 25, 54, 73, 59, 27, 7, 1}/256 + 9 {2, 5, 17, 39, 63, 65, 42, 18, 4, 1}/256 +10 {1, 4, 12, 28, 49, 63, 54, 30, 11, 3, 1}/256 +11 {1, 4, 8, 20, 37, 55, 57, 41, 22, 8, 2, 1}/256 +12 {1, 3, 7, 15, 28, 44, 53, 48, 33, 16, 6, 1, 1}/256 +13 {1, 2, 6, 12, 21, 35, 47, 48, 40, 25, 12, 5, 1, 1}/256 +14 {1, 1, 4, 10, 17, 27, 37, 47, 43, 33, 21, 9, 4, 1, 1}/256 +15 {1, 1, 1, 8, 14, 22, 33, 40, 43, 38, 28, 16, 8, 1, 1, 1}/256 +16 {1, 1, 1, 1, 13, 18, 27, 36, 41, 41, 34, 24, 14, 1, 1, 1, 1}/256 + + + +Pulse Count +PDF + 1 {127, 129}/256 + 2 {53, 149, 54}/256 + 3 {22, 105, 106, 23}/256 + 4 {11, 61, 111, 63, 10}/256 + 5 {6, 35, 86, 88, 36, 5}/256 + 6 {4, 20, 59, 87, 62, 21, 3}/256 + 7 {3, 13, 40, 71, 73, 41, 13, 2}/256 + 8 {3, 9, 27, 53, 70, 56, 28, 9, 1}/256 + 9 {3, 8, 19, 37, 57, 61, 44, 20, 6, 1}/256 +10 {3, 7, 15, 28, 44, 54, 49, 33, 17, 5, 1}/256 +11 {1, 7, 13, 22, 34, 46, 48, 38, 28, 14, 4, 1}/256 +12 {1, 1, 11, 22, 27, 35, 42, 47, 33, 25, 10, 1, 1}/256 +13 {1, 1, 6, 14, 26, 37, 43, 43, 37, 26, 14, 6, 1, 1}/256 +14 {1, 1, 4, 10, 20, 31, 40, 42, 40, 31, 20, 10, 4, 1, 1}/256 +15 {1, 1, 3, 8, 16, 26, 35, 38, 38, 35, 26, 16, 8, 3, 1, 1}/256 +16 {1, 1, 2, 6, 12, 21, 30, 36, 38, 36, 30, 21, 12, 6, 2, 1, 1}/256 + + + +Pulse Count +PDF + 1 {127, 129}/256 + 2 {49, 157, 50}/256 + 3 {20, 107, 109, 20}/256 + 4 {11, 60, 113, 62, 10}/256 + 5 {7, 36, 84, 87, 36, 6}/256 + 6 {6, 24, 57, 82, 60, 23, 4}/256 + 7 {5, 18, 39, 64, 68, 42, 16, 4}/256 + 8 {6, 14, 29, 47, 61, 52, 30, 14, 3}/256 + 9 {1, 15, 23, 35, 51, 50, 40, 30, 10, 1}/256 +10 {1, 1, 21, 32, 42, 52, 46, 41, 18, 1, 1}/256 +11 {1, 6, 16, 27, 36, 42, 42, 36, 27, 16, 6, 1}/256 +12 {1, 5, 12, 21, 31, 38, 40, 38, 31, 21, 12, 5, 1}/256 +13 {1, 3, 9, 17, 26, 34, 38, 38, 34, 26, 17, 9, 3, 1}/256 +14 {1, 3, 7, 14, 22, 29, 34, 36, 34, 29, 22, 14, 7, 3, 1}/256 +15 {1, 2, 5, 11, 18, 25, 31, 35, 35, 31, 25, 18, 11, 5, 2, 1}/256 +16 {1, 1, 4, 9, 15, 21, 28, 32, 34, 32, 28, 21, 15, 9, 4, 1, 1}/256 + + + +Pulse Count +PDF + 1 {128, 128}/256 + 2 {42, 172, 42}/256 + 3 {21, 107, 107, 21}/256 + 4 {12, 60, 112, 61, 11}/256 + 5 {8, 34, 86, 86, 35, 7}/256 + 6 {8, 23, 55, 90, 55, 20, 5}/256 + 7 {5, 15, 38, 72, 72, 36, 15, 3}/256 + 8 {6, 12, 27, 52, 77, 47, 20, 10, 5}/256 + 9 {6, 19, 28, 35, 40, 40, 35, 28, 19, 6}/256 +10 {4, 14, 22, 31, 37, 40, 37, 31, 22, 14, 4}/256 +11 {3, 10, 18, 26, 33, 38, 38, 33, 26, 18, 10, 3}/256 +12 {2, 8, 13, 21, 29, 36, 38, 36, 29, 21, 13, 8, 2}/256 +13 {1, 5, 10, 17, 25, 32, 38, 38, 32, 25, 17, 10, 5, 1}/256 +14 {1, 4, 7, 13, 21, 29, 35, 36, 35, 29, 21, 13, 7, 4, 1}/256 +15 {1, 2, 5, 10, 17, 25, 32, 36, 36, 32, 25, 17, 10, 5, 2, 1}/256 +16 {1, 2, 4, 7, 13, 21, 28, 34, 36, 34, 28, 21, 13, 7, 4, 2, 1}/256 + + +
    + +
    + +After the decoder reads the pulse locations for all blocks, it reads the LSBs + (if any) for each block in turn. +Inside each block, it reads all the LSBs for each coefficient in turn, even + those where no pulses were allocated, before proceeding to the next one. +For 10 ms MB frames, it reads LSBs even for the extra 8 samples in + the last block. +The LSBs are coded from most significant to least significant, and they all use + the PDF in . + + + +PDF +{136, 120}/256 + + + +The number of LSBs read for each coefficient in a block is determined in + . +The magnitude of the coefficient is initially equal to the number of pulses + placed at that location in . +As each LSB is decoded, the magnitude is doubled, and then the value of the LSB + added to it, to obtain an updated magnitude. + +
    + +
    + +After decoding the pulse locations and the LSBs, the decoder knows the + magnitude of each coefficient in the excitation. +It then decodes a sign for all coefficients with a non-zero magnitude, using + one of the PDFs from . +If the value decoded is 0, then the coefficient magnitude is negated. +Otherwise, it remains positive. + + + +The decoder chooses the PDF for the sign based on the signal type and + quantization offset type (from ) and the + number of pulses in the block (from ). +The number of pulses in the block does not take into account any LSBs. +Most PDFs are skewed towards negative signs because of the quantization offset, + but the PDFs for zero pulses are highly skewed towards positive signs. +If a block contains many positive coefficients, it is sometimes beneficial to + code it solely using LSBs (i.e., with zero pulses), since the encoder may be + able to save enough bits on the signs to justify the less efficient + coefficient magnitude encoding. + + + +Signal Type +Quantization Offset Type +Pulse Count +PDF +Inactive Low 0 {2, 254}/256 +Inactive Low 1 {207, 49}/256 +Inactive Low 2 {189, 67}/256 +Inactive Low 3 {179, 77}/256 +Inactive Low 4 {174, 82}/256 +Inactive Low 5 {163, 93}/256 +Inactive Low 6 or more {157, 99}/256 +Inactive High 0 {58, 198}/256 +Inactive High 1 {245, 11}/256 +Inactive High 2 {238, 18}/256 +Inactive High 3 {232, 24}/256 +Inactive High 4 {225, 31}/256 +Inactive High 5 {220, 36}/256 +Inactive High 6 or more {211, 45}/256 +Unvoiced Low 0 {1, 255}/256 +Unvoiced Low 1 {210, 46}/256 +Unvoiced Low 2 {190, 66}/256 +Unvoiced Low 3 {178, 78}/256 +Unvoiced Low 4 {169, 87}/256 +Unvoiced Low 5 {162, 94}/256 +Unvoiced Low 6 or more {152, 104}/256 +Unvoiced High 0 {48, 208}/256 +Unvoiced High 1 {242, 14}/256 +Unvoiced High 2 {235, 21}/256 +Unvoiced High 3 {224, 32}/256 +Unvoiced High 4 {214, 42}/256 +Unvoiced High 5 {205, 51}/256 +Unvoiced High 6 or more {190, 66}/256 +Voiced Low 0 {1, 255}/256 +Voiced Low 1 {162, 94}/256 +Voiced Low 2 {152, 104}/256 +Voiced Low 3 {147, 109}/256 +Voiced Low 4 {144, 112}/256 +Voiced Low 5 {141, 115}/256 +Voiced Low 6 or more {138, 118}/256 +Voiced High 0 {8, 248}/256 +Voiced High 1 {203, 53}/256 +Voiced High 2 {187, 69}/256 +Voiced High 3 {176, 80}/256 +Voiced High 4 {168, 88}/256 +Voiced High 5 {161, 95}/256 +Voiced High 6 or more {154, 102}/256 + + +
    + +
    + + +After the signs have been read, there is enough information to reconstruct the + complete excitation signal. +This requires adding a constant quantization offset to each non-zero sample, + and then pseudorandomly inverting and offsetting every sample. +The constant quantization offset varies depending on the signal type and + quantization offset type (see ). + + + +Signal Type +Quantization Offset Type +Quantization Offset (Q23) +Inactive Low 25 +Inactive High 60 +Unvoiced Low 25 +Unvoiced High 60 +Voiced Low 8 +Voiced High 25 + + + +Let e_raw[i] be the raw excitation value at position i, with a magnitude + composed of the pulses at that location (see + ) combined with any additional LSBs (see + ), and with the corresponding sign decoded in + . +Additionally, let seed be the current pseudorandom seed, which is initialized + to the value decoded from for the first sample in + the current SILK frame, and updated for each subsequent sample according to + the procedure below. +Finally, let offset_Q23 be the quantization offset from + . +Then the following procedure produces the final reconstructed excitation value, + e_Q23[i]: +
    + +
    +When e_raw[i] is zero, sign() returns 0 by the definition in + , so the factor of 20 does not get added. +The final e_Q23[i] value may require more than 16 bits per sample, but will not + require more than 23, including the sign. +
    + +
    + +
    + +
    + + +The remainder of the reconstruction process for the frame does not need to be + bit-exact, as small errors should only introduce proportionally small + distortions. +Although the reference implementation only includes a fixed-point version of + the remaining steps, this section describes them in terms of a floating-point + version for simplicity. +This produces a signal with a nominal range of -1.0 to 1.0. + + + +silk_decode_core() (decode_core.c) contains the code for the main + reconstruction process. +It proceeds subframe-by-subframe, since quantization gains, LTP parameters, and + (in 20 ms SILK frames) LPC coefficients can vary from one to the + next. + + + +Let a_Q12[k] be the LPC coefficients for the current subframe. +If this is the first or second subframe of a 20 ms SILK frame and the LSF + interpolation factor, w_Q2 (see ), is + less than 4, then these correspond to the final LPC coefficients produced by + from the interpolated LSF coefficients, + n1_Q15[k] (computed in ). +Otherwise, they correspond to the final LPC coefficients produced from the + uninterpolated LSF coefficients for the current frame, n2_Q15[k]. + + + +Also, let n be the number of samples in a subframe (40 for NB, 60 for MB, and + 80 for WB), s be the index of the current subframe in this SILK frame (0 or 1 + for 10 ms frames, or 0 to 3 for 20 ms frames), and j be the index of + the first sample in the residual corresponding to the current subframe. + + +
    + +Voiced SILK frames (see ) pass the excitation + through an LTP filter using the parameters decoded in + to produce an LPC residual. +The LTP filter requires LPC residual values from before the current subframe as + input. +However, since the LPC coefficients may have changed, it obtains this residual + by "rewhitening" the corresponding output signal using the LPC coefficients + from the current subframe. +Let out[i] for + (j - pitch_lags[s] - d_LPC - 2) <= i < j + be the fully reconstructed output signal from the last + (pitch_lags[s] + d_LPC + 2) samples of previous subframes + (see ), where pitch_lags[s] is the pitch + lag for the current subframe from . +During reconstruction of the first subframe for this channel after either + +An uncoded regular SILK frame (if this is the side channel), or +A decoder reset (see ), + + out[] is rewhitened into an LPC residual, + res[i], via +
    + +
    +This requires storage to buffer up to 306 values of out[i] from previous + subframes. +This corresponds to WB with a maximum pitch lag of + 18 ms * 16 kHz samples, plus 16 samples for d_LPC, plus 2 + samples for the width of the LTP filter. +
    + + +Let e_Q23[i] for j <= i < (j + n) be the + excitation for the current subframe, and b_Q7[k] for + 0 <= k < 5 be the coefficients of the LTP filter + taken from the codebook entry in one of + Tables  + through  + corresponding to the index decoded for the current subframe in + . +Then for i such that j <= i < (j + n), + the LPC residual is +
    + +
    +
    + + +For unvoiced frames, the LPC residual for + j <= i < (j + n) is simply a normalized + copy of the excitation signal, i.e., +
    + +
    +
    +
    + +
    + +LPC synthesis uses the short-term LPC filter to predict the next output + coefficient. +For i such that (j - d_LPC) <= i < j, let + lpc[i] be the result of LPC synthesis from the last d_LPC samples of the + previous subframe, or zeros in the first subframe for this channel after + either + +An uncoded regular SILK frame (if this is the side channel), or +A decoder reset (see ). + +Then for i such that j <= i < (j + n), the + result of LPC synthesis for the current subframe is +
    + +
    +The decoder saves the final d_LPC values, i.e., lpc[i] such that + (j + n - d_LPC) <= i < (j + n), + to feed into the LPC synthesis of the next subframe. +This requires storage for up to 16 values of lpc[i] (for WB frames). +
    + + +Then, the signal is clamped into the final nominal range: +
    + +
    +This clamping occurs entirely after the LPC synthesis filter has run. +The decoder saves the unclamped values, lpc[i], to feed into the LPC filter for + the next subframe, but saves the clamped values, out[i], for rewhitening in + voiced frames. +
    +
    + +
    + +
    + +
    + +For stereo streams, after decoding a frame from each channel, the decoder must + convert the mid-side (MS) representation into a left-right (LR) + representation. +The function silk_stereo_MS_to_LR (stereo_MS_to_LR.c) implements this process. +In it, the decoder predicts the side channel using a) a simple low-passed + version of the mid channel, and b) the unfiltered mid channel, using the + prediction weights decoded in . +This simple low-pass filter imposes a one-sample delay, and the unfiltered +mid channel is also delayed by one sample. +In order to allow seamless switching between stereo and mono, mono streams must + also impose the same one-sample delay. +The encoder requires an additional one-sample delay for both mono and stereo + streams, though an encoder may omit the delay for mono if it knows it will + never switch to stereo. + + + +The unmixing process operates in two phases. +The first phase lasts for 8 ms, during which it interpolates the + prediction weights from the previous frame, prev_w0_Q13 and prev_w1_Q13, to + the values for the current frame, w0_Q13 and w1_Q13. +The second phase simply uses these weights for the remainder of the frame. + + + +Let mid[i] and side[i] be the contents of out[i] (from + ) for the current mid and side channels, + respectively, and let left[i] and right[i] be the corresponding stereo output + channels. +If the side channel is not coded (see ), + then side[i] is set to zero. +Also let j be defined as in , n1 be + the number of samples in phase 1 (64 for NB, 96 for MB, and 128 for WB), + and n2 be the total number of samples in the frame. +Then for i such that j <= i < (j + n2), + the left and right channel output is +
    + +
    +These formulas require two samples prior to index j, the start of the + frame, for the mid channel, and one prior sample for the side channel. +For the first frame after a decoder reset, zeros are used instead. +
    + +
    + +
    + +After stereo unmixing (if any), the decoder applies resampling to convert the + decoded SILK output to the sample rate desired by the application. +This is necessary when decoding a Hybrid frame at SWB or FB sample rates, or + whenever the decoder wants the output at a different sample rate than the + internal SILK sampling rate (e.g., to allow a constant sample rate when the + audio bandwidth changes, or to allow mixing with audio from other + applications). +The resampler itself is non-normative, and a decoder can use any method it + wants to perform the resampling. + + + +However, a minimum amount of delay is imposed to allow the resampler to + operate, and this delay is normative, so that the corresponding delay can be + applied to the MDCT layer in the encoder. +A decoder is always free to use a resampler which requires more delay than + allowed for here (e.g., to improve quality), but it must then delay the output + of the MDCT layer by this extra amount. +Keeping as much delay as possible on the encoder side allows an encoder which + knows it will never use any of the SILK or Hybrid modes to skip this delay. +By contrast, if it were all applied by the decoder, then a decoder which + processes audio in fixed-size blocks would be forced to delay the output of + CELT frames just in case of a later switch to a SILK or Hybrid mode. + + + + gives the maximum resampler delay + in samples at 48 kHz for each SILK audio bandwidth. +Because the actual output rate may not be 48 kHz, it may not be possible + to achieve exactly these delays while using a whole number of input or output + samples. +The reference implementation is able to resample to any of the supported + output sampling rates (8, 12, 16, 24, or 48 kHz) within or near this + delay constraint. +Some resampling filters (including those used by the reference implementation) + may add a delay that is not an exact integer, or is not linear-phase, and so + cannot be represented by a single delay at all frequencies. +However, such deviations are unlikely to be perceptible, and the comparison + tool described in is designed to be relatively + insensitive to them. +The delays listed here are the ones that should be targeted by the encoder. + + + +Audio Bandwidth +Delay in millisecond +NB 0.538 +MB 0.692 +WB 0.706 + + + +NB is given a smaller decoder delay allocation than MB and WB to allow a + higher-order filter when resampling to 8 kHz in both the encoder and + decoder. +This implies that the audio content of two SILK frames operating at different + bandwidths are not perfectly aligned in time. +This is not an issue for any transitions described in + , because they all involve a SILK decoder reset. +When the decoder is reset, any samples remaining in the resampling buffer + are discarded, and the resampler is re-initialized with silence. + + +
    + +
    + + +
    + + +The CELT layer of Opus is based on the Modified Discrete Cosine Transform + with partially overlapping windows of 5 to 22.5 ms. +The main principle behind CELT is that the MDCT spectrum is divided into +bands that (roughly) follow the Bark scale, i.e., the scale of the ear's +critical bands . The normal CELT layer uses 21 of those bands, though Opus + Custom (see ) may use a different number of bands. +In Hybrid mode, the first 17 bands (up to 8 kHz) are not coded. +A band can contain as little as one MDCT bin per channel, and as many as 176 +bins per channel, as detailed in . +In each band, the gain (energy) is coded separately from +the shape of the spectrum. Coding the gain explicitly makes it easy to +preserve the spectral envelope of the signal. The remaining unit-norm shape +vector is encoded using a Pyramid Vector Quantizer (PVQ) . + + + +Frame Size: +2.5 ms +5 ms +10 ms +20 ms +Start Frequency +Stop Frequency +Band Bins: + 0 1 2 4 8 0 Hz 200 Hz + 1 1 2 4 8 200 Hz 400 Hz + 2 1 2 4 8 400 Hz 600 Hz + 3 1 2 4 8 600 Hz 800 Hz + 4 1 2 4 8 800 Hz 1000 Hz + 5 1 2 4 8 1000 Hz 1200 Hz + 6 1 2 4 8 1200 Hz 1400 Hz + 7 1 2 4 8 1400 Hz 1600 Hz + 8 2 4 8 16 1600 Hz 2000 Hz + 9 2 4 8 16 2000 Hz 2400 Hz +10 2 4 8 16 2400 Hz 2800 Hz +11 2 4 8 16 2800 Hz 3200 Hz +12 4 8 16 32 3200 Hz 4000 Hz +13 4 8 16 32 4000 Hz 4800 Hz +14 4 8 16 32 4800 Hz 5600 Hz +15 6 12 24 48 5600 Hz 6800 Hz +16 6 12 24 48 6800 Hz 8000 Hz +17 8 16 32 64 8000 Hz 9600 Hz +18 12 24 48 96 9600 Hz 12000 Hz +19 18 36 72 144 12000 Hz 15600 Hz +20 22 44 88 176 15600 Hz 20000 Hz + + + +Transients are notoriously difficult for transform codecs to code. +CELT uses two different strategies for them: + +Using multiple smaller MDCTs instead of a single large MDCT, and +Dynamic time-frequency resolution changes (See ). + +To improve quality on highly tonal and periodic signals, CELT includes +a prefilter/postfilter combination. The prefilter on the encoder side +attenuates the signal's harmonics. The postfilter on the decoder side +restores the original gain of the harmonics, while shaping the coding noise +to roughly follow the harmonics. Such noise shaping reduces the perception +of the noise. + + + +When coding a stereo signal, three coding methods are available: + +mid-side stereo: encodes the mean and the difference of the left and right channels, +intensity stereo: only encodes the mean of the left and right channels (discards the difference), +dual stereo: encodes the left and right channels separately. + + + + +An overview of the decoder is given in . + + +
    +| decoder |----+ + | +---------+ | + | | + | +---------+ v + | | Fine | +---+ + +->| decoder |->| + | + | +---------+ +---+ + | ^ | ++---------+ | | | +| Range | | +----------+ v +| Decoder |-+ | Bit | +------+ ++---------+ | |Allocation| | 2**x | + | +----------+ +------+ + | | | + | v v +--------+ + | +---------+ +---+ +-------+ | pitch | + +->| PVQ |->| * |->| IMDCT |->| post- |---> + | | decoder | +---+ +-------+ | filter | + | +---------+ +--------+ + | ^ + +--------------------------------------+ +]]> +
    + + +The decoder is based on the following symbols and sets of symbols: + + + +Symbol(s) +PDF +Condition +silence {32767, 1}/32768 +post-filter {1, 1}/2 +octave uniform (6)post-filter +period raw bits (4+octave)post-filter +gain raw bits (3)post-filter +tapset {2, 1, 1}/4post-filter +transient {7, 1}/8 +intra {7, 1}/8 +coarse energy +tf_change +tf_select {1, 1}/2 +spread {7, 2, 21, 2}/32 +dyn. alloc. +alloc. trim {2, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2}/128 +skip {1, 1}/2 +intensity uniform +dual {1, 1}/2 +fine energy +residual +anti-collapse{1, 1}/2 +finalize + + + +The decoder extracts information from the range-coded bitstream in the order +described in . In some circumstances, it is +possible for a decoded value to be out of range due to a very small amount of redundancy +in the encoding of large integers by the range coder. +In that case, the decoder should assume there has been an error in the coding, +decoding, or transmission and SHOULD take measures to conceal the error and/or report +to the application that a problem has occurred. Such out of range errors cannot occur +in the SILK layer. + + +
    + +The "transient" flag indicates whether the frame uses a single long MDCT or several short MDCTs. +When it is set, then the MDCT coefficients represent multiple +short MDCTs in the frame. When not set, the coefficients represent a single +long MDCT for the frame. The flag is encoded in the bitstream with a probability of 1/8. +In addition to the global transient flag is a per-band +binary flag to change the time-frequency (tf) resolution independently in each band. The +change in tf resolution is defined in tf_select_table[][] in celt.c and depends +on the frame size, whether the transient flag is set, and the value of tf_select. +The tf_select flag uses a 1/2 probability, but is only decoded +if it can have an impact on the result knowing the value of all per-band +tf_change flags. + +
    + +
    + + +It is important to quantize the energy with sufficient resolution because +any energy quantization error cannot be compensated for at a later +stage. Regardless of the resolution used for encoding the spectral shape of a band, +it is perceptually important to preserve the energy in each band. CELT uses a +three-step coarse-fine-fine strategy for encoding the energy in the base-2 log +domain, as implemented in quant_bands.c + +
    + +Coarse quantization of the energy uses a fixed resolution of 6 dB +(integer part of base-2 log). To minimize the bitrate, prediction is applied +both in time (using the previous frame) and in frequency (using the previous +bands). The part of the prediction that is based on the +previous frame can be disabled, creating an "intra" frame where the energy +is coded without reference to prior frames. The decoder first reads the intra flag +to determine what prediction is used. +The 2-D z-transform of +the prediction filter is: +
    + +
    +where b is the band index and l is the frame index. The prediction coefficients +applied depend on the frame size in use when not using intra energy and are alpha=0, beta=4915/32768 +when using intra energy. +The time-domain prediction is based on the final fine quantization of the previous +frame, while the frequency domain (within the current frame) prediction is based +on coarse quantization only (because the fine quantization has not been computed +yet). The prediction is clamped internally so that fixed point implementations with +limited dynamic range always remain in the same state as floating point implementations. +We approximate the ideal +probability distribution of the prediction error using a Laplace distribution +with separate parameters for each frame size in intra- and inter-frame modes. These +parameters are held in the e_prob_model table in quant_bands.c. +The +coarse energy quantization is performed by unquant_coarse_energy() and +unquant_coarse_energy_impl() (quant_bands.c). The encoding of the Laplace-distributed values is +implemented in ec_laplace_decode() (laplace.c). +
    + +
    + +
    + +The number of bits assigned to fine energy quantization in each band is determined +by the bit allocation computation described in . +Let B_i be the number of fine energy bits +for band i; the refinement is an integer f in the range [0,2**B_i-1]. The mapping between f +and the correction applied to the coarse energy is equal to (f+1/2)/2**B_i - 1/2. Fine +energy quantization is implemented in quant_fine_energy() (quant_bands.c). + + +When some bits are left "unused" after all other flags have been decoded, these bits +are assigned to a "final" step of fine allocation. In effect, these bits are used +to add one extra fine energy bit per band per channel. The allocation process +determines two "priorities" for the final fine bits. +Any remaining bits are first assigned only to bands of priority 0, starting +from band 0 and going up. If all bands of priority 0 have received one bit per +channel, then bands of priority 1 are assigned an extra bit per channel, +starting from band 0. If any bits are left after this, they are left unused. +This is implemented in unquant_energy_finalise() (quant_bands.c). + + +
    + +
    + +
    + +Because the bit allocation drives the decoding of the range-coder +stream, it MUST be recovered exactly so that identical coding decisions are +made in the encoder and decoder. Any deviation from the reference's resulting +bit allocation will result in corrupted output, though implementers are +free to implement the procedure in any way which produces identical results. + +The per-band gain-shape structure of the CELT layer ensures that using + the same number of bits for the spectral shape of a band in every frame will + result in a roughly constant signal-to-noise ratio in that band. +This results in coding noise that has the same spectral envelope as the signal. +The masking curve produced by a standard psychoacoustic model also closely + follows the spectral envelope of the signal. +This structure means that the ideal allocation is more consistent from frame to + frame than it is for other codecs without an equivalent structure, and that a + fixed allocation provides fairly consistent perceptual + performance . + +Many codecs transmit significant amounts of side information to control the + bit allocation within a frame. +Often this control is only indirect, and must be exercised carefully to + achieve the desired rate constraints. +The CELT layer, however, can adapt over a very wide range of rates, and thus + has a large number of codebook sizes to choose from for each band. +Explicitly signaling the size of each of these codebooks would impose + considerable overhead, even though the allocation is relatively static from + frame to frame. +This is because all of the information required to compute these codebook sizes + must be derived from a single frame by itself, in order to retain robustness + to packet loss, so the signaling cannot take advantage of knowledge of the + allocation in neighboring frames. +This problem is exacerbated in low-latency (small frame size) applications, + which would include this overhead in every frame. + +For this reason, in the MDCT mode Opus uses a primarily implicit bit +allocation. The available bitstream capacity is known in advance to both +the encoder and decoder without additional signaling, ultimately from the +packet sizes expressed by a higher-level protocol. Using this information, +the codec interpolates an allocation from a hard-coded table. + +While the band-energy structure effectively models intra-band masking, +it ignores the weaker inter-band masking, band-temporal masking, and +other less significant perceptual effects. While these effects can +often be ignored, they can become significant for particular samples. One +mechanism available to encoders would be to simply increase the overall +rate for these frames, but this is not possible in a constant rate mode +and can be fairly inefficient. As a result three explicitly signaled +mechanisms are provided to alter the implicit allocation: + + + +Band boost +Allocation trim +Band skipping + + + +The first of these mechanisms, band boost, allows an encoder to boost +the allocation in specific bands. The second, allocation trim, works by +biasing the overall allocation towards higher or lower frequency bands. The third, band +skipping, selects which low-precision high frequency bands +will be allocated no shape bits at all. + +In stereo mode there are two additional parameters +potentially coded as part of the allocation procedure: a parameter to allow the +selective elimination of allocation for the 'side' (i.e., intensity stereo) in jointly coded bands, +and a flag to deactivate joint coding (i.e., dual stereo). These values are not signaled if +they would be meaningless in the overall context of the allocation. + +Because every signaled adjustment increases overhead and implementation +complexity, none were included speculatively: the reference encoder makes use +of all of these mechanisms. While the decision logic in the reference was +found to be effective enough to justify the overhead and complexity, further +analysis techniques may be discovered which increase the effectiveness of these +parameters. As with other signaled parameters, an encoder is free to choose the +values in any manner, but unless a technique is known to deliver superior +perceptual results the methods used by the reference implementation should be +used. + +The allocation process consists of the following steps: determining the per-band +maximum allocation vector, decoding the boosts, decoding the tilt, determining +the remaining capacity of the frame, searching the mode table for the +entry nearest but not exceeding the available space (subject to the tilt, boosts, band +maximums, and band minimums), linear interpolation, reallocation of +unused bits with concurrent skip decoding, determination of the +fine-energy vs. shape split, and final reallocation. This process results +in a per-band shape allocation (in 1/8th bit units), a per-band fine-energy +allocation (in 1 bit per channel units), a set of band priorities for +controlling the use of remaining bits at the end of the frame, and a +remaining balance of unallocated space, which is usually zero except +at very high rates. + + +The "static" bit allocation (in 1/8 bits) for a quality q, excluding the minimums, maximums, +tilt and boosts, is equal to channels*N*alloc[band][q]<<LM>>2, where +alloc[][] is given in and LM=log2(frame_size/120). The allocation +is obtained by linearly interpolating between two values of q (in steps of 1/64) to find the +highest allocation that does not exceed the number of bits remaining. + + + + Rows indicate the MDCT bands, columns are the different quality (q) parameters. The units are 1/32 bit per MDCT bin. +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +090110118126134144152162172200 +080100110119127137145155165200 +07590103112120130138148158200 +0698493104114124132142152200 +063788695103113123133143200 +05671808997107117127137200 +04965758391101111121131200 +0405870788595105115125200 +034516572788898108118198 +029455966728292102112193 +02039536066768696106188 +01832475460708090100183 +0102640475464748494178 +002031394757677787173 +001223324151617181168 +00015253545556575163 +0004172939495969158 +0000122333435363153 +000011626364656148 +000001015203045129 +00000111120104 + + +The maximum allocation vector is an approximation of the maximum space +that can be used by each band for a given mode. The value is +approximate because the shape encoding is variable rate (due +to entropy coding of splitting parameters). Setting the maximum too low reduces the +maximum achievable quality in a band while setting it too high +may result in waste: bitstream capacity available at the end +of the frame which can not be put to any use. The maximums +specified by the codec reflect the average maximum. In the reference +implementation, the maximums in bits/sample are precomputed in a static table +(see cache_caps50[] in static_modes_float.h) for each band, +for each value of LM, and for both mono and stereo. + +Implementations are expected +to simply use the same table data, but the procedure for generating +this table is included in rate.c as part of compute_pulse_cache(). + +To convert the values in cache.caps into the actual maximums: first +set nbBands to the maximum number of bands for this mode, and stereo to +zero if stereo is not in use and one otherwise. For each band set N +to the number of MDCT bins covered by the band (for one channel), set LM +to the shift value for the frame size, +then set i to nbBands*(2*LM+stereo). Then set the maximum for the band to +the i-th index of cache.caps + 64 and multiply by the number of channels +in the current frame (one or two) and by N, then divide the result by 4 +using integer division. The resulting vector will be called +cap[]. The elements fit in signed 16-bit integers but do not fit in 8 bits. +This procedure is implemented in the reference in the function init_caps() in celt.c. + + +The band boosts are represented by a series of binary symbols which +are entropy coded with very low probability. Each band can potentially be boosted +multiple times, subject to the frame actually having enough room to obey +the boost and having enough room to code the boost symbol. The default +coding cost for a boost starts out at six bits (probability p=1/64), but subsequent boosts +in a band cost only a single bit and every time a band is boosted the +initial cost is reduced (down to a minimum of two bits, or p=1/4). Since the initial +cost of coding a boost is 6 bits, the coding cost of the boost symbols when +completely unused is 0.48 bits/frame for a 21 band mode (21*-log2(1-1/2**6)). + +To decode the band boosts: First set 'dynalloc_logp' to 6, the initial +amount of storage required to signal a boost in bits, 'total_bits' to the +size of the frame in 8th bits, 'total_boost' to zero, and 'tell' to the total number +of 8th bits decoded +so far. For each band from the coding start (0 normally, but 17 in Hybrid mode) +to the coding end (which changes depending on the signaled bandwidth), the boost quanta +in units of 1/8 bit is calculated as quanta = min(8*N, max(48, N)). +This represents a boost step size of six bits, subject to a lower limit of +1/8th bit/sample and an upper limit of 1 bit/sample. +Set 'boost' to zero and 'dynalloc_loop_logp' +to dynalloc_logp. While dynalloc_loop_log (the current worst case symbol cost) in +8th bits plus tell is less than total_bits plus total_boost and boost is less than cap[] for this +band: Decode a bit from the bitstream with a with dynalloc_loop_logp as the cost +of a one, update tell to reflect the current used capacity, if the decoded value +is zero break the loop otherwise add quanta to boost and total_boost, subtract quanta from +total_bits, and set dynalloc_loop_log to 1. When the while loop finishes +boost contains the boost for this band. If boost is non-zero and dynalloc_logp +is greater than 2, decrease dynalloc_logp. Once this process has been +executed on all bands, the band boosts have been decoded. This procedure +is implemented around line 2474 of celt.c. + +At very low rates it is possible that there won't be enough available +space to execute the inner loop even once. In these cases band boost +is not possible but its overhead is completely eliminated. Because of the +high cost of band boost when activated, a reasonable encoder should not be +using it at very low rates. The reference implements its dynalloc decision +logic around line 1304 of celt.c. + +The allocation trim is a integer value from 0-10. The default value of +5 indicates no trim. The trim parameter is entropy coded in order to +lower the coding cost of less extreme adjustments. Values lower than +5 bias the allocation towards lower frequencies and values above 5 +bias it towards higher frequencies. Like other signaled parameters, signaling +of the trim is gated so that it is not included if there is insufficient space +available in the bitstream. To decode the trim, first set +the trim value to 5, then if and only if the count of decoded 8th bits so far (ec_tell_frac) +plus 48 (6 bits) is less than or equal to the total frame size in 8th +bits minus total_boost (a product of the above band boost procedure), +decode the trim value using the PDF in . + + +PDF +{1, 1, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2}/128 + + +For 10 ms and 20 ms frames using short blocks and that have at least LM+2 bits left prior to +the allocation process, then one anti-collapse bit is reserved in the allocation process so it can +be decoded later. Following the the anti-collapse reservation, one bit is reserved for skip if available. + +For stereo frames, bits are reserved for intensity stereo and for dual stereo. Intensity stereo +requires ilog2(end-start) bits. Those bits are reserved if there is enough bits left. Following this, one +bit is reserved for dual stereo if available. + + +The allocation computation begins by setting up some initial conditions. +'total' is set to the remaining available 8th bits, computed by taking the +size of the coded frame times 8 and subtracting ec_tell_frac(). From this value, one (8th bit) +is subtracted to ensure that the resulting allocation will be conservative. 'anti_collapse_rsv' +is set to 8 (8th bits) if and only if the frame is a transient, LM is greater than 1, and total is +greater than or equal to (LM+2) * 8. Total is then decremented by anti_collapse_rsv and clamped +to be equal to or greater than zero. 'skip_rsv' is set to 8 (8th bits) if total is greater than +8, otherwise it is zero. Total is then decremented by skip_rsv. This reserves space for the +final skipping flag. + +If the current frame is stereo, intensity_rsv is set to the conservative log2 in 8th bits +of the number of coded bands for this frame (given by the table LOG2_FRAC_TABLE in rate.c). If +intensity_rsv is greater than total then intensity_rsv is set to zero. Otherwise total is +decremented by intensity_rsv, and if total is still greater than 8, dual_stereo_rsv is +set to 8 and total is decremented by dual_stereo_rsv. + +The allocation process then computes a vector representing the hard minimum amounts allocation +any band will receive for shape. This minimum is higher than the technical limit of the PVQ +process, but very low rate allocations produce an excessively sparse spectrum and these bands +are better served by having no allocation at all. For each coded band, set thresh[band] to +twenty-four times the number of MDCT bins in the band and divide by 16. If 8 times the number +of channels is greater, use that instead. This sets the minimum allocation to one bit per channel +or 48 128th bits per MDCT bin, whichever is greater. The band-size dependent part of this +value is not scaled by the channel count, because at the very low rates where this limit is +applicable there will usually be no bits allocated to the side. + +The previously decoded allocation trim is used to derive a vector of per-band adjustments, +'trim_offsets[]'. For each coded band take the alloc_trim and subtract 5 and LM. Then multiply +the result by the number of channels, the number of MDCT bins in the shortest frame size for this mode, +the number of remaining bands, 2**LM, and 8. Then divide this value by 64. Finally, if the +number of MDCT bins in the band per channel is only one, 8 times the number of channels is subtracted +in order to diminish the allocation by one bit, because width 1 bands receive greater benefit +from the coarse energy coding. + + +
    + +
    + +In each band, the normalized "shape" is encoded +using a vector quantization scheme called a "pyramid vector quantizer". + + +In +the simplest case, the number of bits allocated in + is converted to a number of pulses as described +by . Knowing the number of pulses and the +number of samples in the band, the decoder calculates the size of the codebook +as detailed in . The size is used to decode +an unsigned integer (uniform probability model), which is the codeword index. +This index is converted into the corresponding vector as explained in +. This vector is then scaled to unit norm. + + +
    + +Although the allocation is performed in 1/8th bit units, the quantization requires +an integer number of pulses K. To do this, the encoder searches for the value +of K that produces the number of bits nearest to the allocated value +(rounding down if exactly halfway between two values), not to exceed +the total number of bits available. For efficiency reasons, the search is performed against a +precomputed allocation table which only permits some K values for each N. The number of +codebook entries can be computed as explained in . The difference +between the number of bits allocated and the number of bits used is accumulated to a +"balance" (initialized to zero) that helps adjust the +allocation for the next bands. One third of the balance is applied to the +bit allocation of each band to help achieve the target allocation. The only +exceptions are the band before the last and the last band, for which half the balance +and the whole balance are applied, respectively. + +
    + +
    + + +Decoding of PVQ vectors is implemented in decode_pulses() (cwrs.c). +The unique codeword index is decoded as a uniformly-distributed integer value between 0 and +V(N,K)-1, where V(N,K) is the number of possible combinations of K pulses in +N samples. The index is then converted to a vector in the same way specified in +. The indexing is based on the calculation of V(N,K) +(denoted N(L,K) in ). + + + + The number of combinations can be computed recursively as +V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), with V(N,0) = 1 and V(0,K) = 0, K != 0. +There are many different ways to compute V(N,K), including precomputed tables and direct +use of the recursive formulation. The reference implementation applies the recursive +formulation one line (or column) at a time to save on memory use, +along with an alternate, +univariate recurrence to initialize an arbitrary line, and direct +polynomial solutions for small N. All of these methods are +equivalent, and have different trade-offs in speed, memory usage, and +code size. Implementations MAY use any methods they like, as long as +they are equivalent to the mathematical definition. + + + +The decoded vector X is recovered as follows. +Let i be the index decoded with the procedure in + with ft = V(N,K), so that 0 <= i < V(N,K). +Let k = K. +Then for j = 0 to (N - 1), inclusive, do: + +Let p = (V(N-j-1,k) + V(N-j,k))/2. + +If i < p, then let sgn = 1, else let sgn = -1 + and set i = i - p. + +Let k0 = k and set p = p - V(N-j-1,k). + +While p > i, set k = k - 1 and + p = p - V(N-j-1,k). + + +Set X[j] = sgn*(k0 - k) and i = i - p. + + + + + +The decoded vector X is then normalized such that its +L2-norm equals one. + +
    + +
    + +The normalized vector decoded in is then rotated +for the purpose of avoiding tonal artifacts. The rotation gain is equal to +
    + +
    + +where N is the number of dimensions, K is the number of pulses, and f_r depends on +the value of the "spread" parameter in the bit-stream. +
    + + +Spread value +f_r + 0 infinite (no rotation) + 1 15 + 2 10 + 3 5 + + + +The rotation angle is then calculated as +
    + +
    +A 2-D rotation R(i,j) between points x_i and x_j is defined as: +
    + +
    + +An N-D rotation is then achieved by applying a series of 2-D rotations back and forth, in the +following order: R(x_1, x_2), R(x_2, x_3), ..., R(x_N-2, X_N-1), R(x_N-1, X_N), +R(x_N-2, X_N-1), ..., R(x_1, x_2). +
    + + +If the decoded vector represents more +than one time block, then this spreading process is applied separately on each time block. +Also, if each block represents 8 samples or more, then another N-D rotation, by +(pi/2-theta), is applied before the rotation described above. This +extra rotation is applied in an interleaved manner with a stride equal to round(sqrt(N/nb_blocks)), +i.e., it is applied independently for each set of sample S_k = {stride*n + k}, n=0..N/stride-1. + +
    + +
    + +To avoid the need for multi-precision calculations when decoding PVQ codevectors, +the maximum size allowed for codebooks is 32 bits. When larger codebooks are +needed, the vector is instead split in two sub-vectors of size N/2. +A quantized gain parameter with precision +derived from the current allocation is entropy coded to represent the relative +gains of each side of the split, and the entire decoding process is recursively +applied. Multiple levels of splitting may be applied up to a limit of LM+1 splits. +The same recursive mechanism is applied for the joint coding +of stereo audio. + + +
    + +
    + +The time-frequency (TF) parameters are used to control the time-frequency resolution tradeoff +in each coded band. For each band, there are two possible TF choices. For the first +band coded, the PDF is {3, 1}/4 for frames marked as transient and {15, 1}/16 for +the other frames. For subsequent bands, the TF choice is coded relative to the +previous TF choice with probability {15, 1}/15 for transient frames and {31, 1}/32 +otherwise. The mapping between the decoded TF choices and the adjustment in TF +resolution is shown in the tables below. + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 0 -1 +10 0 -2 +20 0 -2 + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 0 -2 +10 0 -3 +20 0 -3 + + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 1 0 +10 2 0 +20 3 0 + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 1 -1 +10 1 -1 +20 1 -1 + + + +A negative TF adjustment means that the temporal resolution is increased, +while a positive TF adjustment means that the frequency resolution is increased. +Changes in TF resolution are implemented using the Hadamard transform . To increase +the time resolution by N, N "levels" of the Hadamard transform are applied to the +decoded vector for each interleaved MDCT vector. To increase the frequency resolution +(assumes a transient frame), then N levels of the Hadamard transform are applied +across the interleaved MDCT vector. In the case of increased +time resolution the decoder uses the "sequency order" because the input vector +is sorted in time. + +
    + + +
    + +
    + +The anti-collapse feature is designed to avoid the situation where the use of multiple +short MDCTs causes the energy in one or more of the MDCTs to be zero for +some bands, causing unpleasant artifacts. +When the frame has the transient bit set, an anti-collapse bit is decoded. +When anti-collapse is set, the energy in each small MDCT is prevented +from collapsing to zero. For each band of each MDCT where a collapse is +detected, a pseudo-random signal is inserted with an energy corresponding +to the minimum energy over the two previous frames. A renormalization step is +then required to ensure that the anti-collapse step did not alter the +energy preservation property. + +
    + +
    + +Just as each band was normalized in the encoder, the last step of the decoder before +the inverse MDCT is to denormalize the bands. Each decoded normalized band is +multiplied by the square root of the decoded energy. This is done by denormalise_bands() +(bands.c). + +
    + +
    + + +The inverse MDCT implementation has no special characteristics. The +input is N frequency-domain samples and the output is 2*N time-domain +samples, while scaling by 1/2. A "low-overlap" window reduces the algorithmic delay. +It is derived from a basic (full overlap) 240-sample version of the window used by the Vorbis codec: +
    + +
    +The low-overlap window is created by zero-padding the basic window and inserting ones in the +middle, such that the resulting window still satisfies power complementarity . +The IMDCT and +windowing are performed by mdct_backward (mdct.c). +
    + +
    + +The output of the inverse MDCT (after weighted overlap-add) is sent to the +post-filter. Although the post-filter is applied at the end, the post-filter +parameters are encoded at the beginning, just after the silence flag. +The post-filter can be switched on or off using one bit (logp=1). +If the post-filter is enabled, then the octave is decoded as an integer value +between 0 and 6 of uniform probability. Once the octave is known, the fine pitch +within the octave is decoded using 4+octave raw bits. The final pitch period +is equal to (16<<octave)+fine_pitch-1 so it is bounded between 15 and 1022, +inclusively. Next, the gain is decoded as three raw bits and is equal to +G=3*(int_gain+1)/32. The set of post-filter taps is decoded last, using +a pdf equal to {2, 1, 1}/4. Tapset zero corresponds to the filter coefficients +g0 = 0.3066406250, g1 = 0.2170410156, g2 = 0.1296386719. Tapset one +corresponds to the filter coefficients g0 = 0.4638671875, g1 = 0.2680664062, +g2 = 0, and tapset two uses filter coefficients g0 = 0.7998046875, +g1 = 0.1000976562, g2 = 0. + + + +The post-filter response is thus computed as: +
    + + + +
    + +During a transition between different gains, a smooth transition is calculated +using the square of the MDCT window. It is important that values of y(n) be +interpolated one at a time such that the past value of y(n) used is interpolated. +
    +
    + +
    + +After the post-filter, +the signal is de-emphasized using the inverse of the pre-emphasis filter +used in the encoder: +
    + +
    +where alpha_p=0.8500061035. +
    +
    + +
    + +
    + +
    + +Packet loss concealment (PLC) is an optional decoder-side feature that +SHOULD be included when receiving from an unreliable channel. Because +PLC is not part of the bitstream, there are many acceptable ways to +implement PLC with different complexity/quality trade-offs. + + + +The PLC in +the reference implementation depends on the mode of last packet received. +In CELT mode, the PLC finds a periodicity in the decoded +signal and repeats the windowed waveform using the pitch offset. The windowed +waveform is overlapped in such a way as to preserve the time-domain aliasing +cancellation with the previous frame and the next frame. This is implemented +in celt_decode_lost() (mdct.c). In SILK mode, the PLC uses LPC extrapolation +from the previous frame, implemented in silk_PLC() (PLC.c). + + +
    + +Clock drift refers to the gradual desynchronization of two endpoints +whose sample clocks run at different frequencies while they are streaming +live audio. Differences in clock frequencies are generally attributable to +manufacturing variation in the endpoints' clock hardware. For long-lived +streams, the time difference between sender and receiver can grow without +bound. + + + +When the sender's clock runs slower than the receiver's, the effect is similar +to packet loss: too few packets are received. The receiver can distinguish +between drift and loss if the transport provides packet timestamps. A receiver +for live streams SHOULD conceal the effects of drift, and MAY do so by invoking +the PLC. + + + +When the sender's clock runs faster than the receiver's, too many packets will +be received. The receiver MAY respond by skipping any packet (i.e., not +submitting the packet for decoding). This is likely to produce a less severe +artifact than if the frame were dropped after decoding. + + + +A decoder MAY employ a more sophisticated drift compensation method. For +example, the +NetEQ component +of the +Google WebRTC codebase +compensates for drift by adding or removing +one period when the signal is highly periodic. The reference implementation of +Opus allows a caller to learn whether the current frame's signal is highly +periodic, and if so what the period is, using the OPUS_GET_PITCH() request. + +
    + +
    + +
    + + +Switching between the Opus coding modes, audio bandwidths, and channel counts + requires careful consideration to avoid audible glitches. +Switching between any two configurations of the CELT-only mode, any two + configurations of the Hybrid mode, or from WB SILK to Hybrid mode does not + require any special treatment in the decoder, as the MDCT overlap will smooth + the transition. +Switching from Hybrid mode to WB SILK requires adding in the final contents + of the CELT overlap buffer to the first SILK-only packet. +This can be done by decoding a 2.5 ms silence frame with the CELT decoder + using the channel count of the SILK-only packet (and any choice of audio + bandwidth), which will correctly handle the cases when the channel count + changes as well. + + + +When changing the channel count for SILK-only or Hybrid packets, the encoder + can avoid glitches by smoothly varying the stereo width of the input signal + before or after the transition, and SHOULD do so. +However, other transitions between SILK-only packets or between NB or MB SILK + and Hybrid packets may cause glitches, because neither the LSF coefficients + nor the LTP, LPC, stereo unmixing, and resampler buffers are available at the + new sample rate. +These switches SHOULD be delayed by the encoder until quiet periods or + transients, where the inevitable glitches will be less audible. Additionally, + the bit-stream MAY include redundant side information ("redundancy"), in the + form of additional CELT frames embedded in each of the Opus frames around the + transition. + + + +The other transitions that cannot be easily handled are those where the lower + frequencies switch between the SILK LP-based model and the CELT MDCT model. +However, an encoder may not have an opportunity to delay such a switch to a + convenient point. +For example, if the content switches from speech to music, and the encoder does + not have enough latency in its analysis to detect this in advance, there may + be no convenient silence period during which to make the transition for quite + some time. +To avoid or reduce glitches during these problematic mode transitions, and + also between audio bandwidth changes in the SILK-only modes, transitions MAY + include redundant side information ("redundancy"), in the form of an + additional CELT frame embedded in the Opus frame. + + + +A transition between coding the lower frequencies with the LP model and the + MDCT model or a transition that involves changing the SILK bandwidth + is only normatively specified when it includes redundancy. +For those without redundancy, it is RECOMMENDED that the decoder use a + concealment technique (e.g., make use of a PLC algorithm) to "fill in" the + gap or discontinuity caused by the mode transition. +Therefore, PLC MUST NOT be applied during any normative transition, i.e., when + +A packet includes redundancy for this transition (as described below), +The transition is between any WB SILK packet and any Hybrid packet, or vice + versa, +The transition is between any two Hybrid mode packets, or +The transition is between any two CELT mode packets, + + unless there is actual packet loss. + + +
    + +Transitions with side information include an extra 5 ms "redundant" CELT + frame within the Opus frame. +This frame is designed to fill in the gap or discontinuity in the different + layers without requiring the decoder to conceal it. +For transitions from CELT-only to SILK-only or Hybrid, the redundant frame is + inserted in the first Opus frame after the transition (i.e., the first + SILK-only or Hybrid frame). +For transitions from SILK-only or Hybrid to CELT-only, the redundant frame is + inserted in the last Opus frame before the transition (i.e., the last + SILK-only or Hybrid frame). + + +
    + +The presence of redundancy is signaled in all SILK-only and Hybrid frames, not + just those involved in a mode transition. +This allows the frames to be decoded correctly even if an adjacent frame is + lost. +For SILK-only frames, this signaling is implicit, based on the size of the + of the Opus frame and the number of bits consumed decoding the SILK portion of + it. +After decoding the SILK portion of the Opus frame, the decoder uses ec_tell() + (see ) to check if there are at least 17 bits + remaining. +If so, then the frame contains redundancy. + + + +For Hybrid frames, this signaling is explicit. +After decoding the SILK portion of the Opus frame, the decoder uses ec_tell() + (see ) to ensure there are at least 37 bits remaining. +If so, it reads a symbol with the PDF in + , and if the value is 1, then the + frame contains redundancy. +Otherwise (if there were fewer than 37 bits left or the value was 0), the frame + does not contain redundancy. + + + +PDF +{4095, 1}/4096 + +
    + +
    + +Since the current frame is a SILK-only or a Hybrid frame, it must be at least + 10 ms. +Therefore, it needs an additional flag to indicate whether the redundant + 5 ms CELT frame should be mixed into the beginning of the current frame, + or the end. +After determining that a frame contains redundancy, the decoder reads a + 1 bit symbol with a uniform PDF + (). + + + +PDF +{1, 1}/2 + + + +If the value is zero, this is the first frame in the transition, and the + redundancy belongs at the end. +If the value is one, this is the second frame in the transition, and the + redundancy belongs at the beginning. +There is no way to specify that an Opus frame contains separate redundant CELT + frames at both the beginning and the end. + +
    + +
    + +Unlike the CELT portion of a Hybrid frame, the redundant CELT frame does not + use the same entropy coder state as the rest of the Opus frame, because this + would break the CELT bit allocation mechanism in Hybrid frames. +Thus, a redundant CELT frame always starts and ends on a byte boundary, even in + SILK-only frames, where this is not strictly necessary. + + + +For SILK-only frames, the number of bytes in the redundant CELT frame is simply + the number of whole bytes remaining, which must be at least 2, due to the + space check in . +For Hybrid frames, the number of bytes is equal to 2, plus a decoded unsigned + integer less than 256 (see ). +This may be more than the number of whole bytes remaining in the Opus frame, + in which case the frame is invalid. +However, a decoder is not required to ignore the entire frame, as this may be + the result of a bit error that desynchronized the range coder. +There may still be useful data before the error, and a decoder MAY keep any + audio decoded so far instead of invoking the PLC, but it is RECOMMENDED that + the decoder stop decoding and discard the rest of the current Opus frame. + + + +It would have been possible to avoid these invalid states in the design of Opus + by limiting the range of the explicit length decoded from Hybrid frames by the + actual number of whole bytes remaining. +However, this would require an encoder to determine the rate allocation for the + MDCT layer up front, before it began encoding that layer. +By allowing some invalid sizes, the encoder is able to defer that decision + until much later. +When encoding Hybrid frames which do not include redundancy, the encoder must + still decide up-front if it wishes to use the minimum 37 bits required to + trigger encoding of the redundancy flag, but this is a much looser + restriction. + + + +After determining the size of the redundant CELT frame, the decoder reduces + the size of the buffer currently in use by the range coder by that amount. +The CELT layer read any raw bits from the end of this reduced buffer, and all + calculations of the number of bits remaining in the buffer must be done using + this new, reduced size, rather than the original size of the Opus frame. + +
    + +
    + +The redundant frame is decoded like any other CELT-only frame, with the + exception that it does not contain a TOC byte. +The frame size is fixed at 5 ms, the channel count is set to that of the + current frame, and the audio bandwidth is also set to that of the current + frame, with the exception that for MB SILK frames, it is set to WB. + + + +If the redundancy belongs at the beginning (in a CELT-only to SILK-only or + Hybrid transition), the final reconstructed output uses the first 2.5 ms + of audio output by the decoder for the redundant frame as-is, discarding + the corresponding output from the SILK-only or Hybrid portion of the frame. +The remaining 2.5 ms is cross-lapped with the decoded SILK/Hybrid signal + using the CELT's power-complementary MDCT window to ensure a smooth + transition. + + + +If the redundancy belongs at the end (in a SILK-only or Hybrid to CELT-only + transition), only the second half (2.5 ms) of the audio output by the + decoder for the redundant frame is used. +In that case, the second half of the redundant frame is cross-lapped with the + end of the SILK/Hybrid signal, again using CELT's power-complementary MDCT + window to ensure a smooth transition. + +
    + +
    + +
    + +When a transition occurs, the state of the SILK or the CELT decoder (or both) + may need to be reset before decoding a frame in the new mode. +This avoids reusing "out of date" memory, which may not have been updated in + some time or may not be in a well-defined state due to, e.g., PLC. +The SILK state is reset before every SILK-only or Hybrid frame where the + previous frame was CELT-only. +The CELT state is reset every time the operating mode changes and the new mode + is either Hybrid or CELT-only, except when the transition uses redundancy as + described above. +When switching from SILK-only or Hybrid to CELT-only with redundancy, the CELT + state is reset before decoding the redundant CELT frame embedded in the + SILK-only or Hybrid frame, but it is not reset before decoding the following + CELT-only frame. +When switching from CELT-only mode to SILK-only or Hybrid mode with redundancy, + the CELT decoder is not reset for decoding the redundant CELT frame. + +
    + +
    + + + illustrates all of the normative + transitions involving a mode change, an audio bandwidth change, or both. +Each one uses an S, H, or C to represent an Opus frame in the corresponding + mode. +In addition, an R indicates the presence of redundancy in the Opus frame it is + cross-lapped with. +Its location in the first or last 5 ms is assumed to correspond to whether + it is the frame before or after the transition. +Other uses of redundancy are non-normative. +Finally, a c indicates the contents of the CELT overlap buffer after the + previously decoded frame (i.e., as extracted by decoding a silence frame). +
    + S -> S + & + !R -> R + & + ;S -> S -> S + +NB or MB SILK to Hybrid with Redundancy: S -> S -> S + & + !R ->;H -> H -> H + +WB SILK to Hybrid: S -> S -> S ->!H -> H -> H + +SILK to CELT with Redundancy: S -> S -> S + & + !R -> C -> C -> C + +Hybrid to NB or MB SILK with Redundancy: H -> H -> H + & + !R -> R + & + ;S -> S -> S + +Hybrid to WB SILK: H -> H -> H -> c + \ + + > S -> S -> S + +Hybrid to CELT with Redundancy: H -> H -> H + & + !R -> C -> C -> C + +CELT to SILK with Redundancy: C -> C -> C -> R + & + ;S -> S -> S + +CELT to Hybrid with Redundancy: C -> C -> C -> R + & + |H -> H -> H + +Key: +S SILK-only frame ; SILK decoder reset +H Hybrid frame | CELT and SILK decoder resets +C CELT-only frame ! CELT decoder reset +c CELT overlap + Direct mixing +R Redundant CELT frame & Windowed cross-lap +]]> +
    +The first two and the last two Opus frames in each example are illustrative, + i.e., there is no requirement that a stream remain in the same configuration + for three consecutive frames before or after a switch. +
    + + +The behavior of transitions without redundancy where PLC is allowed is non-normative. +An encoder might still wish to use these transitions if, for example, it + doesn't want to add the extra bitrate required for redundancy or if it makes + a decision to switch after it has already transmitted the frame that would + have had to contain the redundancy. + illustrates the recommended + cross-lapping and decoder resets for these transitions. +
    + S -> S ;S -> S -> S + +NB or MB SILK to Hybrid: S -> S -> S |H -> H -> H + +SILK to CELT without Redundancy: S -> S -> S -> P + & + !C -> C -> C + +Hybrid to NB or MB SILK: H -> H -> H -> c + + + ;S -> S -> S + +Hybrid to CELT without Redundancy: H -> H -> H -> P + & + !C -> C -> C + +CELT to SILK without Redundancy: C -> C -> C -> P + & + ;S -> S -> S + +CELT to Hybrid without Redundancy: C -> C -> C -> P + & + |H -> H -> H + +Key: +S SILK-only frame ; SILK decoder reset +H Hybrid frame | CELT and SILK decoder resets +C CELT-only frame ! CELT decoder reset +c CELT overlap + Direct mixing +P Packet Loss Concealment & Windowed cross-lap +]]> +
    +Encoders SHOULD NOT use other transitions, e.g., those that involve redundancy + in ways not illustrated in . +
    + +
    + +
    + +
    + + + + + + +
    + +Just like the decoder, the Opus encoder also normally consists of two main blocks: the +SILK encoder and the CELT encoder. However, unlike the case of the decoder, a valid +(though potentially suboptimal) Opus encoder is not required to support all modes and +may thus only include a SILK encoder module or a CELT encoder module. +The output bit-stream of the Opus encoding contains bits from the SILK and CELT + encoders, though these are not separable due to the use of a range coder. +A block diagram of the encoder is illustrated below. + +
    + +| Rate |--->| Encoder | V + +-----------+ | | Conversion | | | +---------+ + | Optional | | +------------+ +---------+ | Range | +->| High-pass |--+ | Encoder |----> + | Filter | | +--------------+ +---------+ | | Bit- + +-----------+ | | Delay | | CELT | +---------+ stream + +->| Compensation |->| Encoder | ^ + | | | |------+ + +--------------+ +---------+ +]]> + +
    +
    + + +For a normal encoder where both the SILK and the CELT modules are included, an optimal +encoder should select which coding mode to use at run-time depending on the conditions. +In the reference implementation, the frame size is selected by the application, but the +other configuration parameters (number of channels, bandwidth, mode) are automatically +selected (unless explicitly overridden by the application) depend on the following: + +Requested bitrate +Input sampling rate +Type of signal (speech vs music) +Frame size in use + + +The type of signal currently needs to be provided by the application (though it can be +changed in real-time). An Opus encoder implementation could also do automatic detection, +but since Opus is an interactive codec, such an implementation would likely have to either +delay the signal (for non-interactive applications) or delay the mode switching decisions (for +interactive applications). + + + +When the encoder is configured for voice over IP applications, the input signal is +filtered by a high-pass filter to remove the lowest part of the spectrum +that contains little speech energy and may contain background noise. This is a second order +Auto Regressive Moving Average (i.e., with poles and zeros) filter with a cut-off frequency around 50 Hz. +In the future, a music detector may also be used to lower the cut-off frequency when the +input signal is detected to be music rather than speech. + + +
    + +The range coder acts as the bit-packer for Opus. +It is used in three different ways: to encode + + +Entropy-coded symbols with a fixed probability model using ec_encode() + (entenc.c), + + +Integers from 0 to (2**M - 1) using ec_enc_uint() or ec_enc_bits() + (entenc.c), + +Integers from 0 to (ft - 1) (where ft is not a power of two) using + ec_enc_uint() (entenc.c). + + + + + +The range encoder maintains an internal state vector composed of the four-tuple + (val, rng, rem, ext) representing the low end of the current + range, the size of the current range, a single buffered output byte, and a + count of additional carry-propagating output bytes. +Both val and rng are 32-bit unsigned integer values, rem is a byte value or + less than 255 or the special value -1, and ext is an unsigned integer with at + least 11 bits. +This state vector is initialized at the start of each each frame to the value + (0, 2**31, -1, 0). +After encoding a sequence of symbols, the value of rng in the encoder should + exactly match the value of rng in the decoder after decoding the same sequence + of symbols. +This is a powerful tool for detecting errors in either an encoder or decoder + implementation. +The value of val, on the other hand, represents different things in the encoder + and decoder, and is not expected to match. + + + +The decoder has no analog for rem and ext. +These are used to perform carry propagation in the renormalization loop below. +Each iteration of this loop produces 9 bits of output, consisting of 8 data + bits and a carry flag. +The encoder cannot determine the final value of the output bytes until it + propagates these carry flags. +Therefore the reference implementation buffers a single non-propagating output + byte (i.e., one less than 255) in rem and keeps a count of additional + propagating (i.e., 255) output bytes in ext. +An implementation may choose to use any mathematically equivalent scheme to + perform carry propagation. + + +
    + +The main encoding function is ec_encode() (entenc.c), which encodes symbol k in + the current context using the same three-tuple (fl[k], fh[k], ft) + as the decoder to describe the range of the symbol (see + ). + + +ec_encode() updates the state of the encoder as follows. +If fl[k] is greater than zero, then +
    + +
    +Otherwise, val is unchanged and +
    + +
    +The divisions here are integer division. +
    + +
    + +After this update, the range is normalized using a procedure very similar to + that of , implemented by + ec_enc_normalize() (entenc.c). +The following process is repeated until rng > 2**23. +First, the top 9 bits of val, (val>>23), are sent to the carry buffer, + described in . +Then, the encoder sets +
    + +
    +
    +
    + +
    + +The function ec_enc_carry_out() (entenc.c) implements carry propagation and + output buffering. +It takes as input a 9-bit value, c, consisting of 8 data bits and an additional + carry bit. +If c is equal to the value 255, then ext is simply incremented, and no other + state updates are performed. +Otherwise, let b = (c>>8) be the carry bit. +Then, + + +If the buffered byte rem contains a value other than -1, the encoder outputs + the byte (rem + b). +Otherwise, if rem is -1, no byte is output. + + +If ext is non-zero, then the encoder outputs ext bytes---all with a value of 0 + if b is set, or 255 if b is unset---and sets ext to 0. + + +rem is set to the 8 data bits: +
    + +
    +
    +
    +
    +
    + +
    + +
    + +The reference implementation uses three additional encoding methods that are + exactly equivalent to the above, but make assumptions and simplifications that + allow for a more efficient implementation. + + +
    + +The first is ec_encode_bin() (entenc.c), defined using the parameter ftb + instead of ft. +It is mathematically equivalent to calling ec_encode() with + ft = (1<<ftb), but avoids using division. + +
    + +
    + +The next is ec_enc_bit_logp() (entenc.c), which encodes a single binary symbol. +The context is described by a single parameter, logp, which is the absolute + value of the base-2 logarithm of the probability of a "1". +It is mathematically equivalent to calling ec_encode() with the 3-tuple + (fl[k] = 0, fh[k] = (1<<logp) - 1, + ft = (1<<logp)) if k is 0 and with + (fl[k] = (1<<logp) - 1, + fh[k] = ft = (1<<logp)) if k is 1. +The implementation requires no multiplications or divisions. + +
    + +
    + +The last is ec_enc_icdf() (entenc.c), which encodes a single binary symbol with + a table-based context of up to 8 bits. +This uses the same icdf table as ec_dec_icdf() from + . +The function is mathematically equivalent to calling ec_encode() with + fl[k] = (1<<ftb) - icdf[k-1] (or 0 if + k == 0), fh[k] = (1<<ftb) - icdf[k], and + ft = (1<<ftb). +This only saves a few arithmetic operations over ec_encode_bin(), but allows + the encoder to use the same icdf tables as the decoder. + +
    + +
    + +
    + +The raw bits used by the CELT layer are packed at the end of the buffer using + ec_enc_bits() (entenc.c). +Because the raw bits may continue into the last byte output by the range coder + if there is room in the low-order bits, the encoder must be prepared to merge + these values into a single byte. +The procedure in does this in a way that + ensures both the range coded data and the raw bits can be decoded + successfully. + +
    + +
    + +The function ec_enc_uint() (entenc.c) encodes one of ft equiprobable symbols in + the range 0 to (ft - 1), inclusive, each with a frequency of 1, + where ft may be as large as (2**32 - 1). +Like the decoder (see ), it splits up the + value into a range coded symbol representing up to 8 of the high bits, and, if + necessary, raw bits representing the remainder of the value. + + +ec_enc_uint() takes a two-tuple (t, ft), where t is the value to be + encoded, 0 <= t < ft, and ft is not necessarily a + power of two. +Let ftb = ilog(ft - 1), i.e., the number of bits required + to store (ft - 1) in two's complement notation. +If ftb is 8 or less, then t is encoded directly using ec_encode() with the + three-tuple (t, t + 1, ft). + + +If ftb is greater than 8, then the top 8 bits of t are encoded using the + three-tuple (t>>(ftb - 8), + (t>>(ftb - 8)) + 1, + ((ft - 1)>>(ftb - 8)) + 1), and the + remaining bits, + (t & ((1<<(ftb - 8)) - 1), + are encoded as raw bits with ec_enc_bits(). + +
    + +
    + +After all symbols are encoded, the stream must be finalized by outputting a + value inside the current range. +Let end be the integer in the interval [val, val + rng) with the + largest number of trailing zero bits, b, such that + (end + (1<<b) - 1) is also in the interval + [val, val + rng). +This choice of end allows the maximum number of trailing bits to be set to + arbitrary values while still ensuring the range coded part of the buffer can + be decoded correctly. +Then, while end is not zero, the top 9 bits of end, i.e., (end>>23), are + passed to the carry buffer in accordance with the procedure in + , and end is updated via +
    + +
    +Finally, if the buffered output byte, rem, is neither zero nor the special + value -1, or the carry count, ext, is greater than zero, then 9 zero bits are + sent to the carry buffer to flush it to the output buffer. +When outputting the final byte from the range coder, if it would overlap any + raw bits already packed into the end of the output buffer, they should be ORed + into the same byte. +The bit allocation routines in the CELT layer should ensure that this can be + done without corrupting the range coder data so long as end is chosen as + described above. +If there is any space between the end of the range coder data and the end of + the raw bits, it is padded with zero bits. +This entire process is implemented by ec_enc_done() (entenc.c). +
    +
    + +
    + + The bit allocation routines in Opus need to be able to determine a + conservative upper bound on the number of bits that have been used + to encode the current frame thus far. This drives allocation + decisions and ensures that the range coder and raw bits will not + overflow the output buffer. This is computed in the + reference implementation to whole-bit precision by + the function ec_tell() (entcode.h) and to fractional 1/8th bit + precision by the function ec_tell_frac() (entcode.c). + Like all operations in the range coder, it must be implemented in a + bit-exact manner, and must produce exactly the same value returned by + the same functions in the decoder after decoding the same symbols. + +
    + +
    + +
    + + In many respects the SILK encoder mirrors the SILK decoder described + in . + Details such as the quantization and range coder tables can be found + there, while this section describes the high-level design choices that + were made. + The diagram below shows the basic modules of the SILK encoder. +
    + +| Rate |--->| Mixing |--->| Core |----------> +Input |Conversion| | | | Encoder | Bitstream + +----------+ +--------+ +---------+ +]]> + +
    +
    + +
    + +The input signal's sampling rate is adjusted by a sample rate conversion +module so that it matches the SILK internal sampling rate. +The input to the sample rate converter is delayed by a number of samples +depending on the sample rate ratio, such that the overall delay is constant +for all input and output sample rates. + +
    + +
    + +The stereo mixer is only used for stereo input signals. +It converts a stereo left/right signal into an adaptive +mid/side representation. +The first step is to compute non-adaptive mid/side signals +as half the sum and difference between left and right signals. +The side signal is then minimized in energy by subtracting a +prediction of it based on the mid signal. +This prediction works well when the left and right signals +exhibit linear dependency, for instance for an amplitude-panned +input signal. +Like in the decoder, the prediction coefficients are linearly +interpolated during the first 8 ms of the frame. + The mid signal is always encoded, whereas the residual + side signal is only encoded if it has sufficient + energy compared to the mid signal's energy. + If it has not, + the "mid_only_flag" is set without encoding the side signal. + + +The predictor coefficients are coded regardless of whether +the side signal is encoded. +For each frame, two predictor coefficients are computed, one +that predicts between low-passed mid and side channels, and +one that predicts between high-passed mid and side channels. +The low-pass filter is a simple three-tap filter +and creates a delay of one sample. +The high-pass filtered signal is the difference between +the mid signal delayed by one sample and the low-passed +signal. Instead of explicitly computing the high-passed +signal, it is computationally more efficient to transform +the prediction coefficients before applying them to the +filtered mid signal, as follows +
    + + + +
    +where w0 and w1 are the low-pass and high-pass prediction +coefficients, mid(n-1) is the mid signal delayed by one sample, +LP(n) and HP(n) are the low-passed and high-passed +signals and pred(n) is the prediction signal that is subtracted +from the side signal. +
    +
    + +
    + +What follows is a description of the core encoder and its components. +For simplicity, the core encoder is referred to simply as the encoder in +the remainder of this section. An overview of the encoder is given in +. + +
    + +| | + +---------+ | +---------+ | | + |Voice | | |LTP |12 | | + +-->|Activity |--+ +----->|Scaling |-----------+---->| | + | |Detector |3 | | |Control |<--+ | | | + | +---------+ | | +---------+ | | | | + | | | +---------+ | | | | + | | | |Gains | | | | | + | | | +-->|Processor|---|---+---|---->| R | + | | | | | |11 | | | | a | + | \/ | | +---------+ | | | | n | + | +---------+ | | +---------+ | | | | g | + | |Pitch | | | |LSF | | | | | e | + | +->|Analysis |---+ | |Quantizer|---|---|---|---->| | + | | | |4 | | | |8 | | | | E |--> + | | +---------+ | | +---------+ | | | | n | 2 + | | | | 9/\ 10| | | | | c | + | | | | | \/ | | | | o | + | | +---------+ | | +----------+ | | | | d | + | | |Noise | +--|-->|Prediction|--+---|---|---->| e | + | +->|Shaping |---|--+ |Analysis |7 | | | | r | + | | |Analysis |5 | | | | | | | | | + | | +---------+ | | +----------+ | | | | | + | | | | /\ | | | | | + | | +----------|--|--------+ | | | | | + | | | \/ \/ \/ \/ \/ | | + | | | +---------+ +------------+ | | + | | | | | |Noise | | | +-+-------+-----+------>|Prefilter|--------->|Shaping |-->| | +1 | | 6 |Quantization|13 | | + +---------+ +------------+ +---+ + +1: Input speech signal +2: Range encoded bitstream +3: Voice activity estimate +4: Pitch lags (per 5 ms) and voicing decision (per 20 ms) +5: Noise shaping quantization coefficients + - Short term synthesis and analysis + noise shaping coefficients (per 5 ms) + - Long term synthesis and analysis noise + shaping coefficients (per 5 ms and for voiced speech only) + - Noise shaping tilt (per 5 ms) + - Quantizer gain/step size (per 5 ms) +6: Input signal filtered with analysis noise shaping filters +7: Short and long term prediction coefficients + LTP (per 5 ms) and LPC (per 20 ms) +8: LSF quantization indices +9: LSF coefficients +10: Quantized LSF coefficients +11: Processed gains, and synthesis noise shape coefficients +12: LTP state scaling coefficient. Controlling error propagation + / prediction gain trade-off +13: Quantized signal +]]> + +
    + +
    + +The input signal is processed by a Voice Activity Detector (VAD) to produce +a measure of voice activity, spectral tilt, and signal-to-noise estimates for +each frame. The VAD uses a sequence of half-band filterbanks to split the +signal into four subbands: 0...Fs/16, Fs/16...Fs/8, Fs/8...Fs/4, and +Fs/4...Fs/2, where Fs is the sampling frequency (8, 12, 16, or 24 kHz). +The lowest subband, from 0 - Fs/16, is high-pass filtered with a first-order +moving average (MA) filter (with transfer function H(z) = 1-z**(-1)) to +reduce the energy at the lowest frequencies. For each frame, the signal +energy per subband is computed. +In each subband, a noise level estimator tracks the background noise level +and a Signal-to-Noise Ratio (SNR) value is computed as the logarithm of the +ratio of energy to noise level. +Using these intermediate variables, the following parameters are calculated +for use in other SILK modules: + + +Average SNR. The average of the subband SNR values. + + + +Smoothed subband SNRs. Temporally smoothed subband SNR values. + + + +Speech activity level. Based on the average SNR and a weighted average of the +subband energies. + + + +Spectral tilt. A weighted average of the subband SNRs, with positive weights +for the low subbands and negative weights for the high subbands. + + + +
    + +
    + +The input signal is processed by the open loop pitch estimator shown in +. +
    + +|sampling|->|Correlator| | + | | | | | |4 + | +--------+ +----------+ \/ + | | 2 +-------+ + | | +-->|Speech |5 + +---------+ +--------+ | \/ | |Type |-> + |LPC | |Down | | +----------+ | | + +->|Analysis | +->|sample |-+------------->|Time- | +-------+ + | | | | |to 8 kHz| |Correlator|-----------> + | +---------+ | +--------+ |__________| 6 + | | | |3 + | \/ | \/ + | +---------+ | +----------+ + | |Whitening| | |Time- | +-+->|Filter |-+--------------------------->|Correlator|-----------> +1 | | | | 7 + +---------+ +----------+ + +1: Input signal +2: Lag candidates from stage 1 +3: Lag candidates from stage 2 +4: Correlation threshold +5: Voiced/unvoiced flag +6: Pitch correlation +7: Pitch lags +]]> + +
    +The pitch analysis finds a binary voiced/unvoiced classification, and, for +frames classified as voiced, four pitch lags per frame - one for each +5 ms subframe - and a pitch correlation indicating the periodicity of +the signal. +The input is first whitened using a Linear Prediction (LP) whitening filter, +where the coefficients are computed through standard Linear Prediction Coding +(LPC) analysis. The order of the whitening filter is 16 for best results, but +is reduced to 12 for medium complexity and 8 for low complexity modes. +The whitened signal is analyzed to find pitch lags for which the time +correlation is high. +The analysis consists of three stages for reducing the complexity: + +In the first stage, the whitened signal is downsampled to 4 kHz +(from 8 kHz) and the current frame is correlated to a signal delayed +by a range of lags, starting from a shortest lag corresponding to +500 Hz, to a longest lag corresponding to 56 Hz. + + +The second stage operates on an 8 kHz signal (downsampled from 12, 16, +or 24 kHz) and measures time correlations only near the lags +corresponding to those that had sufficiently high correlations in the first +stage. The resulting correlations are adjusted for a small bias towards +short lags to avoid ending up with a multiple of the true pitch lag. +The highest adjusted correlation is compared to a threshold depending on: + + +Whether the previous frame was classified as voiced + + +The speech activity level + + +The spectral tilt. + + +If the threshold is exceeded, the current frame is classified as voiced and +the lag with the highest adjusted correlation is stored for a final pitch +analysis of the highest precision in the third stage. + + +The last stage operates directly on the whitened input signal to compute time +correlations for each of the four subframes independently in a narrow range +around the lag with highest correlation from the second stage. + + +
    +
    + +
    + +The noise shaping analysis finds gains and filter coefficients used in the +prefilter and noise shaping quantizer. These parameters are chosen such that +they will fulfill several requirements: + + +Balancing quantization noise and bitrate. +The quantization gains determine the step size between reconstruction levels +of the excitation signal. Therefore, increasing the quantization gain +amplifies quantization noise, but also reduces the bitrate by lowering +the entropy of the quantization indices. + + +Spectral shaping of the quantization noise; the noise shaping quantizer is +capable of reducing quantization noise in some parts of the spectrum at the +cost of increased noise in other parts without substantially changing the +bitrate. +By shaping the noise such that it follows the signal spectrum, it becomes +less audible. In practice, best results are obtained by making the shape +of the noise spectrum slightly flatter than the signal spectrum. + + +De-emphasizing spectral valleys; by using different coefficients in the +analysis and synthesis part of the prefilter and noise shaping quantizer, +the levels of the spectral valleys can be decreased relative to the levels +of the spectral peaks such as speech formants and harmonics. +This reduces the entropy of the signal, which is the difference between the +coded signal and the quantization noise, thus lowering the bitrate. + + +Matching the levels of the decoded speech formants to the levels of the +original speech formants; an adjustment gain and a first order tilt +coefficient are computed to compensate for the effect of the noise +shaping quantization on the level and spectral tilt. + + + + +
    + + + Frequency + +1: Input signal spectrum +2: De-emphasized and level matched spectrum +3: Quantization noise spectrum +]]> + +
    + shows an example of an +input signal spectrum (1). +After de-emphasis and level matching, the spectrum has deeper valleys (2). +The quantization noise spectrum (3) more or less follows the input signal +spectrum, while having slightly less pronounced peaks. +The entropy, which provides a lower bound on the bitrate for encoding the +excitation signal, is proportional to the area between the de-emphasized +spectrum (2) and the quantization noise spectrum (3). Without de-emphasis, +the entropy is proportional to the area between input spectrum (1) and +quantization noise (3) - clearly higher. +
    + + +The transformation from input signal to de-emphasized signal can be +described as a filtering operation with a filter +
    + + + +
    +having an adjustment gain G, a first order tilt adjustment filter with +tilt coefficient c_tilt, and where +
    + + + +
    +is the analysis part of the de-emphasis filter, consisting of the short-term +shaping filter with coefficients a_ana(k), and the long-term shaping filter +with coefficients b_ana(k) and pitch lag L. +The parameter d determines the number of long-term shaping filter taps. +
    + + +Similarly, but without the tilt adjustment, the synthesis part can be written as +
    + + + +
    +
    + +All noise shaping parameters are computed and applied per subframe of 5 ms. +First, an LPC analysis is performed on a windowed signal block of 15 ms. +The signal block has a look-ahead of 5 ms relative to the current subframe, +and the window is an asymmetric sine window. The LPC analysis is done with the +autocorrelation method, with an order of between 8, in lowest-complexity mode, +and 16, for best quality. + + +Optionally the LPC analysis and noise shaping filters are warped by replacing +the delay elements by first-order allpass filters. +This increases the frequency resolution at low frequencies and reduces it at +high ones, which better matches the human auditory system and improves +quality. +The warped analysis and filtering comes at a cost in complexity +and is therefore only done in higher complexity modes. + + +The quantization gain is found by taking the square root of the residual energy +from the LPC analysis and multiplying it by a value inversely proportional +to the coding quality control parameter and the pitch correlation. + + +Next the two sets of short-term noise shaping coefficients a_ana(k) and +a_syn(k) are obtained by applying different amounts of bandwidth expansion to the +coefficients found in the LPC analysis. +This bandwidth expansion moves the roots of the LPC polynomial towards the +origin, using the formulas +
    + + + +
    +where a(k) is the k'th LPC coefficient, and the bandwidth expansion factors +g_ana and g_syn are calculated as +
    + + + +
    +where C is the coding quality control parameter between 0 and 1. +Applying more bandwidth expansion to the analysis part than to the synthesis +part gives the desired de-emphasis of spectral valleys in between formants. +
    + + +The long-term shaping is applied only during voiced frames. +It uses three filter taps, described by +
    + + + +
    +For unvoiced frames these coefficients are set to 0. The multiplication factors +F_ana and F_syn are chosen between 0 and 1, depending on the coding quality +control parameter, as well as the calculated pitch correlation and smoothed +subband SNR of the lowest subband. By having F_ana less than F_syn, +the pitch harmonics are emphasized relative to the valleys in between the +harmonics. +
    + + +The tilt coefficient c_tilt is for unvoiced frames chosen as +
    + + + +
    +and as +
    + + + +
    +for voiced frames, where V is the voice activity level between 0 and 1. +
    + +The adjustment gain G serves to correct any level mismatch between the original +and decoded signals that might arise from the noise shaping and de-emphasis. +This gain is computed as the ratio of the prediction gain of the short-term +analysis and synthesis filter coefficients. The prediction gain of an LPC +synthesis filter is the square root of the output energy when the filter is +excited by a unit-energy impulse on the input. +An efficient way to compute the prediction gain is by first computing the +reflection coefficients from the LPC coefficients through the step-down +algorithm, and extracting the prediction gain from the reflection coefficients +as +
    + + + +
    +where r_k is the k'th reflection coefficient. +
    + + +Initial values for the quantization gains are computed as the square-root of +the residual energy of the LPC analysis, adjusted by the coding quality control +parameter. +These quantization gains are later adjusted based on the results of the +prediction analysis. + +
    + +
    + +The prediction analysis is performed in one of two ways depending on how +the pitch estimator classified the frame. +The processing for voiced and unvoiced speech is described in + and + , respectively. + Inputs to this function include the pre-whitened signal from the + pitch estimator (see ). + + +
    + + For a frame of voiced speech the pitch pulses will remain dominant in the + pre-whitened input signal. + Further whitening is desirable as it leads to higher quality at the same + available bitrate. + To achieve this, a Long-Term Prediction (LTP) analysis is carried out to + estimate the coefficients of a fifth-order LTP filter for each of four + subframes. + The LTP coefficients are quantized using the method described in + , and the quantized LTP + coefficients are used to compute the LTP residual signal. + This LTP residual signal is the input to an LPC analysis where the LPC coefficients are + estimated using Burg's method , such that the residual energy is minimized. + The estimated LPC coefficients are converted to a Line Spectral Frequency (LSF) vector + and quantized as described in . +After quantization, the quantized LSF vector is converted back to LPC +coefficients using the full procedure in . +By using quantized LTP coefficients and LPC coefficients derived from the +quantized LSF coefficients, the encoder remains fully synchronized with the +decoder. +The quantized LPC and LTP coefficients are also used to filter the input +signal and measure residual energy for each of the four subframes. + +
    +
    + +For a speech signal that has been classified as unvoiced, there is no need +for LTP filtering, as it has already been determined that the pre-whitened +input signal is not periodic enough within the allowed pitch period range +for LTP analysis to be worth the cost in terms of complexity and bitrate. +The pre-whitened input signal is therefore discarded, and instead the input +signal is used for LPC analysis using Burg's method. +The resulting LPC coefficients are converted to an LSF vector and quantized +as described in the following section. +They are then transformed back to obtain quantized LPC coefficients, which +are then used to filter the input signal and measure residual energy for +each of the four subframes. + +
    + +The main purpose of linear prediction in SILK is to reduce the bitrate by +minimizing the residual energy. +At least at high bitrates, perceptual aspects are handled +independently by the noise shaping filter. +Burg's method is used because it provides higher prediction gain +than the autocorrelation method and, unlike the covariance method, +produces stable filters (assuming numerical errors don't spoil +that). SILK's implementation of Burg's method is also computationally +faster than the autocovariance method. +The implementation of Burg's method differs from traditional +implementations in two aspects. +The first difference is that it +operates on autocorrelations, similar to the Schur algorithm , but +with a simple update to the autocorrelations after finding each +reflection coefficient to make the result identical to Burg's method. +This brings down the complexity of Burg's method to near that of +the autocorrelation method. +The second difference is that the signal in each subframe is scaled +by the inverse of the residual quantization step size. Subframes with +a small quantization step size will on average spend more bits for a +given amount of residual energy than subframes with a large step size. +Without scaling, Burg's method minimizes the total residual energy in +all subframes, which doesn't necessarily minimize the total number of +bits needed for coding the quantized residual. The residual energy +of the scaled subframes is a better measure for that number of +bits. + +
    +
    +
    + +
    + +Unlike many other speech codecs, SILK uses variable bitrate coding +for the LSFs. +This improves the average rate-distortion (R-D) tradeoff and reduces outliers. +The variable bitrate coding minimizes a linear combination of the weighted +quantization errors and the bitrate. +The weights for the quantization errors are the Inverse +Harmonic Mean Weighting (IHMW) function proposed by Laroia et al. +(see ). +These weights are referred to here as Laroia weights. + + +The LSF quantizer consists of two stages. +The first stage is an (unweighted) vector quantizer (VQ), with a +codebook size of 32 vectors. +The quantization errors for the codebook vector are sorted, and +for the N best vectors a second stage quantizer is run. +By varying the number N a tradeoff is made between R-D performance +and computational efficiency. +For each of the N codebook vectors the Laroia weights corresponding +to that vector (and not to the input vector) are calculated. +Then the residual between the input LSF vector and the codebook +vector is scaled by the square roots of these Laroia weights. +This scaling partially normalizes error sensitivity for the +residual vector, so that a uniform quantizer with fixed +step sizes can be used in the second stage without too much +performance loss. +And by scaling with Laroia weights determined from the first-stage +codebook vector, the process can be reversed in the decoder. + + +The second stage uses predictive delayed decision scalar +quantization. +The quantization error is weighted by Laroia weights determined +from the LSF input vector. +The predictor multiplies the previous quantized residual value +by a prediction coefficient that depends on the vector index from the +first stage VQ and on the location in the LSF vector. +The prediction is subtracted from the LSF residual value before +quantizing the result, and added back afterwards. +This subtraction can be interpreted as shifting the quantization levels +of the scalar quantizer, and as a result the quantization error of +each value depends on the quantization decision of the previous value. +This dependency is exploited by the delayed decision mechanism to +search for a quantization sequency with best R-D performance +with a Viterbi-like algorithm . +The quantizer processes the residual LSF vector in reverse order +(i.e., it starts with the highest residual LSF value). +This is done because the prediction works slightly +better in the reverse direction. + + +The quantization index of the first stage is entropy coded. +The quantization sequence from the second stage is also entropy +coded, where for each element the probability table is chosen +depending on the vector index from the first stage and the location +of that element in the LSF vector. + + +
    + +If the input is stable, finding the best candidate usually results in a +quantized vector that is also stable. Because of the two-stage approach, +however, it is possible that the best quantization candidate is unstable. +The encoder applies the same stabilization procedure applied by the decoder + (see to ensure the LSF parameters + are within their valid range, increasingly sorted, and have minimum + distances between each other and the border values. + +
    +
    + +
    + +For voiced frames, the prediction analysis described in + resulted in four sets +(one set per subframe) of five LTP coefficients, plus four weighting matrices. +The LTP coefficients for each subframe are quantized using entropy constrained +vector quantization. +A total of three vector codebooks are available for quantization, with +different rate-distortion trade-offs. The three codebooks have 10, 20, and +40 vectors and average rates of about 3, 4, and 5 bits per vector, respectively. +Consequently, the first codebook has larger average quantization distortion at +a lower rate, whereas the last codebook has smaller average quantization +distortion at a higher rate. +Given the weighting matrix W_ltp and LTP vector b, the weighted rate-distortion +measure for a codebook vector cb_i with rate r_i is give by +
    + + + +
    +where u is a fixed, heuristically-determined parameter balancing the distortion +and rate. +Which codebook gives the best performance for a given LTP vector depends on the +weighting matrix for that LTP vector. +For example, for a low valued W_ltp, it is advantageous to use the codebook +with 10 vectors as it has a lower average rate. +For a large W_ltp, on the other hand, it is often better to use the codebook +with 40 vectors, as it is more likely to contain the best codebook vector. +The weighting matrix W_ltp depends mostly on two aspects of the input signal. +The first is the periodicity of the signal; the more periodic, the larger W_ltp. +The second is the change in signal energy in the current subframe, relative to +the signal one pitch lag earlier. +A decaying energy leads to a larger W_ltp than an increasing energy. +Both aspects fluctuate relatively slowly, which causes the W_ltp matrices for +different subframes of one frame often to be similar. +Because of this, one of the three codebooks typically gives good performance +for all subframes, and therefore the codebook search for the subframe LTP +vectors is constrained to only allow codebook vectors to be chosen from the +same codebook, resulting in a rate reduction. +
    + + +To find the best codebook, each of the three vector codebooks is +used to quantize all subframe LTP vectors and produce a combined +weighted rate-distortion measure for each vector codebook. +The vector codebook with the lowest combined rate-distortion +over all subframes is chosen. The quantized LTP vectors are used +in the noise shaping quantizer, and the index of the codebook +plus the four indices for the four subframe codebook vectors +are passed on to the range encoder. + +
    + +
    + +In the prefilter the input signal is filtered using the spectral valley +de-emphasis filter coefficients from the noise shaping analysis +(see ). +By applying only the noise shaping analysis filter to the input signal, +it provides the input to the noise shaping quantizer. + +
    + +
    + +The noise shaping quantizer independently shapes the signal and coding noise +spectra to obtain a perceptually higher quality at the same bitrate. + + +The prefilter output signal is multiplied with a compensation gain G computed +in the noise shaping analysis. Then the output of a synthesis shaping filter +is added, and the output of a prediction filter is subtracted to create a +residual signal. +The residual signal is multiplied by the inverse quantized quantization gain +from the noise shaping analysis, and input to a scalar quantizer. +The quantization indices of the scalar quantizer represent a signal of pulses +that is input to the pyramid range encoder. +The scalar quantizer also outputs a quantization signal, which is multiplied +by the quantized quantization gain from the noise shaping analysis to create +an excitation signal. +The output of the prediction filter is added to the excitation signal to form +the quantized output signal y(n). +The quantized output signal y(n) is input to the synthesis shaping and +prediction filters. + + +Optionally the noise shaping quantizer operates in a delayed decision +mode. +In this mode it uses a Viterbi algorithm to keep track of +multiple rounding choices in the quantizer and select the best +one after a delay of 32 samples. This improves the rate/distortion +performance of the quantizer. + +
    + +
    + + SILK was designed to run in Variable Bitrate (VBR) mode. However + the reference implementation also has a Constant Bitrate (CBR) mode + for SILK. In CBR mode SILK will attempt to encode each packet with + no more than the allowed number of bits. The Opus wrapper code + then pads the bitstream if any unused bits are left in SILK mode, or + encodes the high band with the remaining number of bits in Hybrid mode. + The number of payload bits is adjusted by changing + the quantization gains and the rate/distortion tradeoff in the noise + shaping quantizer, in an iterative loop + around the noise shaping quantizer and entropy coding. + Compared to the SILK VBR mode, the CBR mode has lower + audio quality at a given average bitrate, and also has higher + computational complexity. + +
    + +
    + +
    + + +
    + +Most of the aspects of the CELT encoder can be directly derived from the description +of the decoder. For example, the filters and rotations in the encoder are simply the +inverse of the operation performed by the decoder. Similarly, the quantizers generally +optimize for the mean square error (because noise shaping is part of the bit-stream itself), +so no special search is required. For this reason, only the less straightforward aspects of the +encoder are described here. + + +
    +The pitch prefilter is applied after the pre-emphasis. It is applied +in such a way as to be the inverse of the decoder's post-filter. The main non-obvious aspect of the +prefilter is the selection of the pitch period. The pitch search should be optimized for the +following criteria: + +continuity: it is important that the pitch period +does not change abruptly between frames; and +avoidance of pitch multiples: when the period used is a multiple of the real period +(lower frequency fundamental), the post-filter loses most of its ability to reduce noise + + +
    + +
    + +The MDCT output is divided into bands that are designed to match the ear's critical +bands for the smallest (2.5 ms) frame size. The larger frame sizes use integer +multiples of the 2.5 ms layout. For each band, the encoder +computes the energy that will later be encoded. Each band is then normalized by the +square root of the unquantized energy, such that each band now forms a unit vector X. +The energy and the normalization are computed by compute_band_energies() +and normalise_bands() (bands.c), respectively. + +
    + +
    + + +Energy quantization (both coarse and fine) can be easily understood from the decoding process. +For all useful bitrates, the coarse quantizer always chooses the quantized log energy value that +minimizes the error for each band. Only at very low rate does the encoder allow larger errors to +minimize the rate and avoid using more bits than are available. When the +available CPU requirements allow it, it is best to try encoding the coarse energy both with and without +inter-frame prediction such that the best prediction mode can be selected. The optimal mode depends on +the coding rate, the available bitrate, and the current rate of packet loss. + + +The fine energy quantizer always chooses the quantized log energy value that +minimizes the error for each band because the rate of the fine quantization depends only +on the bit allocation and not on the values that are coded. + +
    + +
    +The encoder must use exactly the same bit allocation process as used by the decoder +and described in . The three mechanisms that can be used by the +encoder to adjust the bitrate on a frame-by-frame basis are band boost, allocation trim, +and band skipping. + + +
    +The reference encoder makes a decision to boost a band when the energy of that band is significantly +higher than that of the neighboring bands. Let E_j be the log-energy of band j, we define + +D_j = 2*E_j - E_j-1 - E_j+1 + + +The allocation of band j is boosted once if D_j > t1 and twice if D_j > t2. For LM>=1, t1=2 and t2=4, +while for LM<1, t1=3 and t2=5. + + +
    + +
    +The allocation trim is a value between 0 and 10 (inclusively) that controls the allocation +balance between the low and high frequencies. The encoder starts with a safe "default" of 5 +and deviates from that default in two different ways. First the trim can deviate by +/- 2 +depending on the spectral tilt of the input signal. For signals with more low frequencies, the +trim is increased by up to 2, while for signals with more high frequencies, the trim is +decreased by up to 2. +For stereo inputs, the trim value can +be decreased by up to 4 when the inter-channel correlation at low frequency (first 8 bands) +is high. +
    + +
    +The encoder uses band skipping to ensure that the shape of the bands is only coded +if there is at least 1/2 bit per sample available for the PVQ. If not, then no bit is allocated +and folding is used instead. To ensure continuity in the allocation, some amount of hysteresis is +added to the process, such that a band that received PVQ bits in the previous frame only needs 7/16 +bit/sample to be coded for the current frame, while a band that did not receive PVQ bits in the +previous frames needs at least 9/16 bit/sample to be coded. +
    + +
    + +
    +Because CELT applies mid-side stereo coupling in the normalized domain, it does not suffer from +important stereo image problems even when the two channels are completely uncorrelated. For this reason +it is always safe to use stereo coupling on any audio frame. That being said, there are some frames +for which dual (independent) stereo is still more efficient. This decision is made by comparing the estimated +entropy with and without coupling over the first 13 bands, taking into account the fact that all bands with +more than two MDCT bins require one extra degree of freedom when coded in mid-side. Let L1_ms and L1_lr +be the L1-norm of the mid-side vector and the L1-norm of the left-right vector, respectively. The decision +to use mid-side is made if and only if +
    + +
    +where bins is the number of MDCT bins in the first 13 bands and E is the number of extra degrees of +freedom for mid-side coding. For LM>1, E=13, otherwise E=5. +
    + +The reference encoder decides on the intensity stereo threshold based on the bitrate alone. After +taking into account the frame size by subtracting 80 bits per frame for coarse energy, the first +band using intensity coding is as follows: + + + +bitrate (kb/s) +start band +<35 8 +35-50 12 +50-68 16 +84-84 18 +84-102 19 +102-130 20 +>130 disabled + + + +
    + +
    + +The choice of time-frequency resolution used in is based on +R-D optimization. The distortion is the L1-norm (sum of absolute values) of each band +after each TF resolution under consideration. The L1 norm is used because it represents the entropy +for a Laplacian source. The number of bits required to code a change in TF resolution between +two bands is higher than the cost of having those two bands use the same resolution, which is +what requires the R-D optimization. The optimal decision is computed using the Viterbi algorithm. +See tf_analysis() in celt/celt.c. + +
    + +
    + +The choice of the spreading value in has an +impact on the nature of the coding noise introduced by CELT. The larger the f_r value, the +lower the impact of the rotation, and the more tonal the coding noise. The +more tonal the signal, the more tonal the noise should be, so the CELT encoder determines +the optimal value for f_r by estimating how tonal the signal is. The tonality estimate +is based on discrete pdf (4-bin histogram) of each band. Bands that have a large number of small +values are considered more tonal and a decision is made by combining all bands with more than +8 samples. See spreading_decision() in celt/bands.c. + +
    + +
    +CELT uses a Pyramid Vector Quantization (PVQ) +codebook for quantizing the details of the spectrum in each band that have not +been predicted by the pitch predictor. The PVQ codebook consists of all sums +of K signed pulses in a vector of N samples, where two pulses at the same position +are required to have the same sign. Thus the codebook includes +all integer codevectors y of N dimensions that satisfy sum(abs(y(j))) = K. + + + +In bands where there are sufficient bits allocated PVQ is used to encode +the unit vector that results from the normalization in + directly. Given a PVQ codevector y, +the unit vector X is obtained as X = y/||y||, where ||.|| denotes the +L2 norm. + + + +
    + + +The search for the best codevector y is performed by alg_quant() +(vq.c). There are several possible approaches to the +search, with a trade-off between quality and complexity. The method used in the reference +implementation computes an initial codeword y1 by projecting the normalized spectrum +X onto the codebook pyramid of K-1 pulses: + + +y0 = truncate_towards_zero( (K-1) * X / sum(abs(X))) + + + +Depending on N, K and the input data, the initial codeword y0 may contain from +0 to K-1 non-zero values. All the remaining pulses, with the exception of the last one, +are found iteratively with a greedy search that minimizes the normalized correlation +between y and X: +
    + +
    +
    + + +The search described above is considered to be a good trade-off between quality +and computational cost. However, there are other possible ways to search the PVQ +codebook and the implementers MAY use any other search methods. See alg_quant() in celt/vq.c. + +
    + +
    + + +The vector to encode, X, is converted into an index i such that + 0 <= i < V(N,K) as follows. +Let i = 0 and k = 0. +Then for j = (N - 1) down to 0, inclusive, do: + + +If k > 0, set + i = i + (V(N-j-1,k-1) + V(N-j,k-1))/2. + +Set k = k + abs(X[j]). + +If X[j] < 0, set + i = i + (V(N-j-1,k) + V(N-j,k))/2. + + + + + +The index i is then encoded using the procedure in + with ft = V(N,K). + + +
    + +
    + + + + + +
    + +
    + + +
    + + +It is our intention to allow the greatest possible choice of freedom in +implementing the specification. For this reason, outside of the exceptions +noted in this section, conformance is defined through the reference +implementation of the decoder provided in . +Although this document includes an English description of the codec, should +the description contradict the source code of the reference implementation, +the latter shall take precedence. + + + +Compliance with this specification means that in addition to following the normative keywords in this document, + a decoder's output MUST also be + within the thresholds specified by the opus_compare.c tool (included + with the code) when compared to the reference implementation for each of the + test vectors provided (see ) and for each output + sampling rate and channel count supported. In addition, a compliant + decoder implementation MUST have the same final range decoder state as that of the + reference decoder. It is therefore RECOMMENDED that the + decoder implement the same functional behavior as the reference. + + A decoder implementation is not required to support all output sampling + rates or all output channel counts. + + +
    + +Using the reference code provided in , +a test vector can be decoded with + +opus_demo -d <rate> <channels> testvectorX.bit testX.out + +where <rate> is the sampling rate and can be 8000, 12000, 16000, 24000, or 48000, and +<channels> is 1 for mono or 2 for stereo. + + + +If the range decoder state is incorrect for one of the frames, the decoder will exit with +"Error: Range coder state mismatch between encoder and decoder". If the decoder succeeds, then +the output can be compared with the "reference" output with + +opus_compare -s -r <rate> testvectorX.dec testX.out + +for stereo or + +opus_compare -r <rate> testvectorX.dec testX.out + +for mono. + + +In addition to indicating whether the test vector comparison passes, the opus_compare tool +outputs an "Opus quality metric" that indicates how well the tested decoder matches the +reference implementation. A quality of 0 corresponds to the passing threshold, while +a quality of 100 is the highest possible value and means that the output of the tested decoder is identical to the reference +implementation. The passing threshold (quality 0) was calibrated in such a way that it corresponds to +additive white noise with a 48 dB SNR (similar to what can be obtained on a cassette deck). +It is still possible for an implementation to sound very good with such a low quality measure +(e.g. if the deviation is due to inaudible phase distortion), but unless this is verified by +listening tests, it is RECOMMENDED that implementations achieve a quality above 90 for 48 kHz +decoding. For other sampling rates, it is normal for the quality metric to be lower +(typically as low as 50 even for a good implementation) because of harmless mismatch with +the delay and phase of the internal sampling rate conversion. + + + +On POSIX environments, the run_vectors.sh script can be used to verify all test +vectors. This can be done with + +run_vectors.sh <exec path> <vector path> <rate> + +where <exec path> is the directory where the opus_demo and opus_compare executables +are built and <vector path> is the directory containing the test vectors. + +
    + +
    + +Opus Custom is an OPTIONAL part of the specification that is defined to +handle special sample rates and frame rates that are not supported by the +main Opus specification. Use of Opus Custom is discouraged for all but very +special applications for which a frame size different from 2.5, 5, 10, or 20 ms is +needed (for either complexity or latency reasons). Because Opus Custom is +optional, streams encoded using Opus Custom cannot be expected to be decodable by all Opus +implementations. Also, because no in-band mechanism exists for specifying the sampling +rate and frame size of Opus Custom streams, out-of-band signaling is required. +In Opus Custom operation, only the CELT layer is available, using the opus_custom_* function +calls in opus_custom.h. + +
    + +
    + +
    + + +Implementations of the Opus codec need to take appropriate security considerations +into account, as outlined in . +It is extremely important for the decoder to be robust against malicious +payloads. +Malicious payloads must not cause the decoder to overrun its allocated memory + or to take an excessive amount of resources to decode. +Although problems +in encoders are typically rarer, the same applies to the encoder. Malicious +audio streams must not cause the encoder to misbehave because this would +allow an attacker to attack transcoding gateways. + + +The reference implementation contains no known buffer overflow or cases where + a specially crafted packet or audio segment could cause a significant increase + in CPU load. +However, on certain CPU architectures where denormalized floating-point + operations are much slower than normal floating-point operations, it is + possible for some audio content (e.g., silence or near-silence) to cause an + increase in CPU load. +Denormals can be introduced by reordering operations in the compiler and depend + on the target architecture, so it is difficult to guarantee that an implementation + avoids them. +For architectures on which denormals are problematic, adding very small + floating-point offsets to the affected signals to prevent significant numbers + of denormalized operations is RECOMMENDED. +Alternatively, it is often possible to configure the hardware to treat + denormals as zero (DAZ). +No such issue exists for the fixed-point reference implementation. + +The reference implementation was validated in the following conditions: + + +Sending the decoder valid packets generated by the reference encoder and + verifying that the decoder's final range coder state matches that of the + encoder. + + +Sending the decoder packets generated by the reference encoder and then + subjected to random corruption. + +Sending the decoder random packets. + +Sending the decoder packets generated by a version of the reference encoder + modified to make random coding decisions (internal fuzzing), including mode + switching, and verifying that the range coder final states match. + + +In all of the conditions above, both the encoder and the decoder were run + inside the Valgrind memory + debugger, which tracks reads and writes to invalid memory regions as well as + the use of uninitialized memory. +There were no errors reported on any of the tested conditions. + +
    + + +
    + +This document has no actions for IANA. + +
    + +
    + +Thanks to all other developers, including Raymond Chen, Soeren Skak Jensen, Gregory Maxwell, +Christopher Montgomery, and Karsten Vandborg Soerensen. We would also +like to thank Igor Dyakonov, Jan Skoglund, and Christian Hoene for their help with subjective testing of the +Opus codec. Thanks to Ralph Giles, John Ridges, Ben Schwartz, Keith Yan, Christian Hoene, Kat Walsh, and many others on the Opus and CELT mailing lists +for their bug reports and feedback. + +
    + +
    +The authors agree to grant third parties the irrevocable right to copy, use and distribute +the work (excluding Code Components available under the simplified BSD license), with or +without modification, in any medium, without royalty, provided that, unless separate +permission is granted, redistributed modified works do not contain misleading author, version, +name of work, or endorsement information. +
    + +
    + + + + + + + +Key words for use in RFCs to Indicate Requirement Levels + + + + + + + + + + + +Requirements for an Internet Audio Codec + + + + + +IETF + + +This document provides specific requirements for an Internet audio + codec. These requirements address quality, sample rate, bitrate, + and packet-loss robustness, as well as other desirable properties. + + + + + + + + + + +SILK Speech Codec + + + + + + + + + + + + + + + + + +Robust and Efficient Quantization of Speech LSP Parameters Using Structured Vector Quantization + + + + + + + + + + + + + + + + +Constrained-Energy Lapped Transform (CELT) Codec + + + + + + + + + + + + + + + + + + +Guidelines for the use of Variable Bit Rate Audio with Secure RTP + + + + + + + + + + + + + + +Internet Denial-of-Service Considerations + + + + + +IAB + + +This document provides an overview of possible avenues for denial-of-service (DoS) attack on Internet systems. The aim is to encourage protocol designers and network engineers towards designs that are more robust. We discuss partial solutions that reduce the effectiveness of attacks, and how some solutions might inadvertently open up alternative vulnerabilities. This memo provides information for the Internet community. + + + + + + +Range encoding: An algorithm for removing redundancy from a digitised message + + + + + + + + +Source coding algorithms for fast data compression + + + + + + + + +A Pyramid Vector Quantizer + + + + + + + + +The Computation of Line Spectral Frequencies Using Chebyshev Polynomials + + + + + + + + + + +Valgrind website + + + + + + +Google NetEQ code + + + + + + +Google WebRTC code + + + + + + + +Opus Git Repository + + + + + + +Opus website + + + + + + +Vorbis website + + + + + + +Matroska website + + + + + + +Opus Testvectors (webside) + + + + + + +Opus Testvectors (proceedings) + + + + + + +Line Spectral Pairs +Wikipedia + + + + + +Range Coding +Wikipedia + + + + + +Hadamard Transform +Wikipedia + + + + + +Viterbi Algorithm +Wikipedia + + + + + +White Noise +Wikipedia + + + + + +Linear Prediction +Wikipedia + + + + + +Modified Discrete Cosine Transform +Wikipedia + + + + + +Fast Fourier Transform +Wikipedia + + + + + +Z-transform +Wikipedia + + + + + + +Maximum Entropy Spectral Analysis + + + + + + +A fixed point computation of partial correlation coefficients + + + + + + + + +Analysis/synthesis filter bank design based on time domain aliasing cancellation + + + + + + + + +A High-Quality Speech and Audio Codec With Less Than 10 ms delay + + + + + + + + + + + + +Subdivision of the audible frequency range into critical bands + + + + + + + + + +
    + +This appendix contains the complete source code for the +reference implementation of the Opus codec written in C. By default, +this implementation relies on floating-point arithmetic, but it can be +compiled to use only fixed-point arithmetic by defining the FIXED_POINT +macro. Information on building and using the reference implementation is +available in the README file. + + +The implementation can be compiled with either a C89 or a C99 +compiler. It is reasonably optimized for most platforms such that +only architecture-specific optimizations are likely to be useful. +The FFT used is a slightly modified version of the KISS-FFT library, +but it is easy to substitute any other FFT library. + + + +While the reference implementation does not rely on any +undefined behavior as defined by C89 or C99, +it relies on common implementation-defined behavior +for two's complement architectures: + +Right shifts of negative values are consistent with two's complement arithmetic, so that a>>b is equivalent to floor(a/(2**b)), +For conversion to a signed integer of N bits, the value is reduced modulo 2**N to be within range of the type, +The result of integer division of a negative value is truncated towards zero, and +The compiler provides a 64-bit integer type (a C99 requirement which is supported by most C89 compilers). + + + + +In its current form, the reference implementation also requires the following +architectural characteristics to obtain acceptable performance: + +Two's complement arithmetic, +At least a 16 bit by 16 bit integer multiplier (32-bit result), and +At least a 32-bit adder/accumulator. + + + + +
    + +The complete source code can be extracted from this draft, by running the +following command line: + + + opus_source.tar.gz +]]> + +tar xzvf opus_source.tar.gz + +cd opus_source +make + +On systems where the provided Makefile does not work, the following command line may be used to compile +the source code: + + + + + +On systems where the base64 utility is not present, the following commands can be used instead: + + opus.b64 +]]> +openssl base64 -d -in opus.b64 > opus_source.tar.gz + + + +
    + +
    + +As of the time of publication of this memo, an up-to-date implementation conforming to +this standard is available in a + Git repository. +Releases and other resources are available at + . However, although that implementation is expected to + remain conformant with the standard, it is the code in this document that shall + remain normative. + +
    + +
    + + + +
    + +
    + +Because of size constraints, the Opus test vectors are not distributed in this +draft. They are available in the proceedings of the 83th IETF meeting (Paris) and from the Opus codec website at +. These test vectors were created specifically to exercise +all aspects of the decoder and therefore the audio quality of the decoded output is +significantly lower than what Opus can achieve in normal operation. + + + +The SHA1 hash of the files in the test vector package are + + + +
    + +
    + +
    + +To use the internal framing described in , the decoder + must know the total length of the Opus packet, in bytes. +This section describes a simple variation of that framing which can be used + when the total length of the packet is not known. +Nothing in the encoding of the packet itself allows a decoder to distinguish + between the regular, undelimited framing and the self-delimiting framing + described in this appendix. +Which one is used and where must be established by context at the transport + layer. +It is RECOMMENDED that a transport layer choose exactly one framing scheme, + rather than allowing an encoder to signal which one it wants to use. + + + +For example, although a regular Opus stream does not support more than two + channels, a multi-channel Opus stream may be formed from several one- and + two-channel streams. +To pack an Opus packet from each of these streams together in a single packet + at the transport layer, one could use the self-delimiting framing for all but + the last stream, and then the regular, undelimited framing for the last one. +Reverting to the undelimited framing for the last stream saves overhead + (because the total size of the transport-layer packet will still be known), + and ensures that a "multi-channel" stream which only has a single Opus stream + uses the same framing as a regular Opus stream does. +This avoids the need for signaling to distinguish these two cases. + + + +The self-delimiting framing is identical to the regular, undelimited framing + from , except that each Opus packet contains one extra + length field, encoded using the same one- or two-byte scheme from + . +This extra length immediately precedes the compressed data of the first Opus + frame in the packet, and is interpreted in the various modes as follows: + + +Code 0 packets: It is the length of the single Opus frame (see + ). + + +Code 1 packets: It is the length used for both of the Opus frames (see + ). + + +Code 2 packets: It is the length of the second Opus frame (see + ). + +CBR Code 3 packets: It is the length used for all of the Opus frames (see + ). + +VBR Code 3 packets: It is the length of the last Opus frame (see + ). + + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    diff --git a/native/codec/libraries/opus/doc/draft-ietf-payload-rtp-opus.xml b/native/codec/libraries/opus/doc/draft-ietf-payload-rtp-opus.xml new file mode 100644 index 0000000..c4eb210 --- /dev/null +++ b/native/codec/libraries/opus/doc/draft-ietf-payload-rtp-opus.xml @@ -0,0 +1,960 @@ + + + + + + + + + + + + + + + + + + + + + + ]> + + + + + + + + + + + + + + + + + + RTP Payload Format for the Opus Speech and Audio Codec + + + +
    + jspittka@gmail.com +
    +
    + + + vocTone +
    + + + + + + + + koenvos74@gmail.com +
    +
    + + + Mozilla +
    + + 331 E. Evelyn Avenue + Mountain View + CA + 94041 + USA + + jmvalin@jmvalin.ca +
    +
    + + + + + + This document defines the Real-time Transport Protocol (RTP) payload + format for packetization of Opus encoded + speech and audio data necessary to integrate the codec in the + most compatible way. It also provides an applicability statement + for the use of Opus over RTP. Further, it describes media type registrations + for the RTP payload format. + + +
    + + +
    + + Opus is a speech and audio codec developed within the + IETF Internet Wideband Audio Codec working group. The codec + has a very low algorithmic delay and it + is highly scalable in terms of audio bandwidth, bitrate, and + complexity. Further, it provides different modes to efficiently encode speech signals + as well as music signals, thus making it the codec of choice for + various applications using the Internet or similar networks. + + + This document defines the Real-time Transport Protocol (RTP) + payload format for packetization + of Opus encoded speech and audio data necessary to + integrate Opus in the + most compatible way. It also provides an applicability statement + for the use of Opus over RTP. + Further, it describes media type registrations for + the RTP payload format. + +
    + +
    + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in . + + + The range of audio frequecies being coded + Constant bitrate + Central Processing Unit + Discontinuous transmission + Forward error correction + Internet Protocol + Speech or audio samples (per channel) + Session Description Protocol + Variable bitrate + + + + Throughout this document, we refer to the following definitions: + + + Abbreviation + Name + Audio Bandwidth (Hz) + Sampling Rate (Hz) + NB + Narrowband + 0 - 4000 + 8000 + + MB + Mediumband + 0 - 6000 + 12000 + + WB + Wideband + 0 - 8000 + 16000 + + SWB + Super-wideband + 0 - 12000 + 24000 + + FB + Fullband + 0 - 20000 + 48000 + + + Audio bandwidth naming + + +
    + +
    + + Opus encodes speech + signals as well as general audio signals. Two different modes can be + chosen, a voice mode or an audio mode, to allow the most efficient coding + depending on the type of the input signal, the sampling frequency of the + input signal, and the intended application. + + + + The voice mode allows efficient encoding of voice signals at lower bit + rates while the audio mode is optimized for general audio signals at medium and + higher bitrates. + + + + Opus is highly scalable in terms of audio + bandwidth, bitrate, and complexity. Further, Opus allows + transmitting stereo signals with in-band signaling in the bit-stream. + + +
    + + Opus supports bitrates from 6 kb/s to 510 kb/s. + The bitrate can be changed dynamically within that range. + All + other parameters being + equal, higher bitrates result in higher audio quality. + +
    + + For a frame size of + 20 ms, these + are the bitrate "sweet spots" for Opus in various configurations: + + + 8-12 kb/s for NB speech, + 16-20 kb/s for WB speech, + 28-40 kb/s for FB speech, + 48-64 kb/s for FB mono music, and + 64-128 kb/s for FB stereo music. + + +
    +
    + + For the same average bitrate, variable bitrate (VBR) can achieve higher audio quality + than constant bitrate (CBR). For the majority of voice transmission applications, VBR + is the best choice. One reason for choosing CBR is the potential + information leak that might occur when encrypting the + compressed stream. See for guidelines on when VBR is + appropriate for encrypted audio communications. In the case where an existing + VBR stream needs to be converted to CBR for security reasons, then the Opus padding + mechanism described in is the RECOMMENDED way to achieve padding + because the RTP padding bit is unencrypted. + + + The bitrate can be adjusted at any point in time. To avoid congestion, + the average bitrate SHOULD NOT exceed the available + network bandwidth. If no target bitrate is specified, the bitrates specified in + are RECOMMENDED. + + +
    + +
    + + + Opus can, as described in , + be operated with a variable bitrate. In that case, the encoder will + automatically reduce the bitrate for certain input signals, like periods + of silence. When using continuous transmission, it will reduce the + bitrate when the characteristics of the input signal permit, but + will never interrupt the transmission to the receiver. Therefore, the + received signal will maintain the same high level of audio quality over the + full duration of a transmission while minimizing the average bit + rate over time. + + + + In cases where the bitrate of Opus needs to be reduced even + further or in cases where only constant bitrate is available, + the Opus encoder can use discontinuous + transmission (DTX), where parts of the encoded signal that + correspond to periods of silence in the input speech or audio signal + are not transmitted to the receiver. A receiver can distinguish + between DTX and packet loss by looking for gaps in the sequence + number, as described by Section 4.1 + of . + + + + On the receiving side, the non-transmitted parts will be handled by a + frame loss concealment unit in the Opus decoder which generates a + comfort noise signal to replace the non transmitted parts of the + speech or audio signal. Use of Comfort + Noise (CN) with Opus is discouraged. + The transmitter MUST drop whole frames only, + based on the size of the last transmitted frame, + to ensure successive RTP timestamps differ by a multiple of 120 and + to allow the receiver to use whole frames for concealment. + + + + DTX can be used with both variable and constant bitrate. + It will have a slightly lower speech or audio + quality than continuous transmission. Therefore, using continuous + transmission is RECOMMENDED unless constraints on available network bandwidth + are severe. + + +
    + +
    + +
    + + + Complexity of the encoder can be scaled to optimize for CPU resources in real-time, mostly as + a trade-off between audio quality and bitrate. Also, different modes of Opus have different complexity. + + +
    + +
    + + + The voice mode of Opus allows for embedding "in-band" forward error correction (FEC) + data into the Opus bit stream. This FEC scheme adds + redundant information about the previous packet (N-1) to the current + output packet N. For + each frame, the encoder decides whether to use FEC based on (1) an + externally-provided estimate of the channel's packet loss rate; (2) an + externally-provided estimate of the channel's capacity; (3) the + sensitivity of the audio or speech signal to packet loss; (4) whether + the receiving decoder has indicated it can take advantage of "in-band" + FEC information. The decision to send "in-band" FEC information is + entirely controlled by the encoder and therefore no special precautions + for the payload have to be taken. + + + + On the receiving side, the decoder can take advantage of this + additional information when it loses a packet and the next packet + is available. In order to use the FEC data, the jitter buffer needs + to provide access to payloads with the FEC data. + Instead of performing loss concealment for a missing packet, the + receiver can then configure its decoder to decode the FEC data from the next packet. + + + + Any compliant Opus decoder is capable of ignoring + FEC information when it is not needed, so encoding with FEC cannot cause + interoperability problems. + However, if FEC cannot be used on the receiving side, then FEC + SHOULD NOT be used, as it leads to an inefficient usage of network + resources. Decoder support for FEC SHOULD be indicated at the time a + session is set up. + + +
    + +
    + + + Opus allows for transmission of stereo audio signals. This operation + is signaled in-band in the Opus bit-stream and no special arrangement + is needed in the payload format. An + Opus decoder is capable of handling a stereo encoding, but an + application might only be capable of consuming a single audio + channel. + + + If a decoder cannot take advantage of the benefits of a stereo signal + this SHOULD be indicated at the time a session is set up. In that case + the sending side SHOULD NOT send stereo signals as it leads to an + inefficient usage of network resources. + + +
    + +
    + +
    + The payload format for Opus consists of the RTP header and Opus payload + data. +
    + The format of the RTP header is specified in . + The use of the fields of the RTP header by the Opus payload format is + consistent with that specification. + + The payload length of Opus is an integer number of octets and + therefore no padding is necessary. The payload MAY be padded by an + integer number of octets according to , + although the Opus internal padding is preferred. + + The timestamp, sequence number, and marker bit (M) of the RTP header + are used in accordance with Section 4.1 + of . + + The RTP payload type for Opus is to be assigned dynamically. + + The receiving side MUST be prepared to receive duplicate RTP + packets. The receiver MUST provide at most one of those payloads to the + Opus decoder for decoding, and MUST discard the others. + + Opus supports 5 different audio bandwidths, which can be adjusted during + a stream. + The RTP timestamp is incremented with a 48000 Hz clock rate + for all modes of Opus and all sampling rates. + The unit + for the timestamp is samples per single (mono) channel. The RTP timestamp corresponds to the + sample time of the first encoded sample in the encoded frame. + For data encoded with sampling rates other than 48000 Hz, + the sampling rate has to be adjusted to 48000 Hz. + +
    + +
    + + The Opus encoder can output encoded frames representing 2.5, 5, 10, 20, + 40, or 60 ms of speech or audio data. Further, an arbitrary number of frames can be + combined into a packet, up to a maximum packet duration representing + 120 ms of speech or audio data. The grouping of one or more Opus + frames into a single Opus packet is defined in Section 3 of + . An RTP payload MUST contain exactly one + Opus packet as defined by that document. + + + shows the structure combined with the RTP header. + +
    + + + +
    + + + shows supported frame sizes in + milliseconds of encoded speech or audio data for the speech and audio modes + (Mode) and sampling rates (fs) of Opus and shows how the timestamp is + incremented for packetization (ts incr). If the Opus encoder + outputs multiple encoded frames into a single packet, the timestamp + increment is the sum of the increments for the individual frames. + + + + Mode + fs + 2.5 + 5 + 10 + 20 + 40 + 60 + ts incr + all + 120 + 240 + 480 + 960 + 1920 + 2880 + voice + NB/MB/WB/SWB/FB + x + x + o + o + o + o + audio + NB/WB/SWB/FB + o + o + o + o + x + x + + +
    + +
    + +
    + + The target bitrate of Opus can be adjusted at any point in time, thus + allowing efficient congestion control. Furthermore, the amount + of encoded speech or audio data encoded in a + single packet can be used for congestion control, since the transmission + rate is inversely proportional to the packet duration. A lower packet + transmission rate reduces the amount of header overhead, but at the same + time increases latency and loss sensitivity, so it ought to be used with + care. + + Since UDP does not provide congestion control, applications that use + RTP over UDP SHOULD implement their own congestion control above the + UDP layer . Work in the rmcat working group + describes the + interactions and conceptual interfaces necessary between the application + components that relate to congestion control, including the RTP layer, + the higher-level media codec control layer, and the lower-level + transport interface, as well as components dedicated to congestion + control functions. +
    + +
    + One media subtype (audio/opus) has been defined and registered as + described in the following section. + +
    + Media type registration is done according to and . + + Type name: audio + Subtype name: opus + + Required parameters: + + the RTP timestamp is incremented with a + 48000 Hz clock rate for all modes of Opus and all sampling + rates. For data encoded with sampling rates other than 48000 Hz, + the sampling rate has to be adjusted to 48000 Hz. + + + + Optional parameters: + + + + a hint about the maximum output sampling rate that the receiver is + capable of rendering in Hz. + The decoder MUST be capable of decoding + any audio bandwidth but due to hardware limitations only signals + up to the specified sampling rate can be played back. Sending signals + with higher audio bandwidth results in higher than necessary network + usage and encoding complexity, so an encoder SHOULD NOT encode + frequencies above the audio bandwidth specified by maxplaybackrate. + This parameter can take any value between 8000 and 48000, although + commonly the value will match one of the Opus bandwidths + (). + By default, the receiver is assumed to have no limitations, i.e. 48000. + + + + + a hint about the maximum input sampling rate that the sender is likely to produce. + This is not a guarantee that the sender will never send any higher bandwidth + (e.g. it could send a pre-recorded prompt that uses a higher bandwidth), but it + indicates to the receiver that frequencies above this maximum can safely be discarded. + This parameter is useful to avoid wasting receiver resources by operating the audio + processing pipeline (e.g. echo cancellation) at a higher rate than necessary. + This parameter can take any value between 8000 and 48000, although + commonly the value will match one of the Opus bandwidths + (). + By default, the sender is assumed to have no limitations, i.e. 48000. + + + + the maximum duration of media represented + by a packet (according to Section 6 of + ) that a decoder wants to receive, in + milliseconds rounded up to the next full integer value. + Possible values are 3, 5, 10, 20, 40, 60, or an arbitrary + multiple of an Opus frame size rounded up to the next full integer + value, up to a maximum value of 120, as + defined in . If no value is + specified, the default is 120. + + + the preferred duration of media represented + by a packet (according to Section 6 of + ) that a decoder wants to receive, in + milliseconds rounded up to the next full integer value. + Possible values are 3, 5, 10, 20, 40, 60, or an arbitrary + multiple of an Opus frame size rounded up to the next full integer + value, up to a maximum value of 120, as defined in . If no value is + specified, the default is 20. + + + specifies the maximum average + receive bitrate of a session in bits per second (b/s). The actual + value of the bitrate can vary, as it is dependent on the + characteristics of the media in a packet. Note that the maximum + average bitrate MAY be modified dynamically during a session. Any + positive integer is allowed, but values outside the range + 6000 to 510000 SHOULD be ignored. If no value is specified, the + maximum value specified in + for the corresponding mode of Opus and corresponding maxplaybackrate + is the default. + + + specifies whether the decoder prefers receiving stereo or mono signals. + Possible values are 1 and 0 where 1 specifies that stereo signals are preferred, + and 0 specifies that only mono signals are preferred. + Independent of the stereo parameter every receiver MUST be able to receive and + decode stereo signals but sending stereo signals to a receiver that signaled a + preference for mono signals may result in higher than necessary network + utilization and encoding complexity. If no value is specified, + the default is 0 (mono). + + + + specifies whether the sender is likely to produce stereo audio. + Possible values are 1 and 0, where 1 specifies that stereo signals are likely to + be sent, and 0 specifies that the sender will likely only send mono. + This is not a guarantee that the sender will never send stereo audio + (e.g. it could send a pre-recorded prompt that uses stereo), but it + indicates to the receiver that the received signal can be safely downmixed to mono. + This parameter is useful to avoid wasting receiver resources by operating the audio + processing pipeline (e.g. echo cancellation) in stereo when not necessary. + If no value is specified, the default is 0 + (mono). + + + + specifies if the decoder prefers the use of a constant bitrate versus + variable bitrate. Possible values are 1 and 0, where 1 specifies constant + bitrate and 0 specifies variable bitrate. If no value is specified, + the default is 0 (vbr). When cbr is 1, the maximum average bitrate can still + change, e.g. to adapt to changing network conditions. + + + specifies that the decoder has the capability to + take advantage of the Opus in-band FEC. Possible values are 1 and 0. + Providing 0 when FEC cannot be used on the receiving side is + RECOMMENDED. If no + value is specified, useinbandfec is assumed to be 0. + This parameter is only a preference and the receiver MUST be able to process + packets that include FEC information, even if it means the FEC part is discarded. + + + specifies if the decoder prefers the use of + DTX. Possible values are 1 and 0. If no value is specified, the + default is 0. + + + Encoding considerations: + + The Opus media type is framed and consists of binary data according + to Section 4.8 in . + + + Security considerations: + + See of this document. + + + Interoperability considerations: none + Published specification: RFC [XXXX] + Note to the RFC Editor: Replace [XXXX] with the number of the published + RFC. + + Applications that use this media type: + + Any application that requires the transport of + speech or audio data can use this media type. Some examples are, + but not limited to, audio and video conferencing, Voice over IP, + media streaming. + + + Fragment identifier considerations: N/A + + Person & email address to contact for further information: + + SILK Support silksupport@skype.net + Jean-Marc Valin jmvalin@jmvalin.ca + + + Intended usage: COMMON + + Restrictions on usage: + + + For transfer over RTP, the RTP payload format ( of this document) SHALL be + used. + + + Author: + + Julian Spittka jspittka@gmail.com + Koen Vos koenvos74@gmail.com + Jean-Marc Valin jmvalin@jmvalin.ca + + + Change controller: IETF Payload Working Group delegated from the IESG +
    +
    + +
    + The information described in the media type specification has a + specific mapping to fields in the Session Description Protocol (SDP) + , which is commonly used to describe RTP + sessions. When SDP is used to specify sessions employing Opus, + the mapping is as follows: + + + + The media type ("audio") goes in SDP "m=" as the media name. + + The media subtype ("opus") goes in SDP "a=rtpmap" as the encoding + name. The RTP clock rate in "a=rtpmap" MUST be 48000 and the number of + channels MUST be 2. + + The OPTIONAL media type parameters "ptime" and "maxptime" are + mapped to "a=ptime" and "a=maxptime" attributes, respectively, in the + SDP. + + The OPTIONAL media type parameters "maxaveragebitrate", + "maxplaybackrate", "stereo", "cbr", "useinbandfec", and + "usedtx", when present, MUST be included in the "a=fmtp" attribute + in the SDP, expressed as a media type string in the form of a + semicolon-separated list of parameter=value pairs (e.g., + maxplaybackrate=48000). They MUST NOT be specified in an + SSRC-specific "fmtp" source-level attribute (as defined in + Section 6.3 of ). + + The OPTIONAL media type parameters "sprop-maxcapturerate", + and "sprop-stereo" MAY be mapped to the "a=fmtp" SDP attribute by + copying them directly from the media type parameter string as part + of the semicolon-separated list of parameter=value pairs (e.g., + sprop-stereo=1). These same OPTIONAL media type parameters MAY also + be specified using an SSRC-specific "fmtp" source-level attribute + as described in Section 6.3 of . + They MAY be specified in both places, in which case the parameter + in the source-level attribute overrides the one found on the + "a=fmtp" line. The value of any parameter which is not specified in + a source-level source attribute MUST be taken from the "a=fmtp" + line, if it is present there. + + + + + Below are some examples of SDP session descriptions for Opus: + + Example 1: Standard mono session with 48000 Hz clock rate +
    + + + +
    + + + Example 2: 16000 Hz clock rate, maximum packet size of 40 ms, + recommended packet size of 40 ms, maximum average bitrate of 20000 bps, + prefers to receive stereo but only plans to send mono, FEC is desired, + DTX is not desired + +
    + + + +
    + + Example 3: Two-way full-band stereo preferred + +
    + + + +
    + + +
    + + When using the offer-answer procedure described in to negotiate the use of Opus, the following + considerations apply: + + + + Opus supports several clock rates. For signaling purposes only + the highest, i.e. 48000, is used. The actual clock rate of the + corresponding media is signaled inside the payload and is not + restricted by this payload format description. The decoder MUST be + capable of decoding every received clock rate. An example + is shown below: + +
    + + + +
    +
    + + The "ptime" and "maxptime" parameters are unidirectional + receive-only parameters and typically will not compromise + interoperability; however, some values might cause application + performance to suffer. defines the SDP offer-answer handling of the + "ptime" parameter. The "maxptime" parameter MUST be handled in the + same way. + + + The "maxplaybackrate" parameter is a unidirectional receive-only + parameter that reflects limitations of the local receiver. When + sending to a single destination, a sender MUST NOT use an audio + bandwidth higher than necessary to make full use of audio sampled at + a sampling rate of "maxplaybackrate". Gateways or senders that + are sending the same encoded audio to multiple destinations + SHOULD NOT use an audio bandwidth higher than necessary to + represent audio sampled at "maxplaybackrate", as this would lead + to inefficient use of network resources. + The "maxplaybackrate" parameter does not + affect interoperability. Also, this parameter SHOULD NOT be used + to adjust the audio bandwidth as a function of the bitrate, as this + is the responsibility of the Opus encoder implementation. + + + The "maxaveragebitrate" parameter is a unidirectional receive-only + parameter that reflects limitations of the local receiver. The sender + of the other side MUST NOT send with an average bitrate higher than + "maxaveragebitrate" as it might overload the network and/or + receiver. The "maxaveragebitrate" parameter typically will not + compromise interoperability; however, some values might cause + application performance to suffer, and ought to be set with + care. + + The "sprop-maxcapturerate" and "sprop-stereo" parameters are + unidirectional sender-only parameters that reflect limitations of + the sender side. + They allow the receiver to set up a reduced-complexity audio + processing pipeline if the sender is not planning to use the full + range of Opus's capabilities. + Neither "sprop-maxcapturerate" nor "sprop-stereo" affect + interoperability and the receiver MUST be capable of receiving any signal. + + + + The "stereo" parameter is a unidirectional receive-only + parameter. When sending to a single destination, a sender MUST + NOT use stereo when "stereo" is 0. Gateways or senders that are + sending the same encoded audio to multiple destinations SHOULD + NOT use stereo when "stereo" is 0, as this would lead to + inefficient use of network resources. The "stereo" parameter does + not affect interoperability. + + + + The "cbr" parameter is a unidirectional receive-only + parameter. + + + The "useinbandfec" parameter is a unidirectional receive-only + parameter. + + The "usedtx" parameter is a unidirectional receive-only + parameter. + + Any unknown parameter in an offer MUST be ignored by the receiver + and MUST be removed from the answer. + +
    + + + The Opus parameters in an SDP Offer/Answer exchange are completely + orthogonal, and there is no relationship between the SDP Offer and + the Answer. + +
    + +
    + + For declarative use of SDP such as in Session Announcement Protocol + (SAP), , and RTSP, , for + Opus, the following needs to be considered: + + + + The values for "maxptime", "ptime", "maxplaybackrate", and + "maxaveragebitrate" ought to be selected carefully to ensure that a + reasonable performance can be achieved for the participants of a session. + + + The values for "maxptime", "ptime", and of the payload + format configuration are recommendations by the decoding side to ensure + the best performance for the decoder. + + + All other parameters of the payload format configuration are declarative + and a participant MUST use the configurations that are provided for + the session. More than one configuration can be provided if necessary + by declaring multiple RTP payload types; however, the number of types + ought to be kept small. + +
    +
    + +
    + + Use of variable bitrate (VBR) is subject to the security considerations in + . + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification , and in any applicable RTP profile such as + RTP/AVP , RTP/AVPF , + RTP/SAVP or RTP/SAVPF . + However, as "Securing the RTP Protocol Framework: + Why RTP Does Not Mandate a Single Media Security Solution" + discusses, it is not an RTP payload + format's responsibility to discuss or mandate what solutions are used + to meet the basic security goals like confidentiality, integrity and + source authenticity for RTP in general. This responsibility lays on + anyone using RTP in an application. They can find guidance on + available security mechanisms and important considerations in Options + for Securing RTP Sessions [I-D.ietf-avtcore-rtp-security-options]. + Applications SHOULD use one or more appropriate strong security + mechanisms. + + This payload format and the Opus encoding do not exhibit any + significant non-uniformity in the receiver-end computational load and thus + are unlikely to pose a denial-of-service threat due to the receipt of + pathological datagrams. +
    + +
    + Many people have made useful comments and suggestions contributing to this document. + In particular, we would like to thank + Tina le Grand, Cullen Jennings, Jonathan Lennox, Gregory Maxwell, Colin Perkins, Jan Skoglund, + Timothy B. Terriberry, Martin Thompson, Justin Uberti, Magnus Westerlund, and Mo Zanaty. +
    +
    + + + + &rfc2119; + &rfc3389; + &rfc3550; + &rfc3711; + &rfc3551; + &rfc6838; + &rfc4855; + &rfc4566; + &rfc3264; + &rfc2326; + &rfc5576; + &rfc6562; + &rfc6716; + + + + &rfc2974; + &rfc4585; + &rfc5124; + &rfc5405; + &rfc7202; + + + + rmcat documents + + + + + + + + + + + +
    diff --git a/native/codec/libraries/opus/doc/footer.html b/native/codec/libraries/opus/doc/footer.html new file mode 100644 index 0000000..ad4a925 --- /dev/null +++ b/native/codec/libraries/opus/doc/footer.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + +
    +For more information visit the Opus Website. + + +
    + + + diff --git a/native/codec/libraries/opus/doc/header.html b/native/codec/libraries/opus/doc/header.html new file mode 100644 index 0000000..b2c906b --- /dev/null +++ b/native/codec/libraries/opus/doc/header.html @@ -0,0 +1,54 @@ + + + + + +$projectname: $title +$title + + +$treeview +$search +$mathjax + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + +
    +
    Opus
    +
    + + +
    +
    $projectbrief
    +
    $projectnumber +
    +
    +
    $projectbrief
    +
    $searchbox
    +
    + diff --git a/native/codec/libraries/opus/doc/opus_in_isobmff.css b/native/codec/libraries/opus/doc/opus_in_isobmff.css new file mode 100644 index 0000000..bffe8f4 --- /dev/null +++ b/native/codec/libraries/opus/doc/opus_in_isobmff.css @@ -0,0 +1,60 @@ +/* Normal links */ +.normal_link a:link +{ + color : yellow; +} +.normal_link a:visited +{ + color : green; +} + +/* Boxes */ +.pre +{ + white-space: pre; /* CSS 2.0 */ + white-space: pre-wrap; /* CSS 2.1 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: -moz-pre-wrap; /* Mozilla */ + white-space: -hp-pre-wrap; /* HP Printers */ + word-wrap : break-word; /* IE 5+ */ +} + +.title_box +{ + width : 470px; + height : 70px; + margin : 2px 50px 2px 2px; + padding : 10px; + border : 1px solid black; + background-color : #666666; + white-space : pre; + float : left; + text-align : center; + color : #C0C0C0; + font-size : 50pt; + font-style : italic; +} + +.subindex_box +{ + margin : 5px; + padding : 14px 22px; + border : 1px solid black; + background-color : #778877; + float : left; + text-align : center; + color : #115555; + font-size : 32pt; +} + +.frame_box +{ + margin : 10px; + padding : 10px; + border : 0px; + background-color : #084040; + text-align : left; + color : #C0C0C0; + font-family : monospace; +} diff --git a/native/codec/libraries/opus/doc/opus_in_isobmff.html b/native/codec/libraries/opus/doc/opus_in_isobmff.html new file mode 100644 index 0000000..38aefbf --- /dev/null +++ b/native/codec/libraries/opus/doc/opus_in_isobmff.html @@ -0,0 +1,692 @@ + + + + + + Encapsulation of Opus in ISO Base Media File Format + + + Encapsulation of Opus in ISO Base Media File Format
    + last updated: August 28, 2018
    +
    + + + diff --git a/native/codec/libraries/opus/doc/opus_logo.svg b/native/codec/libraries/opus/doc/opus_logo.svg new file mode 100644 index 0000000..db2879e --- /dev/null +++ b/native/codec/libraries/opus/doc/opus_logo.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/opus/doc/opus_update.patch b/native/codec/libraries/opus/doc/opus_update.patch new file mode 100644 index 0000000..11f066c --- /dev/null +++ b/native/codec/libraries/opus/doc/opus_update.patch @@ -0,0 +1,244 @@ +diff --git a/celt/bands.c b/celt/bands.c +index 6962587..32e1de6 100644 +--- a/celt/bands.c ++++ b/celt/bands.c +@@ -1234,9 +1234,23 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, + b = 0; + } + +- if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0)) ++ if (resynth && (M*eBands[i]-N >= M*eBands[start] || i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + ++ if (i == start+1) ++ { ++ int n1, n2; ++ int offset; ++ n1 = M*(eBands[start+1]-eBands[start]); ++ n2 = M*(eBands[start+2]-eBands[start+1]); ++ offset = M*eBands[start]; ++ /* Duplicate enough of the first band folding data to be able to fold the second band. ++ Copies no data for CELT-only mode. */ ++ OPUS_COPY(&norm[offset+n1], &norm[offset+2*n1 - n2], n2-n1); ++ if (C==2) ++ OPUS_COPY(&norm2[offset+n1], &norm2[offset+2*n1 - n2], n2-n1); ++ } ++ + tf_change = tf_res[i]; + if (i>=m->effEBands) + { +@@ -1257,7 +1271,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; +- while(M*eBands[++fold_end] < effective_lowband+N); ++ while(++fold_end < i && M*eBands[fold_end] < effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; +diff --git a/celt/quant_bands.c b/celt/quant_bands.c +index e5ed9ef..82fb823 100644 +--- a/celt/quant_bands.c ++++ b/celt/quant_bands.c +@@ -552,6 +552,7 @@ void log2Amp(const CELTMode *m, int start, int end, + { + opus_val16 lg = ADD16(oldEBands[i+c*m->nbEBands], + SHL16((opus_val16)eMeans[i],6)); ++ lg = MIN32(QCONST32(32.f, 16), lg); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) +diff --git a/silk/LPC_inv_pred_gain.c b/silk/LPC_inv_pred_gain.c +index 60c439b..6c301da 100644 +--- a/silk/LPC_inv_pred_gain.c ++++ b/silk/LPC_inv_pred_gain.c +@@ -84,8 +84,13 @@ static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inver + + /* Update AR coefficient */ + for( n = 0; n < k; n++ ) { +- tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 ); +- Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q ); ++ opus_int64 tmp64; ++ tmp_QA = silk_SUB_SAT32( Aold_QA[ n ], MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 ) ); ++ tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( tmp_QA, rc_mult2 ), mult2Q); ++ if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { ++ return 0; ++ } ++ Anew_QA[ n ] = ( opus_int32 )tmp64; + } + } + +diff --git a/silk/NLSF_stabilize.c b/silk/NLSF_stabilize.c +index 979aaba..2ef2398 100644 +--- a/silk/NLSF_stabilize.c ++++ b/silk/NLSF_stabilize.c +@@ -134,7 +134,7 @@ void silk_NLSF_stabilize( + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) +- NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); ++ NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); +diff --git a/silk/dec_API.c b/silk/dec_API.c +index efd7918..21bb7e0 100644 +--- a/silk/dec_API.c ++++ b/silk/dec_API.c +@@ -72,6 +72,9 @@ opus_int silk_InitDecoder( /* O Returns error co + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } ++ silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo)); ++ /* Not strictly needed, but it's cleaner that way */ ++ ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; + } +diff --git a/silk/resampler_private_IIR_FIR.c b/silk/resampler_private_IIR_FIR.c +index dbd6d9a..91a43aa 100644 +--- a/silk/resampler_private_IIR_FIR.c ++++ b/silk/resampler_private_IIR_FIR.c +@@ -75,10 +75,10 @@ void silk_resampler_private_IIR_FIR( + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; +- opus_int16 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_12 ]; ++ opus_int16 buf[ 2*RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_12 ]; + + /* Copy buffered samples to start of buffer */ +- silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; +@@ -95,13 +95,13 @@ void silk_resampler_private_IIR_FIR( + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ +- silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memmove( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ +- silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } + +diff --git a/src/opus_decoder.c b/src/opus_decoder.c +index 0cc56f8..8a30fbc 100644 +--- a/src/opus_decoder.c ++++ b/src/opus_decoder.c +@@ -595,16 +595,14 @@ static int opus_packet_parse_impl(const unsigned char *data, int len, + /* Padding flag is bit 6 */ + if (ch&0x40) + { +- int padding=0; + int p; + do { + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; +- padding += p==255 ? 254: p; ++ len -= p==255 ? 254: p; + } while (p==255); +- len -= padding; + } + if (len<0) + return OPUS_INVALID_PACKET; +diff --git a/run_vectors.sh b/run_vectors.sh +index 7cd23ed..4841b0a 100755 +--- a/run_vectors.sh ++++ b/run_vectors.sh +@@ -1,3 +1,5 @@ ++#!/bin/sh ++# + # Copyright (c) 2011-2012 IETF Trust, Jean-Marc Valin. All rights reserved. + # + # This file is extracted from RFC6716. Please see that RFC for additional +@@ -31,10 +33,8 @@ + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-#!/bin/sh +- +-rm logs_mono.txt +-rm logs_stereo.txt ++rm -f logs_mono.txt logs_mono2.txt ++rm -f logs_stereo.txt logs_stereo2.txt + + if [ "$#" -ne "3" ]; then + echo "usage: run_vectors.sh " +@@ -45,18 +45,23 @@ CMD_PATH=$1 + VECTOR_PATH=$2 + RATE=$3 + +-OPUS_DEMO=$CMD_PATH/opus_demo +-OPUS_COMPARE=$CMD_PATH/opus_compare ++: ${OPUS_DEMO:=$CMD_PATH/opus_demo} ++: ${OPUS_COMPARE:=$CMD_PATH/opus_compare} + + if [ -d $VECTOR_PATH ]; then + echo Test vectors found in $VECTOR_PATH + else + echo No test vectors found +- #Don't make the test fail here because the test vectors will be +- #distributed separately ++ #Don't make the test fail here because the test vectors ++ #will be distributed separately + exit 0 + fi + ++if [ ! -x $OPUS_COMPARE ]; then ++ echo ERROR: Compare program not found: $OPUS_COMPARE ++ exit 1 ++fi ++ + if [ -x $OPUS_DEMO ]; then + echo Decoding with $OPUS_DEMO + else +@@ -82,9 +87,11 @@ do + echo ERROR: decoding failed + exit 1 + fi +- $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_mono.txt 2>&1 ++ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_mono.txt 2>&1 + float_ret=$? +- if [ "$float_ret" -eq "0" ]; then ++ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}m.dec tmp.out >> logs_mono2.txt 2>&1 ++ float_ret2=$? ++ if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo output matches reference + else + echo ERROR: output does not match reference +@@ -111,9 +118,11 @@ do + echo ERROR: decoding failed + exit 1 + fi +- $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_stereo.txt 2>&1 ++ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_stereo.txt 2>&1 + float_ret=$? +- if [ "$float_ret" -eq "0" ]; then ++ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}m.dec tmp.out >> logs_stereo2.txt 2>&1 ++ float_ret2=$? ++ if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo output matches reference + else + echo ERROR: output does not match reference +@@ -125,5 +134,10 @@ done + + + echo All tests have passed successfully +-grep quality logs_mono.txt | awk '{sum+=$4}END{print "Average mono quality is", sum/NR, "%"}' +-grep quality logs_stereo.txt | awk '{sum+=$4}END{print "Average stereo quality is", sum/NR, "%"}' ++mono1=`grep quality logs_mono.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++mono2=`grep quality logs_mono2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++echo $mono1 $mono2 | awk '{if ($2 > $1) $1 = $2; print "Average mono quality is", $1, "%"}' ++ ++stereo1=`grep quality logs_stereo.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++stereo2=`grep quality logs_stereo2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++echo $stereo1 $stereo2 | awk '{if ($2 > $1) $1 = $2; print "Average stereo quality is", $1, "%"}' diff --git a/native/codec/libraries/opus/doc/release.txt b/native/codec/libraries/opus/doc/release.txt new file mode 100644 index 0000000..6d3ffa2 --- /dev/null +++ b/native/codec/libraries/opus/doc/release.txt @@ -0,0 +1,43 @@ += Release checklist = + +== Source release == + +- Check for uncommitted changes to master. +- Update OPUS_LT_* API versioning in configure.ac. +- Tag the release commit with 'git tag -s vN.M'. + - Include release notes in the tag annotation. +- Verify 'make distcheck' produces a tarball with + the desired name. +- Push tag to public repo. +- Upload source package 'opus-${version}.tar.gz' + - Add to https://svn.xiph.org/releases/opus/ + - Update checksum files + - svn commit + - Copy to archive.mozilla.org/pub/opus/ + - Update checksum files there as well. +- Add release notes to https://git.xiph.org/opus-website.git +- Update links and checksums on the downloads page. +- Add a copy of the documentation to + and update the links. +- Update /topic in #opus IRC channel. + +Releases are commited to https://svn.xiph.org/releases/opus/ +which propagates to downloads.xiph.org, and copied manually +to https://archive.mozilla.org/pub/opus/ + +Website updates are committed to https://git.xiph.org/opus-website.git +which propagates to https://opus-codec.org/ + +== Binary release == + +We usually build opus-tools binaries for MacOS and Windows. + +Binary releases are copied manually to +https://archive.mozilla.org/pub/opus/win32/ + +For Mac, submit a pull request to homebrew. + +== Website updates == + +For major releases, recreate the files on https://opus-codec.org/examples/ +with the next encoder. diff --git a/native/codec/libraries/opus/doc/trivial_example.c b/native/codec/libraries/opus/doc/trivial_example.c new file mode 100644 index 0000000..047ca0a --- /dev/null +++ b/native/codec/libraries/opus/doc/trivial_example.c @@ -0,0 +1,160 @@ +/* Copyright (c) 2013 Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is meant to be a simple example of encoding and decoding audio + using Opus. It should make it easy to understand how the Opus API + works. For more information, see the full API documentation at: + https://www.opus-codec.org/docs/ */ + +#include +#include +#include +#include +#include + +/*The frame size is hardcoded for this sample code but it doesn't have to be*/ +#define FRAME_SIZE 960 +#define SAMPLE_RATE 48000 +#define CHANNELS 2 +#define APPLICATION OPUS_APPLICATION_AUDIO +#define BITRATE 64000 + +#define MAX_FRAME_SIZE 6*960 +#define MAX_PACKET_SIZE (3*1276) + +int main(int argc, char **argv) +{ + char *inFile; + FILE *fin; + char *outFile; + FILE *fout; + opus_int16 in[FRAME_SIZE*CHANNELS]; + opus_int16 out[MAX_FRAME_SIZE*CHANNELS]; + unsigned char cbits[MAX_PACKET_SIZE]; + int nbBytes; + /*Holds the state of the encoder and decoder */ + OpusEncoder *encoder; + OpusDecoder *decoder; + int err; + + if (argc != 3) + { + fprintf(stderr, "usage: trivial_example input.pcm output.pcm\n"); + fprintf(stderr, "input and output are 16-bit little-endian raw files\n"); + return EXIT_FAILURE; + } + + /*Create a new encoder state */ + encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err); + if (err<0) + { + fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + /* Set the desired bit-rate. You can also set other parameters if needed. + The Opus library is designed to have good defaults, so only set + parameters you know you need. Doing otherwise is likely to result + in worse quality, but better. */ + err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE)); + if (err<0) + { + fprintf(stderr, "failed to set bitrate: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + inFile = argv[1]; + fin = fopen(inFile, "r"); + if (fin==NULL) + { + fprintf(stderr, "failed to open input file: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + + /* Create a new decoder state. */ + decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err); + if (err<0) + { + fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + outFile = argv[2]; + fout = fopen(outFile, "w"); + if (fout==NULL) + { + fprintf(stderr, "failed to open output file: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + while (1) + { + int i; + unsigned char pcm_bytes[MAX_FRAME_SIZE*CHANNELS*2]; + int frame_size; + + /* Read a 16 bits/sample audio frame. */ + fread(pcm_bytes, sizeof(short)*CHANNELS, FRAME_SIZE, fin); + if (feof(fin)) + break; + /* Convert from little-endian ordering. */ + for (i=0;i>8)&0xFF; + } + /* Write the decoded audio to file. */ + fwrite(pcm_bytes, sizeof(short), frame_size*CHANNELS, fout); + } + /*Destroy the encoder state*/ + opus_encoder_destroy(encoder); + opus_decoder_destroy(decoder); + fclose(fin); + fclose(fout); + return EXIT_SUCCESS; +} diff --git a/native/codec/libraries/opus/include/opus.h b/native/codec/libraries/opus/include/opus.h new file mode 100644 index 0000000..d282f21 --- /dev/null +++ b/native/codec/libraries/opus/include/opus.h @@ -0,0 +1,981 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus.h + * @brief Opus reference implementation API + */ + +#ifndef OPUS_H +#define OPUS_H + +#include "opus_types.h" +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @mainpage Opus + * + * The Opus codec is designed for interactive speech and audio transmission over the Internet. + * It is designed by the IETF Codec Working Group and incorporates technology from + * Skype's SILK codec and Xiph.Org's CELT codec. + * + * The Opus codec is designed to handle a wide range of interactive audio applications, + * including Voice over IP, videoconferencing, in-game chat, and even remote live music + * performances. It can scale from low bit-rate narrowband speech to very high quality + * stereo music. Its main features are: + + * @li Sampling rates from 8 to 48 kHz + * @li Bit-rates from 6 kb/s to 510 kb/s + * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR) + * @li Audio bandwidth from narrowband to full-band + * @li Support for speech and music + * @li Support for mono and stereo + * @li Support for multichannel (up to 255 channels) + * @li Frame sizes from 2.5 ms to 60 ms + * @li Good loss robustness and packet loss concealment (PLC) + * @li Floating point and fixed-point implementation + * + * Documentation sections: + * @li @ref opus_encoder + * @li @ref opus_decoder + * @li @ref opus_repacketizer + * @li @ref opus_multistream + * @li @ref opus_libinfo + * @li @ref opus_custom + */ + +/** @defgroup opus_encoder Opus Encoder + * @{ + * + * @brief This page describes the process and functions used to encode Opus. + * + * Since Opus is a stateful codec, the encoding process starts with creating an encoder + * state. This can be done with: + * + * @code + * int error; + * OpusEncoder *enc; + * enc = opus_encoder_create(Fs, channels, application, &error); + * @endcode + * + * From this point, @c enc can be used for encoding an audio stream. An encoder state + * @b must @b not be used for more than one stream at the same time. Similarly, the encoder + * state @b must @b not be re-initialized for each frame. + * + * While opus_encoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * + * @code + * int size; + * int error; + * OpusEncoder *enc; + * size = opus_encoder_get_size(channels); + * enc = malloc(size); + * error = opus_encoder_init(enc, Fs, channels, application); + * @endcode + * + * where opus_encoder_get_size() returns the required size for the encoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The encoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * It is possible to change some of the encoder's settings using the opus_encoder_ctl() + * interface. All these settings already default to the recommended value, so they should + * only be changed when necessary. The most common settings one may want to change are: + * + * @code + * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)); + * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); + * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type)); + * @endcode + * + * where + * + * @arg bitrate is in bits per second (b/s) + * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest + * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC + * + * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream. + * + * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data: + * @code + * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet); + * @endcode + * + * where + *
      + *
    • audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
    • + *
    • frame_size is the duration of the frame in samples (per channel)
    • + *
    • packet is the byte array to which the compressed data is written
    • + *
    • max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended). + * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.
    • + *
    + * + * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet. + * The return value can be negative, which indicates that an error has occurred. If the return value + * is 2 bytes or less, then the packet does not need to be transmitted (DTX). + * + * Once the encoder state if no longer needed, it can be destroyed with + * + * @code + * opus_encoder_destroy(enc); + * @endcode + * + * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(), + * then no action is required aside from potentially freeing the memory that was manually + * allocated for it (calling free(enc) for the example above) + * + */ + +/** Opus encoder state. + * This contains the complete state of an Opus encoder. + * It is position independent and can be freely copied. + * @see opus_encoder_create,opus_encoder_init + */ +typedef struct OpusEncoder OpusEncoder; + +/** Gets the size of an OpusEncoder structure. + * @param[in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels); + +/** + */ + +/** Allocates and initializes an encoder state. + * There are three coding modes: + * + * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice + * signals. It enhances the input signal by high-pass filtering and + * emphasizing formants and harmonics. Optionally it includes in-band + * forward error correction to protect against packet loss. Use this + * mode for typical VoIP applications. Because of the enhancement, + * even at high bitrates the output may sound different from the input. + * + * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most + * non-voice signals like music. Use this mode for music and mixed + * (music/voice) content, broadcast, and applications requiring less + * than 15 ms of coding delay. + * + * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that + * disables the speech-optimized mode in exchange for slightly reduced delay. + * This mode can only be set on an newly initialized or freshly reset encoder + * because it changes the codec delay. + * + * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @param [out] error int*: @ref opus_errorcodes + * @note Regardless of the sampling rate and number channels selected, the Opus encoder + * can switch to a lower audio bandwidth or number of channels if the bitrate + * selected is too low. This also means that it is safe to always use 48 kHz stereo input + * and let the encoder optimize the encoding. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create( + opus_int32 Fs, + int channels, + int application, + int *error +); + +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be at least the size returned by opus_encoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_encoder_create(),opus_encoder_get_size() + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_encoder_init( + OpusEncoder *st, + opus_int32 Fs, + int channels, + int application +) OPUS_ARG_NONNULL(1); + +/** Encodes an Opus frame. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode( + OpusEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes an Opus frame from floating point input. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. + * length is frame_size*channels*sizeof(float) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float( + OpusEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusEncoder allocated by opus_encoder_create(). + * @param[in] st OpusEncoder*: State to be freed. + */ +OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st); + +/** Perform a CTL function on an Opus encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusEncoder*: Encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_encoderctls. + * @see opus_genericctls + * @see opus_encoderctls + */ +OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); +/**@}*/ + +/** @defgroup opus_decoder Opus Decoder + * @{ + * + * @brief This page describes the process and functions used to decode Opus. + * + * The decoding process also starts with creating a decoder + * state. This can be done with: + * @code + * int error; + * OpusDecoder *dec; + * dec = opus_decoder_create(Fs, channels, &error); + * @endcode + * where + * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000 + * @li channels is the number of channels (1 or 2) + * @li error will hold the error code in case of failure (or #OPUS_OK on success) + * @li the return value is a newly created decoder state to be used for decoding + * + * While opus_decoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * @code + * int size; + * int error; + * OpusDecoder *dec; + * size = opus_decoder_get_size(channels); + * dec = malloc(size); + * error = opus_decoder_init(dec, Fs, channels); + * @endcode + * where opus_decoder_get_size() returns the required size for the decoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The decoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data: + * @code + * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0); + * @endcode + * where + * + * @li packet is the byte array containing the compressed data + * @li len is the exact number of bytes contained in the packet + * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float()) + * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array + * + * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet. + * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio + * buffer is too small to hold the decoded audio. + * + * Opus is a stateful codec with overlapping blocks and as a result Opus + * packets are not coded independently of each other. Packets must be + * passed into the decoder serially and in the correct order for a correct + * decode. Lost packets can be replaced with loss concealment by calling + * the decoder with a null pointer and zero length for the missing packet. + * + * A single codec state may only be accessed from a single thread at + * a time and any required locking must be performed by the caller. Separate + * streams must be decoded with separate decoder states and can be decoded + * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK + * defined. + * + */ + +/** Opus decoder state. + * This contains the complete state of an Opus decoder. + * It is position independent and can be freely copied. + * @see opus_decoder_create,opus_decoder_init + */ +typedef struct OpusDecoder OpusDecoder; + +/** Gets the size of an OpusDecoder structure. + * @param [in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels); + +/** Allocates and initializes a decoder state. + * @param [in] Fs opus_int32: Sample rate to decode at (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes + * + * Internally Opus stores data at 48000 Hz, so that should be the default + * value for Fs. However, the decoder can efficiently decode to buffers + * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use + * data at the full sample rate, or knows the compressed data doesn't + * use the full frequency range, it can request decoding at a reduced + * rate. Likewise, the decoder is capable of filling in either mono or + * interleaved stereo pcm buffers, at the caller's request. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create( + opus_int32 Fs, + int channels, + int *error +); + +/** Initializes a previously allocated decoder state. + * The state must be at least the size returned by opus_decoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusDecoder*: Decoder state. + * @param [in] Fs opus_int32: Sampling rate to decode to (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_decoder_init( + OpusDecoder *st, + opus_int32 Fs, + int channels +) OPUS_ARG_NONNULL(1); + +/** Decode an Opus packet. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload* + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available, the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an Opus packet with floating point output. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusDecoder*: Decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_decoderctls. + * @see opus_genericctls + * @see opus_decoderctls + */ +OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusDecoder allocated by opus_decoder_create(). + * @param[in] st OpusDecoder*: State to be freed. + */ +OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st); + +/** Parse an opus packet into one or more frames. + * Opus_decode will perform this operation internally so most applications do + * not need to use this function. + * This function does not copy the frames, the returned pointers are pointers into + * the input packet. + * @param [in] data char*: Opus packet to be parsed + * @param [in] len opus_int32: size of data + * @param [out] out_toc char*: TOC pointer + * @param [out] frames char*[48] encapsulated frames + * @param [out] size opus_int16[48] sizes of the encapsulated frames + * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes) + * @returns number of frames + */ +OPUS_EXPORT int opus_packet_parse( + const unsigned char *data, + opus_int32 len, + unsigned char *out_toc, + const unsigned char *frames[48], + opus_int16 size[48], + int *payload_offset +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5); + +/** Gets the bandwidth of an Opus packet. + * @param [in] data char*: Opus packet + * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass) + * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass) + * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass) + * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass) + * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass) + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples per frame from an Opus packet. + * @param [in] data char*: Opus packet. + * This must contain at least one byte of + * data. + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples per frame. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of channels from an Opus packet. + * @param [in] data char*: Opus packet + * @returns Number of channels + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of frames in an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of frames + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] dec OpusDecoder*: Decoder state + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of samples + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +/** Applies soft-clipping to bring a float signal within the [-1,1] range. If + * the signal is already in that range, nothing is done. If there are values + * outside of [-1,1], then the signal is clipped as smoothly as possible to + * both fit in the range and avoid creating excessive distortion in the + * process. + * @param [in,out] pcm float*: Input PCM and modified PCM + * @param [in] frame_size int Number of samples per channel to process + * @param [in] channels int: Number of channels + * @param [in,out] softclip_mem float*: State memory for the soft clipping process (one float per channel, initialized to zero) + */ +OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem); + + +/**@}*/ + +/** @defgroup opus_repacketizer Repacketizer + * @{ + * + * The repacketizer can be used to merge multiple Opus packets into a single + * packet or alternatively to split Opus packets that have previously been + * merged. Splitting valid Opus packets is always guaranteed to succeed, + * whereas merging valid packets only succeeds if all frames have the same + * mode, bandwidth, and frame size, and when the total duration of the merged + * packet is no more than 120 ms. The 120 ms limit comes from the + * specification and limits decoder memory requirements at a point where + * framing overhead becomes negligible. + * + * The repacketizer currently only operates on elementary Opus + * streams. It will not manipualte multistream packets successfully, except in + * the degenerate case where they consist of data from a single stream. + * + * The repacketizing process starts with creating a repacketizer state, either + * by calling opus_repacketizer_create() or by allocating the memory yourself, + * e.g., + * @code + * OpusRepacketizer *rp; + * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size()); + * if (rp != NULL) + * opus_repacketizer_init(rp); + * @endcode + * + * Then the application should submit packets with opus_repacketizer_cat(), + * extract new packets with opus_repacketizer_out() or + * opus_repacketizer_out_range(), and then reset the state for the next set of + * input packets via opus_repacketizer_init(). + * + * For example, to split a sequence of packets into individual frames: + * @code + * unsigned char *data; + * int len; + * while (get_next_packet(&data, &len)) + * { + * unsigned char out[1276]; + * opus_int32 out_len; + * int nb_frames; + * int err; + * int i; + * err = opus_repacketizer_cat(rp, data, len); + * if (err != OPUS_OK) + * { + * release_packet(data); + * return err; + * } + * nb_frames = opus_repacketizer_get_nb_frames(rp); + * for (i = 0; i < nb_frames; i++) + * { + * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packet(data); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * } + * opus_repacketizer_init(rp); + * release_packet(data); + * } + * @endcode + * + * Alternatively, to combine a sequence of frames into packets that each + * contain up to TARGET_DURATION_MS milliseconds of data: + * @code + * // The maximum number of packets with duration TARGET_DURATION_MS occurs + * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5) + * // packets. + * unsigned char *data[(TARGET_DURATION_MS*2/5)+1]; + * opus_int32 len[(TARGET_DURATION_MS*2/5)+1]; + * int nb_packets; + * unsigned char out[1277*(TARGET_DURATION_MS*2/2)]; + * opus_int32 out_len; + * int prev_toc; + * nb_packets = 0; + * while (get_next_packet(data+nb_packets, len+nb_packets)) + * { + * int nb_frames; + * int err; + * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]); + * if (nb_frames < 1) + * { + * release_packets(data, nb_packets+1); + * return nb_frames; + * } + * nb_frames += opus_repacketizer_get_nb_frames(rp); + * // If adding the next packet would exceed our target, or it has an + * // incompatible TOC sequence, output the packets we already have before + * // submitting it. + * // N.B., The nb_packets > 0 check ensures we've submitted at least one + * // packet since the last call to opus_repacketizer_init(). Otherwise a + * // single packet longer than TARGET_DURATION_MS would cause us to try to + * // output an (invalid) empty packet. It also ensures that prev_toc has + * // been set to a valid value. Additionally, len[nb_packets] > 0 is + * // guaranteed by the call to opus_packet_get_nb_frames() above, so the + * // reference to data[nb_packets][0] should be valid. + * if (nb_packets > 0 && ( + * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) || + * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames > + * TARGET_DURATION_MS*48)) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packets(data, nb_packets+1); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * opus_repacketizer_init(rp); + * release_packets(data, nb_packets); + * data[0] = data[nb_packets]; + * len[0] = len[nb_packets]; + * nb_packets = 0; + * } + * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]); + * if (err != OPUS_OK) + * { + * release_packets(data, nb_packets+1); + * return err; + * } + * prev_toc = data[nb_packets][0]; + * nb_packets++; + * } + * // Output the final, partial packet. + * if (nb_packets > 0) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * release_packets(data, nb_packets); + * if (out_len < 0) + * return (int)out_len; + * output_next_packet(out, out_len); + * } + * @endcode + * + * An alternate way of merging packets is to simply call opus_repacketizer_cat() + * unconditionally until it fails. At that point, the merged packet can be + * obtained with opus_repacketizer_out() and the input packet for which + * opus_repacketizer_cat() needs to be re-added to a newly reinitialized + * repacketizer state. + */ + +typedef struct OpusRepacketizer OpusRepacketizer; + +/** Gets the size of an OpusRepacketizer structure. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void); + +/** (Re)initializes a previously allocated repacketizer state. + * The state must be at least the size returned by opus_repacketizer_get_size(). + * This can be used for applications which use their own allocator instead of + * malloc(). + * It must also be called to reset the queue of packets waiting to be + * repacketized, which is necessary if the maximum packet duration of 120 ms + * is reached or if you wish to submit packets with a different Opus + * configuration (coding mode, audio bandwidth, frame size, or channel count). + * Failure to do so will prevent a new packet from being added with + * opus_repacketizer_cat(). + * @see opus_repacketizer_create + * @see opus_repacketizer_get_size + * @see opus_repacketizer_cat + * @param rp OpusRepacketizer*: The repacketizer state to + * (re)initialize. + * @returns A pointer to the same repacketizer state that was passed in. + */ +OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Allocates memory and initializes the new repacketizer with + * opus_repacketizer_init(). + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void); + +/** Frees an OpusRepacketizer allocated by + * opus_repacketizer_create(). + * @param[in] rp OpusRepacketizer*: State to be freed. + */ +OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp); + +/** Add a packet to the current repacketizer state. + * This packet must match the configuration of any packets already submitted + * for repacketization since the last call to opus_repacketizer_init(). + * This means that it must have the same coding mode, audio bandwidth, frame + * size, and channel count. + * This can be checked in advance by examining the top 6 bits of the first + * byte of the packet, and ensuring they match the top 6 bits of the first + * byte of any previously submitted packet. + * The total duration of audio in the repacketizer state also must not exceed + * 120 ms, the maximum duration of a single packet, after adding this packet. + * + * The contents of the current repacketizer state can be extracted into new + * packets using opus_repacketizer_out() or opus_repacketizer_out_range(). + * + * In order to add a packet with a different configuration or to add more + * audio beyond 120 ms, you must clear the repacketizer state by calling + * opus_repacketizer_init(). + * If a packet is too large to add to the current repacketizer state, no part + * of it is added, even if it contains multiple frames, some of which might + * fit. + * If you wish to be able to add parts of such packets, you should first use + * another repacketizer to split the packet into pieces and add them + * individually. + * @see opus_repacketizer_out_range + * @see opus_repacketizer_out + * @see opus_repacketizer_init + * @param rp OpusRepacketizer*: The repacketizer state to which to + * add the packet. + * @param[in] data const unsigned char*: The packet data. + * The application must ensure + * this pointer remains valid + * until the next call to + * opus_repacketizer_init() or + * opus_repacketizer_destroy(). + * @param len opus_int32: The number of bytes in the packet data. + * @returns An error code indicating whether or not the operation succeeded. + * @retval #OPUS_OK The packet's contents have been added to the repacketizer + * state. + * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence, + * the packet's TOC sequence was not compatible + * with previously submitted packets (because + * the coding mode, audio bandwidth, frame size, + * or channel count did not match), or adding + * this packet would increase the total amount of + * audio stored in the repacketizer state to more + * than 120 ms. + */ +OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param begin int: The index of the first frame in the current + * repacketizer state to include in the output. + * @param end int: One past the index of the last frame in the + * current repacketizer state to include in the + * output. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1276 for a single frame, + * or for multiple frames, + * 1277*(end-begin). + * However, 1*(end-begin) plus + * the size of all packet data submitted to + * the repacketizer since the last call to + * opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of + * frames (begin < 0, begin >= end, or end > + * opus_repacketizer_get_nb_frames()). + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Return the total number of frames contained in packet data submitted to + * the repacketizer state so far via opus_repacketizer_cat() since the last + * call to opus_repacketizer_init() or opus_repacketizer_create(). + * This defines the valid range of packets that can be extracted with + * opus_repacketizer_out_range() or opus_repacketizer_out(). + * @param rp OpusRepacketizer*: The repacketizer state containing the + * frames. + * @returns The total number of frames contained in the packet data submitted + * to the repacketizer state. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * This is a convenience routine that returns all the data submitted so far + * in a single packet. + * It is equivalent to calling + * @code + * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp), + * data, maxlen) + * @endcode + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1277*opus_repacketizer_get_nb_frames(rp). + * However, + * 1*opus_repacketizer_get_nb_frames(rp) + * plus the size of all packet data + * submitted to the repacketizer since the + * last call to opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1); + +/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence). + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to pad. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param new_len opus_int32: The desired size of the packet after padding. + * This must be at least as large as len. + * @returns an error code + * @retval #OPUS_OK \a on success. + * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len); + +/** Remove all padding from a given Opus packet and rewrite the TOC sequence to + * minimize space usage. + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to strip. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @returns The new size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG \a len was less than 1. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len); + +/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence). + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to pad. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param new_len opus_int32: The desired size of the packet after padding. + * This must be at least 1. + * @param nb_streams opus_int32: The number of streams (not channels) in the packet. + * This must be at least as large as len. + * @returns an error code + * @retval #OPUS_OK \a on success. + * @retval #OPUS_BAD_ARG \a len was less than 1. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams); + +/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to + * minimize space usage. + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to strip. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param nb_streams opus_int32: The number of streams (not channels) in the packet. + * This must be at least 1. + * @returns The new size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_H */ diff --git a/native/codec/libraries/opus/include/opus_custom.h b/native/codec/libraries/opus/include/opus_custom.h new file mode 100644 index 0000000..41f36bf --- /dev/null +++ b/native/codec/libraries/opus/include/opus_custom.h @@ -0,0 +1,342 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2012 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + @file opus_custom.h + @brief Opus-Custom reference implementation API + */ + +#ifndef OPUS_CUSTOM_H +#define OPUS_CUSTOM_H + +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CUSTOM_MODES +# define OPUS_CUSTOM_EXPORT OPUS_EXPORT +# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT +#else +# define OPUS_CUSTOM_EXPORT +# ifdef OPUS_BUILD +# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE +# else +# define OPUS_CUSTOM_EXPORT_STATIC +# endif +#endif + +/** @defgroup opus_custom Opus Custom + * @{ + * Opus Custom is an optional part of the Opus specification and + * reference implementation which uses a distinct API from the regular + * API and supports frame sizes that are not normally supported.\ Use + * of Opus Custom is discouraged for all but very special applications + * for which a frame size different from 2.5, 5, 10, or 20 ms is needed + * (for either complexity or latency reasons) and where interoperability + * is less important. + * + * In addition to the interoperability limitations the use of Opus custom + * disables a substantial chunk of the codec and generally lowers the + * quality available at a given bitrate. Normally when an application needs + * a different frame size from the codec it should buffer to match the + * sizes but this adds a small amount of delay which may be important + * in some very low latency applications. Some transports (especially + * constant rate RF transports) may also work best with frames of + * particular durations. + * + * Libopus only supports custom modes if they are enabled at compile time. + * + * The Opus Custom API is similar to the regular API but the + * @ref opus_encoder_create and @ref opus_decoder_create calls take + * an additional mode parameter which is a structure produced by + * a call to @ref opus_custom_mode_create. Both the encoder and decoder + * must create a mode using the same sample rate (fs) and frame size + * (frame size) so these parameters must either be signaled out of band + * or fixed in a particular implementation. + * + * Similar to regular Opus the custom modes support on the fly frame size + * switching, but the sizes available depend on the particular frame size in + * use. For some initial frame sizes on a single on the fly size is available. + */ + +/** Contains the state of an encoder. One encoder state is needed + for each stream. It is initialized once at the beginning of the + stream. Do *not* re-initialize the state for every frame. + @brief Encoder state + */ +typedef struct OpusCustomEncoder OpusCustomEncoder; + +/** State of the decoder. One decoder state is needed for each stream. + It is initialized once at the beginning of the stream. Do *not* + re-initialize the state for every frame. + @brief Decoder state + */ +typedef struct OpusCustomDecoder OpusCustomDecoder; + +/** The mode contains all the information necessary to create an + encoder. Both the encoder and decoder need to be initialized + with exactly the same mode, otherwise the output will be + corrupted. + @brief Mode configuration + */ +typedef struct OpusCustomMode OpusCustomMode; + +/** Creates a new mode struct. This will be passed to an encoder or + * decoder. The mode MUST NOT BE DESTROYED until the encoders and + * decoders that use it are destroyed as well. + * @param [in] Fs int: Sampling rate (8000 to 96000 Hz) + * @param [in] frame_size int: Number of samples (per channel) to encode in each + * packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes) + * @param [out] error int*: Returned error code (if NULL, no error will be returned) + * @return A newly created mode + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error); + +/** Destroys a mode struct. Only call this after all encoders and + * decoders using this mode are destroyed as well. + * @param [in] mode OpusCustomMode*: Mode to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode); + + +#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C) + +/* Encoder */ +/** Gets the size of an OpusCustomEncoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +# ifdef CUSTOM_MODES +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_encoder_create(),opus_custom_encoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_init( + OpusCustomEncoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); +# endif +#endif + + +/** Creates a new encoder state. Each stream needs its own encoder + * state (can't be shared across simultaneous streams). + * @param [in] mode OpusCustomMode*: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created encoder state. +*/ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + + +/** Destroys a an encoder state. + * @param[in] st OpusCustomEncoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm float*: PCM audio in float format, with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. There must be exactly + * frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float( + OpusCustomEncoder *st, + const float *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm opus_int16*: PCM audio in signed 16-bit format (native endian). + * There must be exactly frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode( + OpusCustomEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_encoderctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + + +#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C) +/* Decoder */ + +/** Gets the size of an OpusCustomDecoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +/** Initializes a previously allocated decoder state + * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_decoder_create(),opus_custom_decoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * encoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init( + OpusCustomDecoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +#endif + + +/** Creates a new decoder state. Each stream needs its own decoder state (can't + * be shared across simultaneous streams). + * @param [in] mode OpusCustomMode: Contains all the information about the characteristics of the + * stream (must be the same characteristics as used for the encoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created decoder state. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + +/** Destroys a an decoder state. + * @param[in] st OpusCustomDecoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st); + +/** Decode an opus custom frame with floating point output + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + float *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an opus custom frame + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + opus_int16 *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_genericctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_CUSTOM_H */ diff --git a/native/codec/libraries/opus/include/opus_defines.h b/native/codec/libraries/opus/include/opus_defines.h new file mode 100644 index 0000000..d141418 --- /dev/null +++ b/native/codec/libraries/opus/include/opus_defines.h @@ -0,0 +1,799 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus_defines.h + * @brief Opus reference implementation constants + */ + +#ifndef OPUS_DEFINES_H +#define OPUS_DEFINES_H + +#include "opus_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup opus_errorcodes Error codes + * @{ + */ +/** No error @hideinitializer*/ +#define OPUS_OK 0 +/** One or more invalid/out of range arguments @hideinitializer*/ +#define OPUS_BAD_ARG -1 +/** Not enough bytes allocated in the buffer @hideinitializer*/ +#define OPUS_BUFFER_TOO_SMALL -2 +/** An internal error was detected @hideinitializer*/ +#define OPUS_INTERNAL_ERROR -3 +/** The compressed data passed is corrupted @hideinitializer*/ +#define OPUS_INVALID_PACKET -4 +/** Invalid/unsupported request number @hideinitializer*/ +#define OPUS_UNIMPLEMENTED -5 +/** An encoder or decoder structure is invalid or already freed @hideinitializer*/ +#define OPUS_INVALID_STATE -6 +/** Memory allocation has failed @hideinitializer*/ +#define OPUS_ALLOC_FAIL -7 +/**@}*/ + +/** @cond OPUS_INTERNAL_DOC */ +/**Export control for opus functions */ + +#ifndef OPUS_EXPORT +# if defined(WIN32) +# if defined(OPUS_BUILD) && defined(DLL_EXPORT) +# define OPUS_EXPORT __declspec(dllexport) +# else +# define OPUS_EXPORT +# endif +# elif defined(__GNUC__) && defined(OPUS_BUILD) +# define OPUS_EXPORT __attribute__ ((visibility ("default"))) +# else +# define OPUS_EXPORT +# endif +#endif + +# if !defined(OPUS_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define OPUS_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define OPUS_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(3,0) +# define OPUS_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define OPUS_RESTRICT __restrict +# else +# define OPUS_RESTRICT +# endif +#else +# define OPUS_RESTRICT restrict +#endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(2,7) +# define OPUS_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define OPUS_INLINE __inline +# else +# define OPUS_INLINE +# endif +#else +# define OPUS_INLINE inline +#endif + +/**Warning attributes for opus functions + * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out + * some paranoid null checks. */ +#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +#else +# define OPUS_WARN_UNUSED_RESULT +#endif +#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +#else +# define OPUS_ARG_NONNULL(_x) +#endif + +/** These are the actual Encoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +#define OPUS_SET_APPLICATION_REQUEST 4000 +#define OPUS_GET_APPLICATION_REQUEST 4001 +#define OPUS_SET_BITRATE_REQUEST 4002 +#define OPUS_GET_BITRATE_REQUEST 4003 +#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004 +#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005 +#define OPUS_SET_VBR_REQUEST 4006 +#define OPUS_GET_VBR_REQUEST 4007 +#define OPUS_SET_BANDWIDTH_REQUEST 4008 +#define OPUS_GET_BANDWIDTH_REQUEST 4009 +#define OPUS_SET_COMPLEXITY_REQUEST 4010 +#define OPUS_GET_COMPLEXITY_REQUEST 4011 +#define OPUS_SET_INBAND_FEC_REQUEST 4012 +#define OPUS_GET_INBAND_FEC_REQUEST 4013 +#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014 +#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015 +#define OPUS_SET_DTX_REQUEST 4016 +#define OPUS_GET_DTX_REQUEST 4017 +#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020 +#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021 +#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022 +#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023 +#define OPUS_SET_SIGNAL_REQUEST 4024 +#define OPUS_GET_SIGNAL_REQUEST 4025 +#define OPUS_GET_LOOKAHEAD_REQUEST 4027 +/* #define OPUS_RESET_STATE 4028 */ +#define OPUS_GET_SAMPLE_RATE_REQUEST 4029 +#define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_GET_PITCH_REQUEST 4033 +#define OPUS_SET_GAIN_REQUEST 4034 +#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */ +#define OPUS_SET_LSB_DEPTH_REQUEST 4036 +#define OPUS_GET_LSB_DEPTH_REQUEST 4037 +#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039 +#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040 +#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041 +#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042 +#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043 +/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */ +#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046 +#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047 +#define OPUS_GET_IN_DTX_REQUEST 4049 + +/** Defines for the presence of extended APIs. */ +#define OPUS_HAVE_OPUS_PROJECTION_H + +/* Macros to trigger compilation errors when the wrong types are provided to a CTL */ +#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) +#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr))) +#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr))) +#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr))) +/** @endcond */ + +/** @defgroup opus_ctlvalues Pre-defined values for CTL interface + * @see opus_genericctls, opus_encoderctls + * @{ + */ +/* Values for the various encoder CTLs */ +#define OPUS_AUTO -1000 /**opus_int32: Allowed values: 0-10, inclusive. + * + * @hideinitializer */ +#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x) +/** Gets the encoder's complexity configuration. + * @see OPUS_SET_COMPLEXITY + * @param[out] x opus_int32 *: Returns a value in the range 0-10, + * inclusive. + * @hideinitializer */ +#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x) + +/** Configures the bitrate in the encoder. + * Rates from 500 to 512000 bits per second are meaningful, as well as the + * special values #OPUS_AUTO and #OPUS_BITRATE_MAX. + * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much + * rate as it can, which is useful for controlling the rate by adjusting the + * output buffer size. + * @see OPUS_GET_BITRATE + * @param[in] x opus_int32: Bitrate in bits per second. The default + * is determined based on the number of + * channels and the input sampling rate. + * @hideinitializer */ +#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x) +/** Gets the encoder's bitrate configuration. + * @see OPUS_SET_BITRATE + * @param[out] x opus_int32 *: Returns the bitrate in bits per second. + * The default is determined based on the + * number of channels and the input + * sampling rate. + * @hideinitializer */ +#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables variable bitrate (VBR) in the encoder. + * The configured bitrate may not be met exactly because frames must + * be an integer number of bytes in length. + * @see OPUS_GET_VBR + * @see OPUS_SET_VBR_CONSTRAINT + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Hard CBR. For LPC/hybrid modes at very low bit-rate, this can + * cause noticeable quality degradation.
    + *
    1
    VBR (default). The exact type of VBR is controlled by + * #OPUS_SET_VBR_CONSTRAINT.
    + *
    + * @hideinitializer */ +#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x) +/** Determine if variable bitrate (VBR) is enabled in the encoder. + * @see OPUS_SET_VBR + * @see OPUS_GET_VBR_CONSTRAINT + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Hard CBR.
    + *
    1
    VBR (default). The exact type of VBR may be retrieved via + * #OPUS_GET_VBR_CONSTRAINT.
    + *
    + * @hideinitializer */ +#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables constrained VBR in the encoder. + * This setting is ignored when the encoder is in CBR mode. + * @warning Only the MDCT mode of Opus currently heeds the constraint. + * Speech mode ignores it completely, hybrid mode may fail to obey it + * if the LPC layer uses more bitrate than the constraint would have + * permitted. + * @see OPUS_GET_VBR_CONSTRAINT + * @see OPUS_SET_VBR + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Unconstrained VBR.
    + *
    1
    Constrained VBR (default). This creates a maximum of one + * frame of buffering delay assuming a transport with a + * serialization speed of the nominal bitrate.
    + *
    + * @hideinitializer */ +#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x) +/** Determine if constrained VBR is enabled in the encoder. + * @see OPUS_SET_VBR_CONSTRAINT + * @see OPUS_GET_VBR + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Unconstrained VBR.
    + *
    1
    Constrained VBR (default).
    + *
    + * @hideinitializer */ +#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x) + +/** Configures mono/stereo forcing in the encoder. + * This can force the encoder to produce packets encoded as either mono or + * stereo, regardless of the format of the input audio. This is useful when + * the caller knows that the input signal is currently a mono source embedded + * in a stereo stream. + * @see OPUS_GET_FORCE_CHANNELS + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    Not forced (default)
    + *
    1
    Forced mono
    + *
    2
    Forced stereo
    + *
    + * @hideinitializer */ +#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) +/** Gets the encoder's forced channel configuration. + * @see OPUS_SET_FORCE_CHANNELS + * @param[out] x opus_int32 *: + *
    + *
    #OPUS_AUTO
    Not forced (default)
    + *
    1
    Forced mono
    + *
    2
    Forced stereo
    + *
    + * @hideinitializer */ +#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) + +/** Configures the maximum bandpass that the encoder will select automatically. + * Applications should normally use this instead of #OPUS_SET_BANDWIDTH + * (leaving that set to the default, #OPUS_AUTO). This allows the + * application to set an upper bound based on the type of input it is + * providing, but still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_MAX_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
    + *
    OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    OPUS_BANDWIDTH_FULLBAND
    20 kHz passband (default)
    + *
    + * @hideinitializer */ +#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Gets the encoder's configured maximum allowed bandpass. + * @see OPUS_SET_MAX_BANDWIDTH + * @param[out] x opus_int32 *: Allowed values: + *
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband (default)
    + *
    + * @hideinitializer */ +#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Sets the encoder's bandpass to a specific value. + * This prevents the encoder from automatically selecting the bandpass based + * on the available bitrate. If an application knows the bandpass of the input + * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH + * instead, which still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband
    + *
    + * @hideinitializer */ +#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Configures the type of signal being encoded. + * This is a hint which helps the encoder's mode selection. + * @see OPUS_GET_SIGNAL + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_SIGNAL_VOICE
    Bias thresholds towards choosing LPC or Hybrid modes.
    + *
    #OPUS_SIGNAL_MUSIC
    Bias thresholds towards choosing MDCT modes.
    + *
    + * @hideinitializer */ +#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal type. + * @see OPUS_SET_SIGNAL + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_SIGNAL_VOICE
    Bias thresholds towards choosing LPC or Hybrid modes.
    + *
    #OPUS_SIGNAL_MUSIC
    Bias thresholds towards choosing MDCT modes.
    + *
    + * @hideinitializer */ +#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x) + + +/** Configures the encoder's intended application. + * The initial value is a mandatory argument to the encoder_create function. + * @see OPUS_GET_APPLICATION + * @param[in] x opus_int32: Returns one of the following values: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @hideinitializer */ +#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured application. + * @see OPUS_SET_APPLICATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @hideinitializer */ +#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the total samples of delay added by the entire codec. + * This can be queried by the encoder and then the provided number of samples can be + * skipped on from the start of the decoder's output to provide time aligned input + * and output. From the perspective of a decoding application the real data begins this many + * samples late. + * + * The decoder contribution to this delay is identical for all decoders, but the + * encoder portion of the delay may vary from implementation to implementation, + * version to version, or even depend on the encoder's initial configuration. + * Applications needing delay compensation should call this CTL rather than + * hard-coding a value. + * @param[out] x opus_int32 *: Number of lookahead samples + * @hideinitializer */ +#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of inband forward error correction (FEC). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_INBAND_FEC + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Disable inband FEC (default).
    + *
    1
    Enable inband FEC.
    + *
    + * @hideinitializer */ +#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of inband forward error correction. + * @see OPUS_SET_INBAND_FEC + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Inband FEC disabled (default).
    + *
    1
    Inband FEC enabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's expected packet loss percentage. + * Higher values trigger progressively more loss resistant behavior in the encoder + * at the expense of quality at a given bitrate in the absence of packet loss, but + * greater quality under loss. + * @see OPUS_GET_PACKET_LOSS_PERC + * @param[in] x opus_int32: Loss percentage in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured packet loss percentage. + * @see OPUS_SET_PACKET_LOSS_PERC + * @param[out] x opus_int32 *: Returns the configured loss percentage + * in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of discontinuous transmission (DTX). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_DTX + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Disable DTX (default).
    + *
    1
    Enabled DTX.
    + *
    + * @hideinitializer */ +#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of discontinuous transmission. + * @see OPUS_SET_DTX + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    DTX disabled (default).
    + *
    1
    DTX enabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x) +/** Configures the depth of signal being encoded. + * + * This is a hint which helps the encoder identify silence and near-silence. + * It represents the number of significant bits of linear intensity below + * which the signal contains ignorable quantization or other noise. + * + * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting + * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate + * for 16-bit linear pcm input with opus_encode_float(). + * + * When using opus_encode() instead of opus_encode_float(), or when libopus + * is compiled for fixed-point, the encoder uses the minimum of the value + * set here and the value 16. + * + * @see OPUS_GET_LSB_DEPTH + * @param[in] x opus_int32: Input precision in bits, between 8 and 24 + * (default: 24). + * @hideinitializer */ +#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal depth. + * @see OPUS_SET_LSB_DEPTH + * @param[out] x opus_int32 *: Input precision in bits, between 8 and + * 24 (default: 24). + * @hideinitializer */ +#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of variable duration frames. + * When variable duration is enabled, the encoder is free to use a shorter frame + * size than the one requested in the opus_encode*() call. + * It is then the user's responsibility + * to verify how much audio was encoded by checking the ToC byte of the encoded + * packet. The part of the audio that was not encoded needs to be resent to the + * encoder for the next call. Do not use this option unless you really + * know what you are doing. + * @see OPUS_GET_EXPERT_FRAME_DURATION + * @param[in] x opus_int32: Allowed values: + *
    + *
    OPUS_FRAMESIZE_ARG
    Select frame size from the argument (default).
    + *
    OPUS_FRAMESIZE_2_5_MS
    Use 2.5 ms frames.
    + *
    OPUS_FRAMESIZE_5_MS
    Use 5 ms frames.
    + *
    OPUS_FRAMESIZE_10_MS
    Use 10 ms frames.
    + *
    OPUS_FRAMESIZE_20_MS
    Use 20 ms frames.
    + *
    OPUS_FRAMESIZE_40_MS
    Use 40 ms frames.
    + *
    OPUS_FRAMESIZE_60_MS
    Use 60 ms frames.
    + *
    OPUS_FRAMESIZE_80_MS
    Use 80 ms frames.
    + *
    OPUS_FRAMESIZE_100_MS
    Use 100 ms frames.
    + *
    OPUS_FRAMESIZE_120_MS
    Use 120 ms frames.
    + *
    + * @hideinitializer */ +#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured use of variable duration frames. + * @see OPUS_SET_EXPERT_FRAME_DURATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    OPUS_FRAMESIZE_ARG
    Select frame size from the argument (default).
    + *
    OPUS_FRAMESIZE_2_5_MS
    Use 2.5 ms frames.
    + *
    OPUS_FRAMESIZE_5_MS
    Use 5 ms frames.
    + *
    OPUS_FRAMESIZE_10_MS
    Use 10 ms frames.
    + *
    OPUS_FRAMESIZE_20_MS
    Use 20 ms frames.
    + *
    OPUS_FRAMESIZE_40_MS
    Use 40 ms frames.
    + *
    OPUS_FRAMESIZE_60_MS
    Use 60 ms frames.
    + *
    OPUS_FRAMESIZE_80_MS
    Use 80 ms frames.
    + *
    OPUS_FRAMESIZE_100_MS
    Use 100 ms frames.
    + *
    OPUS_FRAMESIZE_120_MS
    Use 120 ms frames.
    + *
    + * @hideinitializer */ +#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x) + +/** If set to 1, disables almost all use of prediction, making frames almost + * completely independent. This reduces quality. + * @see OPUS_GET_PREDICTION_DISABLED + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Enable prediction (default).
    + *
    1
    Disable prediction.
    + *
    + * @hideinitializer */ +#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured prediction status. + * @see OPUS_SET_PREDICTION_DISABLED + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Prediction enabled (default).
    + *
    1
    Prediction disabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_genericctls Generic CTLs + * + * These macros are used with the \c opus_decoder_ctl and + * \c opus_encoder_ctl calls to generate a particular + * request. + * + * When called on an \c OpusDecoder they apply to that + * particular decoder instance. When called on an + * \c OpusEncoder they apply to the corresponding setting + * on that encoder instance, if present. + * + * Some usage examples: + * + * @code + * int ret; + * opus_int32 pitch; + * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch)); + * if (ret == OPUS_OK) return ret; + * + * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE); + * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE); + * + * opus_int32 enc_bw, dec_bw; + * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw)); + * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw)); + * if (enc_bw != dec_bw) { + * printf("packet bandwidth mismatch!\n"); + * } + * @endcode + * + * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls + * @{ + */ + +/** Resets the codec state to be equivalent to a freshly initialized state. + * This should be called when switching streams in order to prevent + * the back to back decoding from giving different results from + * one at a time decoding. + * @hideinitializer */ +#define OPUS_RESET_STATE 4028 + +/** Gets the final state of the codec's entropy coder. + * This is used for testing purposes, + * The encoder and decoder state should be identical after coding a payload + * (assuming no data corruption or software bugs) + * + * @param[out] x opus_uint32 *: Entropy coder state + * + * @hideinitializer */ +#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) + +/** Gets the encoder's configured bandpass or the decoder's last bandpass. + * @see OPUS_SET_BANDWIDTH + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband
    + *
    + * @hideinitializer */ +#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Gets the sampling rate the encoder or decoder was initialized with. + * This simply returns the Fs value passed to opus_encoder_init() + * or opus_decoder_init(). + * @param[out] x opus_int32 *: Sampling rate of encoder or decoder. + * @hideinitializer + */ +#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x) + +/** If set to 1, disables the use of phase inversion for intensity stereo, + * improving the quality of mono downmixes, but slightly reducing normal + * stereo quality. Disabling phase inversion in the decoder does not comply + * with RFC 6716, although it does not cause any interoperability issue and + * is expected to become part of the Opus standard once RFC 6716 is updated + * by draft-ietf-codec-opus-update. + * @see OPUS_GET_PHASE_INVERSION_DISABLED + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Enable phase inversion (default).
    + *
    1
    Disable phase inversion.
    + *
    + * @hideinitializer */ +#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured phase inversion status. + * @see OPUS_SET_PHASE_INVERSION_DISABLED + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Stereo phase inversion enabled (default).
    + *
    1
    Stereo phase inversion disabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x) +/** Gets the DTX state of the encoder. + * Returns whether the last encoded frame was either a comfort noise update + * during DTX or not encoded because of DTX. + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    The encoder is not in DTX.
    + *
    1
    The encoder is in DTX.
    + *
    + * @hideinitializer */ +#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_decoderctls Decoder related CTLs + * @see opus_genericctls, opus_encoderctls, opus_decoder + * @{ + */ + +/** Configures decoder gain adjustment. + * Scales the decoded output by a factor specified in Q8 dB units. + * This has a maximum range of -32768 to 32767 inclusive, and returns + * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment. + * This setting survives decoder reset. + * + * gain = pow(10, x/(20.0*256)) + * + * @param[in] x opus_int32: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x) +/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN + * + * @param[out] x opus_int32 *: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x) + +/** Gets the duration (in samples) of the last packet successfully decoded or concealed. + * @param[out] x opus_int32 *: Number of samples (at current sampling rate). + * @hideinitializer */ +#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the pitch of the last decoded frame, if available. + * This can be used for any post-processing algorithm requiring the use of pitch, + * e.g. time stretching/shortening. If the last frame was not voiced, or if the + * pitch was not coded in the frame, then zero is returned. + * + * This CTL is only implemented for decoder instances. + * + * @param[out] x opus_int32 *: pitch period at 48 kHz (or 0 if not available) + * + * @hideinitializer */ +#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_libinfo Opus library information functions + * @{ + */ + +/** Converts an opus error code into a human readable string. + * + * @param[in] error int: Error number + * @returns Error string + */ +OPUS_EXPORT const char *opus_strerror(int error); + +/** Gets the libopus version string. + * + * Applications may look for the substring "-fixed" in the version string to + * determine whether they have a fixed-point or floating-point build at + * runtime. + * + * @returns Version string + */ +OPUS_EXPORT const char *opus_get_version_string(void); +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_DEFINES_H */ diff --git a/native/codec/libraries/opus/include/opus_multistream.h b/native/codec/libraries/opus/include/opus_multistream.h new file mode 100644 index 0000000..babcee6 --- /dev/null +++ b/native/codec/libraries/opus/include/opus_multistream.h @@ -0,0 +1,660 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus_multistream.h + * @brief Opus reference implementation multistream API + */ + +#ifndef OPUS_MULTISTREAM_H +#define OPUS_MULTISTREAM_H + +#include "opus.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** Macros to trigger compilation errors when the wrong types are provided to a + * CTL. */ +/**@{*/ +#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr))) +#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr))) +/**@}*/ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120 +#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122 +/**@}*/ + +/** @endcond */ + +/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and + * @ref opus_decoderctls may be applied to a multistream encoder or decoder as + * well. + * In addition, you may retrieve the encoder or decoder state for an specific + * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or + * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually. + */ +/**@{*/ + +/** Gets the encoder state for an individual stream of a multistream encoder. + * @param[in] x opus_int32: The index of the stream whose encoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the encoder. + * @param[out] y OpusEncoder**: Returns a pointer to the given + * encoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y) + +/** Gets the decoder state for an individual stream of a multistream decoder. + * @param[in] x opus_int32: The index of the stream whose decoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the decoder. + * @param[out] y OpusDecoder**: Returns a pointer to the given + * decoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y) + +/**@}*/ + +/** @defgroup opus_multistream Opus Multistream API + * @{ + * + * The multistream API allows individual Opus streams to be combined into a + * single packet, enabling support for up to 255 channels. Unlike an + * elementary Opus stream, the encoder and decoder must negotiate the channel + * configuration before the decoder can successfully interpret the data in the + * packets produced by the encoder. Some basic information, such as packet + * duration, can be computed without any special negotiation. + * + * The format for multistream Opus packets is defined in + * RFC 7845 + * and is based on the self-delimited Opus framing described in Appendix B of + * RFC 6716. + * Normal Opus packets are just a degenerate case of multistream Opus packets, + * and can be encoded or decoded with the multistream API by setting + * streams to 1 when initializing the encoder or + * decoder. + * + * Multistream Opus streams can contain up to 255 elementary Opus streams. + * These may be either "uncoupled" or "coupled", indicating that the decoder + * is configured to decode them to either 1 or 2 channels, respectively. + * The streams are ordered so that all coupled streams appear at the + * beginning. + * + * A mapping table defines which decoded channel i + * should be used for each input/output (I/O) channel j. This table is + * typically provided as an unsigned char array. + * Let i = mapping[j] be the index for I/O channel j. + * If i < 2*coupled_streams, then I/O channel j is + * encoded as the left channel of stream (i/2) if i + * is even, or as the right channel of stream (i/2) if + * i is odd. Otherwise, I/O channel j is encoded as + * mono in stream (i - coupled_streams), unless it has the special + * value 255, in which case it is omitted from the encoding entirely (the + * decoder will reproduce it as silence). Each value i must either + * be the special value 255 or be less than streams + coupled_streams. + * + * The output channels specified by the encoder + * should use the + * Vorbis + * channel ordering. A decoder may wish to apply an additional permutation + * to the mapping the encoder used to achieve a different output channel + * order (e.g. for outputing in WAV order). + * + * Each multistream packet contains an Opus packet for each stream, and all of + * the Opus packets in a single multistream packet must have the same + * duration. Therefore the duration of a multistream packet can be extracted + * from the TOC sequence of the first stream, which is located at the + * beginning of the packet, just like an elementary Opus stream: + * + * @code + * int nb_samples; + * int nb_frames; + * nb_frames = opus_packet_get_nb_frames(data, len); + * if (nb_frames < 1) + * return nb_frames; + * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames; + * @endcode + * + * The general encoding and decoding process proceeds exactly the same as in + * the normal @ref opus_encoder and @ref opus_decoder APIs. + * See their documentation for an overview of how to use the corresponding + * multistream functions. + */ + +/** Opus multistream encoder state. + * This contains the complete state of a multistream Opus encoder. + * It is position independent and can be freely copied. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_init + */ +typedef struct OpusMSEncoder OpusMSEncoder; + +/** Opus multistream decoder state. + * This contains the complete state of a multistream Opus decoder. + * It is position independent and can be freely copied. + * @see opus_multistream_decoder_create + * @see opus_multistream_decoder_init + */ +typedef struct OpusMSDecoder OpusMSDecoder; + +/**\name Multistream encoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSEncoder structure. + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size( + int streams, + int coupled_streams +); + +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size( + int channels, + int mapping_family +); + + +/** Allocates and initializes a multistream encoder state. + * Call opus_multistream_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(5); + +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); + +/** Initialize a previously allocated multistream encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +OPUS_EXPORT int opus_multistream_surround_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6) OPUS_ARG_NONNULL(7); + +/** Encodes a multistream Opus frame. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode( + OpusMSEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a multistream Opus frame from floating point input. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float( + OpusMSEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusMSEncoder allocated by + * opus_multistream_encoder_create(). + * @param st OpusMSEncoder*: Multistream encoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st); + +/** Perform a CTL function on a multistream Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +/**\name Multistream decoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSDecoder structure. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size( + int streams, + int coupled_streams +); + +/** Allocates and initializes a multistream decoder state. + * Call opus_multistream_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) OPUS_ARG_NONNULL(5); + +/** Intialize a previously allocated decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_decoder_create + * @see opus_multistream_deocder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +/** Decode a multistream Opus packet. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode a multistream Opus packet with floating point output. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on a multistream Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusMSDecoder allocated by + * opus_multistream_decoder_create(). + * @param st OpusMSDecoder: Multistream decoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_MULTISTREAM_H */ diff --git a/native/codec/libraries/opus/include/opus_projection.h b/native/codec/libraries/opus/include/opus_projection.h new file mode 100644 index 0000000..9dabf4e --- /dev/null +++ b/native/codec/libraries/opus/include/opus_projection.h @@ -0,0 +1,568 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus_projection.h + * @brief Opus projection reference API + */ + +#ifndef OPUS_PROJECTION_H +#define OPUS_PROJECTION_H + +#include "opus_multistream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications.c + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST 6001 +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST 6003 +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST 6005 +/**@}*/ + + +/** @endcond */ + +/** @defgroup opus_projection_ctls Projection specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_projection_encoder_ctl() and opus_projection_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, + * @ref opus_decoderctls, and @ref opus_multistream_ctls may be applied to a + * projection encoder or decoder as well. + */ +/**@{*/ + +/** Gets the gain (in dB. S7.8-format) of the demixing matrix from the encoder. + * @param[out] x opus_int32 *: Returns the gain (in dB. S7.8-format) + * of the demixing matrix. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST, __opus_check_int_ptr(x) + + +/** Gets the size in bytes of the demixing matrix from the encoder. + * @param[out] x opus_int32 *: Returns the size in bytes of the + * demixing matrix. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, __opus_check_int_ptr(x) + + +/** Copies the demixing matrix to the supplied pointer location. + * @param[out] x unsigned char *: Returns the demixing matrix to the + * supplied pointer location. + * @param y opus_int32: The size in bytes of the reserved memory at the + * pointer location. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX(x,y) OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, x, __opus_check_int(y) + + +/**@}*/ + +/** Opus projection encoder state. + * This contains the complete state of a projection Opus encoder. + * It is position independent and can be freely copied. + * @see opus_projection_ambisonics_encoder_create + */ +typedef struct OpusProjectionEncoder OpusProjectionEncoder; + + +/** Opus projection decoder state. + * This contains the complete state of a projection Opus decoder. + * It is position independent and can be freely copied. + * @see opus_projection_decoder_create + * @see opus_projection_decoder_init + */ +typedef struct OpusProjectionDecoder OpusProjectionDecoder; + + +/**\name Projection encoder functions */ +/**@{*/ + +/** Gets the size of an OpusProjectionEncoder structure. + * @param channels int: The total number of input channels to encode. + * This must be no more than 255. + * @param mapping_family int: The mapping family to use for selecting + * the appropriate projection. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_ambisonics_encoder_get_size( + int channels, + int mapping_family +); + + +/** Allocates and initializes a projection encoder state. + * Call opus_projection_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param mapping_family int: The mapping family to use for selecting + * the appropriate projection. + * @param[out] streams int *: The total number of streams that will + * be encoded from the input. + * @param[out] coupled_streams int *: Number of coupled (2 channel) + * streams that will be encoded from the input. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + int application, + int *error +) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5); + + +/** Initialize a previously allocated projection encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_projection_ambisonics_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_projection_ambisonics_encoder_create + * @see opus_projection_ambisonics_encoder_get_size + * @param st OpusProjectionEncoder*: Projection encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_projection_ambisonics_encoder_init( + OpusProjectionEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); + + +/** Encodes a projection Opus frame. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode( + OpusProjectionEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + + +/** Encodes a projection Opus frame from floating point input. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode_float( + OpusProjectionEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + + +/** Frees an OpusProjectionEncoder allocated by + * opus_projection_ambisonics_encoder_create(). + * @param st OpusProjectionEncoder*: Projection encoder state to be freed. + */ +OPUS_EXPORT void opus_projection_encoder_destroy(OpusProjectionEncoder *st); + + +/** Perform a CTL function on a projection Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, @ref opus_multistream_ctls, or + * @ref opus_projection_ctls + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + * @see opus_projection_ctls + */ +OPUS_EXPORT int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + + +/**@}*/ + +/**\name Projection decoder functions */ +/**@{*/ + +/** Gets the size of an OpusProjectionDecoder structure. + * @param channels int: The total number of output channels. + * This must be no more than 255. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_decoder_get_size( + int channels, + int streams, + int coupled_streams +); + + +/** Allocates and initializes a projection decoder state. + * Call opus_projection_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix + * that mapping from coded channels to output channels, + * as described in @ref opus_projection and + * @ref opus_projection_ctls. + * @param demixing_matrix_size opus_int32: The size in bytes of the + * demixing matrix, as + * described in @ref + * opus_projection_ctls. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionDecoder *opus_projection_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *demixing_matrix, + opus_int32 demixing_matrix_size, + int *error +) OPUS_ARG_NONNULL(5); + + +/** Intialize a previously allocated projection decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_projection_decoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_projection_decoder_create + * @see opus_projection_deocder_get_size + * @param st OpusProjectionDecoder*: Projection encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix + * that mapping from coded channels to output channels, + * as described in @ref opus_projection and + * @ref opus_projection_ctls. + * @param demixing_matrix_size opus_int32: The size in bytes of the + * demixing matrix, as + * described in @ref + * opus_projection_ctls. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_projection_decoder_init( + OpusProjectionDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *demixing_matrix, + opus_int32 demixing_matrix_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + + +/** Decode a projection Opus packet. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode( + OpusProjectionDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + + +/** Decode a projection Opus packet with floating point output. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode_float( + OpusProjectionDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + + +/** Perform a CTL function on a projection Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, @ref opus_multistream_ctls, or + * @ref opus_projection_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + * @see opus_projection_ctls + */ +OPUS_EXPORT int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + + +/** Frees an OpusProjectionDecoder allocated by + * opus_projection_decoder_create(). + * @param st OpusProjectionDecoder: Projection decoder state to be freed. + */ +OPUS_EXPORT void opus_projection_decoder_destroy(OpusProjectionDecoder *st); + + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_PROJECTION_H */ diff --git a/native/codec/libraries/opus/include/opus_types.h b/native/codec/libraries/opus/include/opus_types.h new file mode 100644 index 0000000..7cf6755 --- /dev/null +++ b/native/codec/libraries/opus/include/opus_types.h @@ -0,0 +1,166 @@ +/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ +/* Modified by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* opus_types.h based on ogg_types.h from libogg */ + +/** + @file opus_types.h + @brief Opus reference implementation types +*/ +#ifndef OPUS_TYPES_H +#define OPUS_TYPES_H + +#define opus_int int /* used for counters etc; at least 16 bits */ +#define opus_int64 long long +#define opus_int8 signed char + +#define opus_uint unsigned int /* used for counters etc; at least 16 bits */ +#define opus_uint64 unsigned long long +#define opus_uint8 unsigned char + +/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ +#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) +#include +# undef opus_int64 +# undef opus_int8 +# undef opus_uint64 +# undef opus_uint8 + typedef int8_t opus_int8; + typedef uint8_t opus_uint8; + typedef int16_t opus_int16; + typedef uint16_t opus_uint16; + typedef int32_t opus_int32; + typedef uint32_t opus_uint32; + typedef int64_t opus_int64; + typedef uint64_t opus_uint64; +#elif defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t opus_int32; + typedef _G_uint32_t opus_uint32; + typedef _G_int16 opus_int16; + typedef _G_uint16 opus_uint16; +# elif defined(__MINGW32__) + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; +# elif defined(__MWERKS__) + typedef int opus_int32; + typedef unsigned int opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; +# else + /* MSVC/Borland */ + typedef __int32 opus_int32; + typedef unsigned __int32 opus_uint32; + typedef __int16 opus_int16; + typedef unsigned __int16 opus_uint16; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 opus_int16; + typedef UInt16 opus_uint16; + typedef SInt32 opus_int32; + typedef UInt32 opus_uint32; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t opus_int16; + typedef u_int16_t opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16 opus_int16; + typedef u_int16 opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int opus_int32; + typedef unsigned opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short opus_int16; + typedef unsigned short opus_uint16; + typedef signed int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef long opus_int32; + typedef unsigned long opus_uint32; + +#elif defined(CONFIG_TI_C6X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#else + + /* Give up, take a reasonable guess */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#endif + +#endif /* OPUS_TYPES_H */ diff --git a/native/codec/libraries/opus/m4/as-gcc-inline-assembly.m4 b/native/codec/libraries/opus/m4/as-gcc-inline-assembly.m4 new file mode 100644 index 0000000..b0d2da4 --- /dev/null +++ b/native/codec/libraries/opus/m4/as-gcc-inline-assembly.m4 @@ -0,0 +1,98 @@ +dnl as-gcc-inline-assembly.m4 0.1.0 + +dnl autostars m4 macro for detection of gcc inline assembly + +dnl David Schleef + +dnl AS_COMPILER_FLAG(ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_GCC_INLINE_ASSEMBLY], +[ + AC_MSG_CHECKING([if compiler supports gcc-style inline assembly]) + + AC_TRY_COMPILE([], [ +#ifdef __GNUC_MINOR__ +#if (__GNUC__ * 1000 + __GNUC_MINOR__) < 3004 +#error GCC before 3.4 has critical bugs compiling inline assembly +#endif +#endif +__asm__ (""::) ], [flag_ok=yes], [flag_ok=no]) + + if test "X$flag_ok" = Xyes ; then + $1 + true + else + $2 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + +AC_DEFUN([AS_ASM_ARM_NEON], +[ + AC_MSG_CHECKING([if assembler supports NEON instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("vorr d0,d0,d0")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_NEON_FORCE], +[ + AC_MSG_CHECKING([if assembler supports NEON instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv7-a\n.fpu neon\n.object_arch armv4t\nvorr d0,d0,d0")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_MEDIA], +[ + AC_MSG_CHECKING([if assembler supports ARMv6 media instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("shadd8 r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_MEDIA_FORCE], +[ + AC_MSG_CHECKING([if assembler supports ARMv6 media instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv6\n.object_arch armv4t\nshadd8 r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_EDSP], +[ + AC_MSG_CHECKING([if assembler supports EDSP instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("qadd r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_EDSP_FORCE], +[ + AC_MSG_CHECKING([if assembler supports EDSP instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv5te\n.object_arch armv4t\nqadd r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) diff --git a/native/codec/libraries/opus/m4/ax_add_fortify_source.m4 b/native/codec/libraries/opus/m4/ax_add_fortify_source.m4 new file mode 100644 index 0000000..1c89e41 --- /dev/null +++ b/native/codec/libraries/opus/m4/ax_add_fortify_source.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# Modified from https://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_ADD_FORTIFY_SOURCE +# +# DESCRIPTION +# +# Check whether -D_FORTIFY_SOURCE=2 can be added to CFLAGS without macro +# redefinition warnings. Some distributions (such as Gentoo Linux) enable +# _FORTIFY_SOURCE globally in their compilers, leading to unnecessary +# warnings in the form of +# +# :0:0: error: "_FORTIFY_SOURCE" redefined [-Werror] +# : note: this is the location of the previous definition +# +# which is a problem if -Werror is enabled. This macro checks whether +# _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2 +# to CFLAGS. +# +# LICENSE +# +# Copyright (c) 2017 David Seifert +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[ + AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CFLAGS]) + AC_LINK_IFELSE([ + AC_LANG_SOURCE( + [[ + int main() { + #ifndef _FORTIFY_SOURCE + return 0; + #else + this_is_an_error; + #endif + } + ]] + )], [ + AC_MSG_RESULT([yes]) + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" + ], [ + AC_MSG_RESULT([no]) + ]) +]) diff --git a/native/codec/libraries/opus/m4/opus-intrinsics.m4 b/native/codec/libraries/opus/m4/opus-intrinsics.m4 new file mode 100644 index 0000000..a262ca1 --- /dev/null +++ b/native/codec/libraries/opus/m4/opus-intrinsics.m4 @@ -0,0 +1,29 @@ +dnl opus-intrinsics.m4 +dnl macro for testing for support for compiler intrinsics, either by default or with a compiler flag + +dnl OPUS_CHECK_INTRINSICS(NAME-OF-INTRINSICS, COMPILER-FLAG-FOR-INTRINSICS, VAR-IF-PRESENT, VAR-IF-DEFAULT, TEST-PROGRAM-HEADER, TEST-PROGRAM-BODY) +AC_DEFUN([OPUS_CHECK_INTRINSICS], +[ + AC_MSG_CHECKING([if compiler supports $1 intrinsics]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM($5, $6)], + [ + $3=1 + $4=1 + AC_MSG_RESULT([yes]) + ],[ + $4=0 + AC_MSG_RESULT([no]) + AC_MSG_CHECKING([if compiler supports $1 intrinsics with $2]) + save_CFLAGS="$CFLAGS"; CFLAGS="$CFLAGS $2" + AC_LINK_IFELSE([AC_LANG_PROGRAM($5, $6)], + [ + AC_MSG_RESULT([yes]) + $3=1 + ],[ + AC_MSG_RESULT([no]) + $3=0 + ]) + CFLAGS="$save_CFLAGS" + ]) +]) diff --git a/native/codec/libraries/opus/opus-uninstalled.pc.in b/native/codec/libraries/opus/opus-uninstalled.pc.in new file mode 100644 index 0000000..19f5c93 --- /dev/null +++ b/native/codec/libraries/opus/opus-uninstalled.pc.in @@ -0,0 +1,12 @@ +# Opus codec reference implementation uninstalled pkg-config file + +libdir=${pcfiledir}/.libs +includedir=${pcfiledir} + +Name: opus uninstalled +Description: Opus IETF audio codec (not installed, @PC_BUILD@) +Version: @VERSION@ +Requires: +Conflicts: +Libs: ${libdir}/libopus.la @LIBM@ +Cflags: -I${pcfiledir}/@top_srcdir@/include diff --git a/native/codec/libraries/opus/opus.m4 b/native/codec/libraries/opus/opus.m4 new file mode 100644 index 0000000..47f5ec4 --- /dev/null +++ b/native/codec/libraries/opus/opus.m4 @@ -0,0 +1,117 @@ +# Configure paths for libopus +# Gregory Maxwell 08-30-2012 +# Shamelessly stolen from Jack Moffitt (libogg) who +# Shamelessly stole from Owen Taylor and Manish Singh + +dnl XIPH_PATH_OPUS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libopus, and define OPUS_CFLAGS and OPUS_LIBS +dnl +AC_DEFUN([XIPH_PATH_OPUS], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(opus,AC_HELP_STRING([--with-opus=PFX],[Prefix where opus is installed (optional)]), opus_prefix="$withval", opus_prefix="") +AC_ARG_WITH(opus-libraries,AC_HELP_STRING([--with-opus-libraries=DIR],[Directory where the opus library is installed (optional)]), opus_libraries="$withval", opus_libraries="") +AC_ARG_WITH(opus-includes,AC_HELP_STRING([--with-opus-includes=DIR],[Directory where the opus header files are installed (optional)]), opus_includes="$withval", opus_includes="") +AC_ARG_ENABLE(opustest,AC_HELP_STRING([--disable-opustest],[Do not try to compile and run a test opus program]),, enable_opustest=yes) + + if test "x$opus_libraries" != "x" ; then + OPUS_LIBS="-L$opus_libraries" + elif test "x$opus_prefix" = "xno" || test "x$opus_prefix" = "xyes" ; then + OPUS_LIBS="" + elif test "x$opus_prefix" != "x" ; then + OPUS_LIBS="-L$opus_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + OPUS_LIBS="-L$prefix/lib" + fi + + if test "x$opus_prefix" != "xno" ; then + OPUS_LIBS="$OPUS_LIBS -lopus" + fi + + if test "x$opus_includes" != "x" ; then + OPUS_CFLAGS="-I$opus_includes" + elif test "x$opus_prefix" = "xno" || test "x$opus_prefix" = "xyes" ; then + OPUS_CFLAGS="" + elif test "x$opus_prefix" != "x" ; then + OPUS_CFLAGS="-I$opus_prefix/include" + elif test "x$prefix" != "xNONE"; then + OPUS_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for Opus) + if test "x$opus_prefix" = "xno" ; then + no_opus="disabled" + enable_opustest="no" + else + no_opus="" + fi + + + if test "x$enable_opustest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $OPUS_CFLAGS" + LIBS="$LIBS $OPUS_LIBS" +dnl +dnl Now check if the installed Opus is sufficiently new. +dnl + rm -f conf.opustest + AC_TRY_RUN([ +#include +#include +#include +#include + +int main () +{ + system("touch conf.opustest"); + return 0; +} + +],, no_opus=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_opus" = "xdisabled" ; then + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) + elif test "x$no_opus" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.opustest ; then + : + else + echo "*** Could not run Opus test program, checking why..." + CFLAGS="$CFLAGS $OPUS_CFLAGS" + LIBS="$LIBS $OPUS_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Opus or finding the wrong" + echo "*** version of Opus. If it is not finding Opus, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occurred. This usually means Opus was incorrectly installed" + echo "*** or that you have moved Opus since it was installed." ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + OPUS_CFLAGS="" + OPUS_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(OPUS_CFLAGS) + AC_SUBST(OPUS_LIBS) + rm -f conf.opustest +]) diff --git a/native/codec/libraries/opus/opus.pc.in b/native/codec/libraries/opus/opus.pc.in new file mode 100644 index 0000000..6946e7d --- /dev/null +++ b/native/codec/libraries/opus/opus.pc.in @@ -0,0 +1,16 @@ +# Opus codec reference implementation pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Opus +Description: Opus IETF audio codec (@PC_BUILD@ build) +URL: https://opus-codec.org/ +Version: @VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -lopus +Libs.private: @LIBM@ +Cflags: -I${includedir}/opus diff --git a/native/codec/libraries/opus/opus_buildtype.cmake b/native/codec/libraries/opus/opus_buildtype.cmake new file mode 100644 index 0000000..aaee9ef --- /dev/null +++ b/native/codec/libraries/opus/opus_buildtype.cmake @@ -0,0 +1,23 @@ +# Set a default build type if none was specified + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + if(CMAKE_C_FLAGS) + message(STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS}) + else() + set(default_build_type "Release") + message( + STATUS + "Setting build type to '${default_build_type}' as none was specified and no CFLAGS was exported." + ) + set(CMAKE_BUILD_TYPE "${default_build_type}" + CACHE STRING "Choose the type of build." + FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release" + "MinSizeRel" + "RelWithDebInfo") + endif() +endif() diff --git a/native/codec/libraries/opus/opus_config.cmake b/native/codec/libraries/opus/opus_config.cmake new file mode 100644 index 0000000..a0bfd58 --- /dev/null +++ b/native/codec/libraries/opus/opus_config.cmake @@ -0,0 +1,43 @@ +include(opus_functions.cmake) + +configure_file(config.h.cmake.in config.h @ONLY) +add_definitions(-DHAVE_CONFIG_H) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY C_STANDARD 99) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +include(CheckLibraryExists) +check_library_exists(m floor "" HAVE_LIBM) +if(HAVE_LIBM) + list(APPEND OPUS_REQUIRED_LIBRARIES m) +endif() + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(i[0-9]86|x86|X86|amd64|AMD64|x86_64)") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(OPUS_CPU_X64 1) + else() + set(OPUS_CPU_X86 1) + endif() +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") + set(OPUS_CPU_ARM 1) +endif() + +opus_supports_cpu_detection(RUNTIME_CPU_CAPABILITY_DETECTION) + +if(OPUS_CPU_X86 OR OPUS_CPU_X64) + opus_detect_sse(COMPILER_SUPPORT_SIMD) +elseif(OPUS_CPU_ARM) + opus_detect_neon(COMPILER_SUPPORT_NEON) + if(COMPILER_SUPPORT_NEON) + option(OPUS_USE_NEON "Option to turn off SSE" ON) + option(OPUS_MAY_SUPPORT_NEON "Does runtime check for neon support" ON) + option(OPUS_PRESUME_NEON "Assume target CPU has NEON support" OFF) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + set(OPUS_PRESUME_NEON ON) + endif() + endif() +endif() diff --git a/native/codec/libraries/opus/opus_functions.cmake b/native/codec/libraries/opus/opus_functions.cmake new file mode 100644 index 0000000..fe309c2 --- /dev/null +++ b/native/codec/libraries/opus/opus_functions.cmake @@ -0,0 +1,262 @@ +#[[Cmake helper function to parse source files from make files +this is to avoid breaking existing make and auto make support +but still have the option to use CMake with only lists at one place]] + +cmake_minimum_required(VERSION 3.1) + +function(get_library_version OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR) + file(STRINGS configure.ac opus_lt_current_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_CURRENT=") + string(REGEX MATCH + "OPUS_LT_CURRENT=([0-9]*)" + _ + ${opus_lt_current_string}) + set(OPUS_LT_CURRENT ${CMAKE_MATCH_1}) + + file(STRINGS configure.ac opus_lt_revision_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_REVISION=") + string(REGEX MATCH + "OPUS_LT_REVISION=([0-9]*)" + _ + ${opus_lt_revision_string}) + set(OPUS_LT_REVISION ${CMAKE_MATCH_1}) + + file(STRINGS configure.ac opus_lt_age_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_AGE=") + string(REGEX MATCH + "OPUS_LT_AGE=([0-9]*)" + _ + ${opus_lt_age_string}) + set(OPUS_LT_AGE ${CMAKE_MATCH_1}) + + math(EXPR OPUS_LIBRARY_VERSION_MAJOR "${OPUS_LT_CURRENT} - ${OPUS_LT_AGE}") + set(OPUS_LIBRARY_VERSION_MINOR ${OPUS_LT_AGE}) + set(OPUS_LIBRARY_VERSION_PATCH ${OPUS_LT_REVISION}) + set( + OPUS_LIBRARY_VERSION + "${OPUS_LIBRARY_VERSION_MAJOR}.${OPUS_LIBRARY_VERSION_MINOR}.${OPUS_LIBRARY_VERSION_PATCH}" + PARENT_SCOPE) + set(OPUS_LIBRARY_VERSION_MAJOR ${OPUS_LIBRARY_VERSION_MAJOR} PARENT_SCOPE) +endfunction() + +function(get_package_version PACKAGE_VERSION) + find_package(Git) + if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --match "v*" + OUTPUT_VARIABLE OPUS_PACKAGE_VERSION) + if(OPUS_PACKAGE_VERSION) + string(STRIP ${OPUS_PACKAGE_VERSION}, OPUS_PACKAGE_VERSION) + string(REPLACE \n + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + string(REPLACE , + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + + string(SUBSTRING ${OPUS_PACKAGE_VERSION} + 1 + -1 + OPUS_PACKAGE_VERSION) + set(PACKAGE_VERSION ${OPUS_PACKAGE_VERSION} PARENT_SCOPE) + return() + endif() + endif() + + if(EXISTS "${CMAKE_SOURCE_DIR}/package_version") + # Not a git repo, lets' try to parse it from package_version file if exists + file(STRINGS package_version opus_package_version_string + LIMIT_COUNT 1 + REGEX "PACKAGE_VERSION=") + string(REPLACE "PACKAGE_VERSION=" + "" + opus_package_version_string + ${opus_package_version_string}) + string(REPLACE "\"" + "" + opus_package_version_string + ${opus_package_version_string}) + set(PACKAGE_VERSION ${opus_package_version_string} PARENT_SCOPE) + return() + endif() + + # if all else fails set to 0 + set(PACKAGE_VERSION 0 PARENT_SCOPE) +endfunction() + +function(check_and_set_flag NAME FLAG) + include(CheckCCompilerFlag) + check_c_compiler_flag(${FLAG} ${NAME}_SUPPORTED) + if(${NAME}_SUPPORTED) + add_definitions(${FLAG}) + endif() +endfunction() + +function(check_flag NAME FLAG) + include(CheckCCompilerFlag) + check_c_compiler_flag(${FLAG} ${NAME}_SUPPORTED) +endfunction() + +include(CheckIncludeFile) +# function to check if compiler supports SSE, SSE2, SSE4.1 and AVX if target +# systems may not have SSE support then use OPUS_MAY_HAVE_SSE option if target +# system is guaranteed to have SSE support then OPUS_PRESUME_SSE can be used to +# skip SSE runtime check +function(opus_detect_sse COMPILER_SUPPORT_SIMD) + message(STATUS "Check SIMD support by compiler") + check_include_file(xmmintrin.h HAVE_XMMINTRIN_H) # SSE1 + if(HAVE_XMMINTRIN_H) + if(MSVC) + # different arch options for 32 and 64 bit target for MSVC + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE1 /arch:SSE) + else() + set(SSE1_SUPPORTED 1 PARENT_SCOPE) + endif() + else() + check_and_set_flag(SSE1 -msse) + endif() + else() + set(SSE1_SUPPORTED 0 PARENT_SCOPE) + endif() + + check_include_file(emmintrin.h HAVE_EMMINTRIN_H) # SSE2 + if(HAVE_EMMINTRIN_H) + if(MSVC) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE2 /arch:SSE2) + else() + set(SSE2_SUPPORTED 1 PARENT_SCOPE) + endif() + else() + check_and_set_flag(SSE2 -msse2) + endif() + else() + set(SSE2_SUPPORTED 0 PARENT_SCOPE) + endif() + + check_include_file(smmintrin.h HAVE_SMMINTRIN_H) # SSE4.1 + if(HAVE_SMMINTRIN_H) + if(MSVC) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE4_1 /arch:SSE2) # SSE2 and above + else() + set(SSE4_1_SUPPORTED 1 PARENT_SCOPE) + endif() + else() + check_and_set_flag(SSE4_1 -msse4.1) + endif() + else() + set(SSE4_1_SUPPORTED 0 PARENT_SCOPE) + endif() + + check_include_file(immintrin.h HAVE_IMMINTRIN_H) # AVX + if(HAVE_IMMINTRIN_H) + if(MSVC) + check_flag(AVX /arch:AVX) + else() + check_and_set_flag(AVX -mavx) + endif() + else() + set(AVX_SUPPORTED 0 PARENT_SCOPE) + endif() + + if(MSVC) # To avoid warning D9025 of overriding compiler options + if(AVX_SUPPORTED) # on 64 bit and 32 bits + add_definitions(/arch:AVX) + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) # if AVX not supported then set SSE flag + if(SSE4_1_SUPPORTED OR SSE2_SUPPORTED) + add_definitions(/arch:SSE2) + elseif(SSE1_SUPPORTED) + add_definitions(/arch:SSE) + endif() + endif() + endif() + + if(SSE1_SUPPORTED OR SSE2_SUPPORTED OR SSE4_1_SUPPORTED OR AVX_SUPPORTED) + set(COMPILER_SUPPORT_SIMD 1 PARENT_SCOPE) + else() + message(STATUS "No SIMD support in compiler") + endif() +endfunction() + +function(opus_detect_neon COMPILER_SUPPORT_NEON) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "(armv7-a|aarch64)") + message(STATUS "Check NEON support by compiler") + check_include_file(arm_neon.h HAVE_ARM_NEON_H) + if(HAVE_ARM_NEON_H) + set(COMPILER_SUPPORT_NEON ${HAVE_ARM_NEON_H} PARENT_SCOPE) + endif() + endif() +endfunction() + +function(opus_supports_cpu_detection RUNTIME_CPU_CAPABILITY_DETECTION) + if(MSVC) + check_include_file(intrin.h HAVE_INTRIN_H) + else() + check_include_file(cpuid.h HAVE_CPUID_H) + endif() + if(HAVE_INTRIN_H OR HAVE_CPUID_H) + set(RUNTIME_CPU_CAPABILITY_DETECTION 1 PARENT_SCOPE) + else() + set(RUNTIME_CPU_CAPABILITY_DETECTION 0 PARENT_SCOPE) + endif() +endfunction() + +function(add_sources_group target group) + target_sources(${target} PRIVATE ${ARGN}) + source_group(${group} FILES ${ARGN}) +endfunction() + +function(get_opus_sources SOURCE_GROUP MAKE_FILE SOURCES) + # read file, each item in list is one group + file(STRINGS ${MAKE_FILE} opus_sources) + + # add wildcard for regex match + string(CONCAT SOURCE_GROUP ${SOURCE_GROUP} ".*$") + + # find group + foreach(val IN LISTS opus_sources) + if(val MATCHES ${SOURCE_GROUP}) + list(LENGTH val list_length) + if(${list_length} EQUAL 1) + # for tests split by '=' and clean up the rest into a list + string(FIND ${val} "=" index) + math(EXPR index "${index} + 1") + string(SUBSTRING ${val} + ${index} + -1 + sources) + string(REPLACE " " + ";" + sources + ${sources}) + else() + # discard the group + list(REMOVE_AT val 0) + set(sources ${val}) + endif() + break() + endif() + endforeach() + + list(LENGTH sources list_length) + if(${list_length} LESS 1) + message( + FATAL_ERROR + "No files parsed succesfully from ${SOURCE_GROUP} in ${MAKE_FILE}") + endif() + + # remove trailing whitespaces + set(list_var "") + foreach(source ${sources}) + string(STRIP "${source}" source) + list(APPEND list_var "${source}") + endforeach() + + set(${SOURCES} ${list_var} PARENT_SCOPE) +endfunction() diff --git a/native/codec/libraries/opus/opus_headers.mk b/native/codec/libraries/opus/opus_headers.mk new file mode 100644 index 0000000..27596f2 --- /dev/null +++ b/native/codec/libraries/opus/opus_headers.mk @@ -0,0 +1,9 @@ +OPUS_HEAD = \ +include/opus.h \ +include/opus_multistream.h \ +include/opus_projection.h \ +src/opus_private.h \ +src/analysis.h \ +src/mapping_matrix.h \ +src/mlp.h \ +src/tansig_table.h diff --git a/native/codec/libraries/opus/opus_sources.cmake b/native/codec/libraries/opus/opus_sources.cmake new file mode 100644 index 0000000..225543a --- /dev/null +++ b/native/codec/libraries/opus/opus_sources.cmake @@ -0,0 +1,38 @@ +include(opus_functions.cmake) + +get_opus_sources(SILK_SOURCES silk_sources.mk silk_sources) +get_opus_sources(SILK_SOURCES_FLOAT silk_sources.mk silk_sources_float) +get_opus_sources(SILK_SOURCES_FIXED silk_sources.mk silk_sources_fixed) +get_opus_sources(SILK_SOURCES_SSE4_1 silk_sources.mk silk_sources_sse4_1) +get_opus_sources(SILK_SOURCES_FIXED_SSE4_1 silk_sources.mk + silk_sources_fixed_sse4_1) +get_opus_sources(SILK_SOURCES_ARM_NEON_INTR silk_sources.mk + silk_sources_arm_neon_intr) +get_opus_sources(SILK_SOURCES_FIXED_ARM_NEON_INTR silk_sources.mk + silk_sources_fixed_arm_neon_intr) + +get_opus_sources(OPUS_SOURCES opus_sources.mk opus_sources) +get_opus_sources(OPUS_SOURCES_FLOAT opus_sources.mk opus_sources_float) + +get_opus_sources(CELT_SOURCES celt_sources.mk celt_sources) +get_opus_sources(CELT_SOURCES_SSE celt_sources.mk celt_sources_sse) +get_opus_sources(CELT_SOURCES_SSE2 celt_sources.mk celt_sources_sse2) +get_opus_sources(CELT_SOURCES_SSE4_1 celt_sources.mk celt_sources_sse4_1) +get_opus_sources(CELT_SOURCES_ARM celt_sources.mk celt_sources_arm) +get_opus_sources(CELT_SOURCES_ARM_ASM celt_sources.mk celt_sources_arm_asm) +get_opus_sources(CELT_AM_SOURCES_ARM_ASM celt_sources.mk + celt_am_sources_arm_asm) +get_opus_sources(CELT_SOURCES_ARM_NEON_INTR celt_sources.mk + celt_sources_arm_neon_intr) +get_opus_sources(CELT_SOURCES_ARM_NE10 celt_sources.mk celt_sources_arm_ne10) + +get_opus_sources(opus_demo_SOURCES Makefile.am opus_demo_sources) +get_opus_sources(opus_custom_demo_SOURCES Makefile.am opus_custom_demo_sources) +get_opus_sources(opus_compare_SOURCES Makefile.am opus_compare_sources) +get_opus_sources(tests_test_opus_api_SOURCES Makefile.am test_opus_api_sources) +get_opus_sources(tests_test_opus_encode_SOURCES Makefile.am + test_opus_encode_sources) +get_opus_sources(tests_test_opus_decode_SOURCES Makefile.am + test_opus_decode_sources) +get_opus_sources(tests_test_opus_padding_SOURCES Makefile.am + test_opus_padding_sources) diff --git a/native/codec/libraries/opus/opus_sources.mk b/native/codec/libraries/opus/opus_sources.mk new file mode 100644 index 0000000..44153b5 --- /dev/null +++ b/native/codec/libraries/opus/opus_sources.mk @@ -0,0 +1,16 @@ +OPUS_SOURCES = \ +src/opus.c \ +src/opus_decoder.c \ +src/opus_encoder.c \ +src/opus_multistream.c \ +src/opus_multistream_encoder.c \ +src/opus_multistream_decoder.c \ +src/repacketizer.c \ +src/opus_projection_encoder.c \ +src/opus_projection_decoder.c \ +src/mapping_matrix.c + +OPUS_SOURCES_FLOAT = \ +src/analysis.c \ +src/mlp.c \ +src/mlp_data.c diff --git a/native/codec/libraries/opus/releases.sha2 b/native/codec/libraries/opus/releases.sha2 new file mode 100644 index 0000000..334976b --- /dev/null +++ b/native/codec/libraries/opus/releases.sha2 @@ -0,0 +1,79 @@ +b2f75c4ac5ab837845eb028413fae2a28754bfb0a6d76416e2af1441ef447649 opus-0.9.0.tar.gz +4e379a98ba95bbbfe9087ef10fdd05c8ac9060b6d695f587ea82a7b43a0df4fe opus-0.9.10.tar.gz +b1cad6846a8f819a141009fe3f8f10c946e8eff7e9c2339cd517bb136cc59eae opus-0.9.14.tar.gz +206221afc47b87496588013bd4523e1e9f556336c0813f4372773fc536dd4293 opus-0.9.1.tar.gz +6e85c1b57e1d7b7dfe2928bf92586b96b73a9067e054ede45bd8e6d24bd30582 opus-0.9.2.tar.gz +d916e34c18a396eb7dffc47af754f441af52a290b761e20db9aedb65928c699e opus-0.9.3.tar.gz +53801066fa97329768e7b871fd1495740269ec46802e1c9051aa7e78c6edee5b opus-0.9.5.tar.gz +3bfaeb25f4b4a625a0bc994d6fc6f6776a05193f60099e0a99f7530c6b256309 opus-0.9.6.tar.gz +1b69772c31c5cbaa43d1dfa5b1c495fc29712e8e0ff69d6f8ad46459e5c6715f opus-0.9.7.tar.gz +4aa30d2e0652ffb4a7a22cc8a29c4ce78267626f560a2d9213b1d2d4e618cf36 opus-0.9.8.tar.gz +2f62359f09151fa3b242040dc9b4c5b6bda15557c5daea59c8420f1a2ff328b7 opus-0.9.9.tar.gz +43bcea51afa531f32a6a5fdd9cba4bd496993e26a141217db3cccce6caa7cd74 opus-1.0.0-rc.tar.gz +9250fcc74472d45c1e14745542ec9c8d09982538aefed56962495614be3e0d2d opus-1.0.0.tar.gz +76bc0a31502a51dae9ab737b4db043b9ecfcd0b5861f0bfda41b662bd5b92227 opus-1.0.1-rc2.tar.gz +3de8d6809dac38971ebb305532d4ea532519d3bed08985f25d6c557f9ce5e8ff opus-1.0.1-rc3.tar.gz +8044397a6365a07117b08cbe8f9818bf7c93746908806ba74a2917187bbdda5f opus-1.0.1-rc.tar.gz +80fa5c3caf2ac0fd68f8a22cce1564fc46b368c773a17554887d0066fe1841ef opus-1.0.1.tar.gz +da615edbee5d019c1833071d69a4782c19f178cf9ca1401375036ecef25cd78a opus-1.0.2.tar.gz +191a089c92dbc403de6980463dd3604b65beb12d283c607e246c8076363cb49c opus-1.0.3.tar.gz +a8d40efe87f6c3e76725391457d46277878c7a816ae1642843261463133fa5c8 opus-1.1-alpha.tar.gz +ec1784287f385aef994b64734aaecae04860e61aa50fc6eef6643fa7e40dd193 opus-1.1-beta.tar.gz +8aa16360f59a94d3e38f38f28d24039f7663179682cbae82aa42f1dd9e52e6ed opus-1.1-rc.tar.gz +ebc87a086d4fe677c5e42d56888b1fd25af858e4179eae4f8656270410dffac3 opus-1.1-rc2.tar.gz +cbfd09c58cc10a4d3fcb727ad5d46d7bb549f8185ac922ee28b4581b52a7bee9 opus-1.1-rc3.tar.gz +b9727015a58affcf3db527322bf8c4d2fcf39f5f6b8f15dbceca20206cbe1d95 opus-1.1.tar.gz +0c668639dcd16b14709fc9dc49e6686606f5a256f2eaa1ebaa2f39a66f8626cd opus-1.1.1-beta.tar.gz +66f2a5877c8803dc9a5a44b4f3d0bdc8f06bd066324222d144eb255612b68152 opus-1.1.1-rc.tar.gz +9b84ff56bd7720d5554103c557664efac2b8b18acc4bbcc234cb881ab9a3371e opus-1.1.1.tar.gz +0e290078e31211baa7b5886bcc8ab6bc048b9fc83882532da4a1a45e58e907fd opus-1.1.2.tar.gz +58b6fe802e7e30182e95d0cde890c0ace40b6f125cffc50635f0ad2eef69b633 opus-1.1.3.tar.gz +9122b6b380081dd2665189f97bfd777f04f92dc3ab6698eea1dbb27ad59d8692 opus-1.1.4.tar.gz +eb84981ca0f40a3e5d5e58d2e8582cb2fee05a022825a6dfe14d14b04eb563e4 opus-1.1.5.tar.gz +654a9bebb73266271a28edcfff431e4cfd9bfcde71f42849a0cdd73bece803a7 opus-1.2-alpha.tar.gz +c0e90507259cf21ce7b2c82fb9ac55367d8543dae91cc3d4d2c59afd37f44023 opus-1.2-alpha2.tar.gz +291e979a8a2fb679ed35a5dff5d761a9d9a5e22586fd07934ed94461e2636c7a opus-1.2-beta.tar.gz +85343fdaed96529d94c1e1f3a210fa51240d04ca62fa01e97ef02f88020c2ce9 opus-1.2-rc1.tar.gz +77db45a87b51578fbc49555ef1b10926179861d854eb2613207dc79d9ec0a9a9 opus-1.2.tar.gz +cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732 opus-1.2.1.tar.gz +7f56e058c9549d03ae35511ad9e16ef6d1eb257836830d54abff0f495f17e187 opus-1.3-beta.tar.gz +96fa28598e8ccd558b297277ad59a045c551ba0e06d65a9675938e084f837669 opus-1.3-rc.tar.gz +f6bab321fb81db984766f1e4d340a9e71a5ca2c5d4d53f4ee072e84afda271ca opus-1.3-rc2.tar.gz +4f3d69aefdf2dbaf9825408e452a8a414ffc60494c70633560700398820dc550 opus-1.3.tar.gz +65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d opus-1.3.1.tar.gz +94ac78ca4f74c4e43bc9fe4ec1ad0aa36f38ab90f45b0727c40dd1e96096e767 opus_testvectors-draft11.tar.gz +94ac78ca4f74c4e43bc9fe4ec1ad0aa36f38ab90f45b0727c40dd1e96096e767 opus_testvectors.tar.gz +6b26a22f9ba87b2b836906a9bb7afec5f8e54d49553b1200382520ee6fedfa55 opus_testvectors-rfc8251.tar.gz +5d2b99757bcb628bab2611f3ed27af6f35276ce3abc96c0ed4399d6c6463dda5 opus-tools-0.1.2.tar.gz +008317297d6ce84f84992abf8cc948a048a4fa135e1d1caf429fafde8965a792 opus-tools-0.1.3.tar.gz +de80485c5afa1fd83c0e16a0dd4860470c872997a7dd0a58e99b2ee8a93e5168 opus-tools-0.1.4.tar.gz +76678d0eb7a9b3d793bd0243f9ced9ab0ecdab263f5232ed940c8f5795fb0405 opus-tools-0.1.5.tar.gz +cc86dbc2a4d76da7e1ed9afee85448c8f798c465a5412233f178783220f3a2c1 opus-tools-0.1.6.tar.gz +e0f08d301555dffc417604269b5a85d2bd197f259c7d6c957f370ffd33d6d9cd opus-tools-0.1.7.tar.gz +e4e188579ea1c4e4d5066460d4a7214a7eafe3539e9a4466fdc98af41ba4a2f6 opus-tools-0.1.8.tar.gz +b1873dd78c7fbc98cf65d6e10cfddb5c2c03b3af93f922139a2104baedb4643a opus-tools-0.1.9.tar.gz +a2357532d19471b70666e0e0ec17d514246d8b3cb2eb168f68bb0f6fd372b28c opus-tools-0.1.10.tar.gz +b4e56cb00d3e509acfba9a9b627ffd8273b876b4e2408642259f6da28fa0ff86 opus-tools-0.2.tar.gz +bd6d14e8897a2f80065ef34a516c70e74f8e00060abdbc238e79e5f99bca3e96 libopusenc-0.1.tar.gz +02e6e0b14cbbe0569d948a46420f9c9a81d93bba32dc576a4007cbf96da68ef3 libopusenc-0.1.1.tar.gz +c79e95eeee43a0b965e9b2c59a243763a8f8b0a7e71441df2aa9084f6171c73a libopusenc-0.2.tar.gz +8298db61a8d3d63e41c1a80705baa8ce9ff3f50452ea7ec1c19a564fe106cbb9 libopusenc-0.2.1.tar.gz +8071b968475c1a17f54b6840d6de9d9ee20f930e827b0401abe3c4cf4f3bf30a opusfile-0.1.tar.gz +b4a678b3b6c4adfb6aff1f67ef658becfe146ea7c7ff228e99543762171557f9 opusfile-0.2.tar.gz +4248927f2c4e316ea5b84fb02bd100bfec8fa4624a6910d77f0af7f0c6cb8baa opusfile-0.3.tar.gz +9836ea11706c44f36de92c4c9b1248e03a4c521e7fb2cff18a0cb4f8b0e79140 opusfile-0.4.tar.gz +f187906b1b35f7f0d7de6a759b4aab512a9279d23adb35d8009e7e33bd6a922a opusfile-0.4.zip +2ce52d006aeeec9f10260dbe3073c4636954a1ab19c82b8baafefe0180aa4a39 opusfile-0.5.tar.gz +b940d62beb15b5974764574b9f265481fe5b6ee16902fb705727546caf956261 opusfile-0.5.zip +2428717b356e139f18ed2fdb5ad990b5654a238907a0058200b39c46a7d03ea6 opusfile-0.6.tar.gz +753339225193df605372944889023b9b3c5378d672e8784d69fa241cd465278c opusfile-0.6.zip +9e2bed13bc729058591a0f1cab2505e8cfd8e7ac460bf10a78bcc3b125e7c301 opusfile-0.7.tar.gz +346967d7989bb83b05949483b76bd0f69a12c59bd8b4457e864902b52bb0ac34 opusfile-0.7.zip +2c231ed3cfaa1b3173f52d740e5bbd77d51b9dfecb87014b404917fba4b855a4 opusfile-0.8.tar.gz +89dff4342c3b789574cbea5c57f11b96d4ebe4d28ab90248c1783ea569b1e9e3 opusfile-0.8.zip +f75fb500e40b122775ac1a71ad80c4477698842a8fe9da4a1b4a1a9f16e4e979 opusfile-0.9.tar.gz +e9591da4d4c9e857436c2d46a28a9e470fa5355ea5a76d4d582f137d18755d36 opusfile-0.9.zip +48e03526ba87ef9cf5f1c47b5ebe3aa195bd89b912a57060c36184a6cd19412f opusfile-0.10.tar.gz +9d9e95d01817ecf48bf6daaea8f071f9b45bd1751ca1fc8ce50e5075eb2bc3c8 opusfile-0.10.zip +74ce9b6cf4da103133e7b5c95df810ceb7195471e1162ed57af415fabf5603bf opusfile-0.11.tar.gz +23c5168026c4f1fc34843650135b409d0fc8cf452508163b4ece8077256ac6ff opusfile-0.11.zip diff --git a/native/codec/libraries/opus/scripts/dump_rnn.py b/native/codec/libraries/opus/scripts/dump_rnn.py new file mode 100755 index 0000000..dd66403 --- /dev/null +++ b/native/codec/libraries/opus/scripts/dump_rnn.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.models import load_model +from keras import backend as K + +import numpy as np + +def printVector(f, vector, name): + v = np.reshape(vector, (-1)); + #print('static const float ', name, '[', len(v), '] = \n', file=f) + f.write('static const opus_int16 {}[{}] = {{\n '.format(name, len(v))) + for i in range(0, len(v)): + f.write('{}'.format(int(round(8192*v[i])))) + if (i!=len(v)-1): + f.write(',') + else: + break; + if (i%8==7): + f.write("\n ") + else: + f.write(" ") + #print(v, file=f) + f.write('\n};\n\n') + return; + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + + +model = load_model("weights.hdf5", custom_objects={'binary_crossentrop2': binary_crossentrop2}) + +weights = model.get_weights() + +f = open('rnn_weights.c', 'w') + +f.write('/*This file is automatically generated from a Keras model*/\n\n') +f.write('#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n#include "mlp.h"\n\n') + +printVector(f, weights[0], 'layer0_weights') +printVector(f, weights[1], 'layer0_bias') +printVector(f, weights[2], 'layer1_weights') +printVector(f, weights[3], 'layer1_recur_weights') +printVector(f, weights[4], 'layer1_bias') +printVector(f, weights[5], 'layer2_weights') +printVector(f, weights[6], 'layer2_bias') + +f.write('const DenseLayer layer0 = {\n layer0_bias,\n layer0_weights,\n 25, 16, 0\n};\n\n') +f.write('const GRULayer layer1 = {\n layer1_bias,\n layer1_weights,\n layer1_recur_weights,\n 16, 12\n};\n\n') +f.write('const DenseLayer layer2 = {\n layer2_bias,\n layer2_weights,\n 12, 2, 1\n};\n\n') + +f.close() diff --git a/native/codec/libraries/opus/scripts/rnn_train.py b/native/codec/libraries/opus/scripts/rnn_train.py new file mode 100755 index 0000000..ffdaa1e --- /dev/null +++ b/native/codec/libraries/opus/scripts/rnn_train.py @@ -0,0 +1,67 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.layers import SimpleRNN +from keras.layers import Dropout +from keras import losses +import h5py + +from keras import backend as K +import numpy as np + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + +print('Build model...') +#model = Sequential() +#model.add(Dense(16, activation='tanh', input_shape=(None, 25))) +#model.add(GRU(12, dropout=0.0, recurrent_dropout=0.0, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)) +#model.add(Dense(2, activation='sigmoid')) + +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(16, activation='tanh')(main_input) +x = GRU(12, dropout=0.1, recurrent_dropout=0.1, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x) +x = Dense(2, activation='sigmoid')(x) +model = Model(inputs=main_input, outputs=x) + +batch_size = 64 + +print('Loading data...') +with h5py.File('features.h5', 'r') as hf: + all_data = hf['features'][:] +print('done.') + +window_size = 1500 + +nb_sequences = len(all_data)/window_size +print(nb_sequences, ' sequences') +x_train = all_data[:nb_sequences*window_size, :-2] +x_train = np.reshape(x_train, (nb_sequences, window_size, 25)) + +y_train = np.copy(all_data[:nb_sequences*window_size, -2:]) +y_train = np.reshape(y_train, (nb_sequences, window_size, 2)) + +all_data = 0; +x_train = x_train.astype('float32') +y_train = y_train.astype('float32') + +print(len(x_train), 'train sequences. x shape =', x_train.shape, 'y shape = ', y_train.shape) + +# try using different optimizers and different optimizer configs +model.compile(loss=binary_crossentrop2, + optimizer='adam', + metrics=['binary_accuracy']) + +print('Train...') +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=200, + validation_data=(x_train, y_train)) +model.save("newweights.hdf5") diff --git a/native/codec/libraries/opus/silk/A2NLSF.c b/native/codec/libraries/opus/silk/A2NLSF.c new file mode 100644 index 0000000..b487686 --- /dev/null +++ b/native/codec/libraries/opus/silk/A2NLSF.c @@ -0,0 +1,267 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* Conversion between prediction filter coefficients and NLSFs */ +/* Requires the order to be an even number */ +/* A piecewise linear approximation maps LSF <-> cos(LSF) */ +/* Therefore the result is not accurate NLSFs, but the two */ +/* functions are accurate inverses of each other */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "tables.h" + +/* Number of binary divisions, when not in low complexity mode */ +#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ +#define MAX_ITERATIONS_A2NLSF_FIX 16 + +/* Helper function for A2NLSF(..) */ +/* Transforms polynomials from cos(n*f) to cos(f)^n */ +static OPUS_INLINE void silk_A2NLSF_trans_poly( + opus_int32 *p, /* I/O Polynomial */ + const opus_int dd /* I Polynomial order (= filter order / 2 ) */ +) +{ + opus_int k, n; + + for( k = 2; k <= dd; k++ ) { + for( n = dd; n > k; n-- ) { + p[ n - 2 ] -= p[ n ]; + } + p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 ); + } +} +/* Helper function for A2NLSF(..) */ +/* Polynomial evaluation */ +static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */ + opus_int32 *p, /* I Polynomial, Q16 */ + const opus_int32 x, /* I Evaluation point, Q12 */ + const opus_int dd /* I Order */ +) +{ + opus_int n; + opus_int32 x_Q16, y32; + + y32 = p[ dd ]; /* Q16 */ + x_Q16 = silk_LSHIFT( x, 4 ); + + if ( opus_likely( 8 == dd ) ) + { + y32 = silk_SMLAWW( p[ 7 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 6 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 5 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 4 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 3 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 2 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 1 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 0 ], y32, x_Q16 ); + } + else + { + for( n = dd - 1; n >= 0; n-- ) { + y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */ + } + } + return y32; +} + +static OPUS_INLINE void silk_A2NLSF_init( + const opus_int32 *a_Q16, + opus_int32 *P, + opus_int32 *Q, + const opus_int dd +) +{ + opus_int k; + + /* Convert filter coefs to even and odd polynomials */ + P[dd] = silk_LSHIFT( 1, 16 ); + Q[dd] = silk_LSHIFT( 1, 16 ); + for( k = 0; k < dd; k++ ) { + P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */ + Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */ + } + + /* Divide out zeros as we have that for even filter orders, */ + /* z = 1 is always a root in Q, and */ + /* z = -1 is always a root in P */ + for( k = dd; k > 0; k-- ) { + P[ k - 1 ] -= P[ k ]; + Q[ k - 1 ] += Q[ k ]; + } + + /* Transform polynomials from cos(n*f) to cos(f)^n */ + silk_A2NLSF_trans_poly( P, dd ); + silk_A2NLSF_trans_poly( Q, dd ); +} + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +) +{ + opus_int i, k, m, dd, root_ix, ffrac; + opus_int32 xlo, xhi, xmid; + opus_int32 ylo, yhi, ymid, thr; + opus_int32 nom, den; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 *PQ[ 2 ]; + opus_int32 *p; + + /* Store pointers to array */ + PQ[ 0 ] = P; + PQ[ 1 ] = Q; + + dd = silk_RSHIFT( d, 1 ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + + /* Find roots, alternating between P and Q */ + p = P; /* Pointer to polynomial */ + + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Loop counter */ + i = 0; /* Counter for bandwidth expansions applied */ + thr = 0; + while( 1 ) { + /* Evaluate polynomial */ + xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */ + yhi = silk_A2NLSF_eval_poly( p, xhi, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) { + if( yhi == 0 ) { + /* If the root lies exactly at the end of the current */ + /* interval, look for the next root in the next interval */ + thr = 1; + } else { + thr = 0; + } + /* Binary division */ + ffrac = -256; + for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) { + /* Evaluate polynomial */ + xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 ); + ymid = silk_A2NLSF_eval_poly( p, xmid, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) { + /* Reduce frequency */ + xhi = xmid; + yhi = ymid; + } else { + /* Increase frequency */ + xlo = xmid; + ylo = ymid; + ffrac = silk_ADD_RSHIFT( ffrac, 128, m ); + } + } + + /* Interpolate */ + if( silk_abs( ylo ) < 65536 ) { + /* Avoid dividing by zero */ + den = ylo - yhi; + nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 ); + if( den != 0 ) { + ffrac += silk_DIV32( nom, den ); + } + } else { + /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */ + ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) ); + } + NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX ); + + silk_assert( NLSF[ root_ix ] >= 0 ); + + root_ix++; /* Next root */ + if( root_ix >= d ) { + /* Found all roots */ + break; + } + /* Alternate pointer to polynomial */ + p = PQ[ root_ix & 1 ]; + + /* Evaluate polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/ + ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 ); + } else { + /* Increment loop counter */ + k++; + xlo = xhi; + ylo = yhi; + thr = 0; + + if( k > LSF_COS_TAB_SZ_FIX ) { + i++; + if( i > MAX_ITERATIONS_A2NLSF_FIX ) { + /* Set NLSFs to white spectrum and exit */ + NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 ); + for( k = 1; k < d; k++ ) { + NLSF[ k ] = (opus_int16)silk_ADD16( NLSF[ k-1 ], NLSF[ 0 ] ); + } + return; + } + + /* Error: Apply progressively more bandwidth expansion and run again */ + silk_bwexpander_32( a_Q16, d, 65536 - silk_LSHIFT( 1, i ) ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + p = P; /* Pointer to polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Reset loop counter */ + } + } + } +} diff --git a/native/codec/libraries/opus/silk/API.h b/native/codec/libraries/opus/silk/API.h new file mode 100644 index 0000000..4d90ff9 --- /dev/null +++ b/native/codec/libraries/opus/silk/API.h @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_API_H +#define SILK_API_H + +#include "control.h" +#include "typedef.h" +#include "errors.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SILK_MAX_FRAMES_PER_PACKET 3 + +/* Struct for TOC (Table of Contents) */ +typedef struct { + opus_int VADFlag; /* Voice activity for packet */ + opus_int VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet */ + opus_int inbandFECFlag; /* Flag indicating if packet contains in-band FEC */ +} silk_TOC_struct; + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk encoder state */ +/***********************************************/ +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +); + +/*************************/ +/* Init or reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + int arch, /* I Run-time architecture */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + int activity /* I Decision of Opus voice activity detector */ +); + +/****************************************/ +/* Decoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk decoder state */ +/***********************************************/ +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +); + +/*************************/ +/* Init or Reset decoder */ +/*************************/ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +); + +/******************/ +/* Decode a frame */ +/******************/ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut, /* O Number of samples decoded */ + int arch /* I Run-time architecture */ +); + +#if 0 +/**************************************/ +/* Get table of contents for a packet */ +/**************************************/ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/CNG.c b/native/codec/libraries/opus/silk/CNG.c new file mode 100644 index 0000000..ef8e38d --- /dev/null +++ b/native/codec/libraries/opus/silk/CNG.c @@ -0,0 +1,184 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Generates excitation for CNG LPC synthesis */ +static OPUS_INLINE void silk_CNG_exc( + opus_int32 exc_Q14[], /* O CNG excitation signal Q10 */ + opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */ + opus_int length, /* I Length */ + opus_int32 *rand_seed /* I/O Seed to random index generator */ +) +{ + opus_int32 seed; + opus_int i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while( exc_mask > length ) { + exc_mask = silk_RSHIFT( exc_mask, 1 ); + } + + seed = *rand_seed; + for( i = 0; i < length; i++ ) { + seed = silk_RAND( seed ); + idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask ); + silk_assert( idx >= 0 ); + silk_assert( idx <= CNG_BUF_MASK_MAX ); + exc_Q14[ i ] = exc_buf_Q14[ idx ]; + } + *rand_seed = seed; +} + +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + opus_int i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 ); + NLSF_acc_Q15 = 0; + for( i = 0; i < psDec->LPC_order; i++ ) { + NLSF_acc_Q15 += NLSF_step_Q15; + psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15; + } + psDec->sCNG.CNG_smth_Gain_Q16 = 0; + psDec->sCNG.rand_seed = 3176576; +} + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +) +{ + opus_int i, subfr; + opus_int32 LPC_pred_Q10, max_Gain_Q16, gain_Q16, gain_Q10; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; + silk_CNG_struct *psCNG = &psDec->sCNG; + SAVE_STACK; + + if( psDec->fs_kHz != psCNG->fs_kHz ) { + /* Reset state */ + silk_CNG_Reset( psDec ); + + psCNG->fs_kHz = psDec->fs_kHz; + } + if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for( i = 0; i < psDec->LPC_order; i++ ) { + psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 ); + } + /* Find the subframe with the highest gain */ + max_Gain_Q16 = 0; + subfr = 0; + for( i = 0; i < psDec->nb_subfr; i++ ) { + if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) { + max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + subfr = i; + } + } + /* Update CNG excitation buffer with excitation from this subframe */ + silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) ); + silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) ); + + /* Smooth gains */ + for( i = 0; i < psDec->nb_subfr; i++ ) { + psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + } + } + + /* Add CNG when packet is lost or during DTX */ + if( psDec->lossCnt ) { + VARDECL( opus_int32, CNG_sig_Q14 ); + ALLOC( CNG_sig_Q14, length + MAX_LPC_ORDER, opus_int32 ); + + /* Generate CNG excitation */ + gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] ); + if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) { + gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 ); + } else { + gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 ); + } + gain_Q10 = silk_RSHIFT( gain_Q16, 6 ); + + silk_CNG_exc( CNG_sig_Q14 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed ); + + /* Convert CNG NLSF to filter representation */ + silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order, psDec->arch ); + + /* Generate CNG signal, by synthesis filtering */ + silk_memcpy( CNG_sig_Q14, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + for( i = 0; i < length; i++ ) { + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] ); + } + + /* Update states */ + CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( CNG_sig_Q14[ MAX_LPC_ORDER + i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) ); + + /* Scale with Gain and add to input signal */ + frame[ i ] = (opus_int16)silk_ADD_SAT16( frame[ i ], silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( CNG_sig_Q14[ MAX_LPC_ORDER + i ], gain_Q10 ), 8 ) ) ); + + } + silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q14[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + } else { + silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/HP_variable_cutoff.c b/native/codec/libraries/opus/silk/HP_variable_cutoff.c new file mode 100644 index 0000000..bbe10f0 --- /dev/null +++ b/native/codec/libraries/opus/silk/HP_variable_cutoff.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +) +{ + opus_int quality_Q15; + opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; + silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn; + + /* Adaptive cutoff frequency: estimate low end of pitch frequency range */ + if( psEncC1->prevSignalType == TYPE_VOICED ) { + /* difference, in log domain */ + pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag ); + pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); + + /* adjustment based on quality */ + quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ]; + pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ), + pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) ); + + /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */ + delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 ); + if( delta_freq_Q7 < 0 ) { + /* less smoothing for decreasing pitch frequency, to track something close to the minimum */ + delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 ); + } + + /* limit delta, to reduce impact of outliers in pitch estimation */ + delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) ); + + /* update smoother */ + psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15, + silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) ); + + /* limit frequency range */ + psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15, + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ), + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) ); + } +} diff --git a/native/codec/libraries/opus/silk/Inlines.h b/native/codec/libraries/opus/silk/Inlines.h new file mode 100644 index 0000000..ec986cd --- /dev/null +++ b/native/codec/libraries/opus/silk/Inlines.h @@ -0,0 +1,188 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/*! \file silk_Inlines.h + * \brief silk_Inlines.h defines OPUS_INLINE signal processing functions. + */ + +#ifndef SILK_FIX_INLINES_H +#define SILK_FIX_INLINES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* count leading zeros of opus_int64 */ +static OPUS_INLINE opus_int32 silk_CLZ64( opus_int64 in ) +{ + opus_int32 in_upper; + + in_upper = (opus_int32)silk_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + silk_CLZ32( (opus_int32) in ); + } else { + /* Search in the upper 32 bits */ + return silk_CLZ32( in_upper ); + } +} + +/* get number of leading zeros and fractional part (the bits right after the leading one */ +static OPUS_INLINE void silk_CLZ_FRAC( + opus_int32 in, /* I input */ + opus_int32 *lz, /* O number of leading zeros */ + opus_int32 *frac_Q7 /* O the 7 bits right after the leading one */ +) +{ + opus_int32 lzeros = silk_CLZ32(in); + + * lz = lzeros; + * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f; +} + +/* Approximation of square root */ +/* Accuracy: < +/- 10% for output values > 15 */ +/* < +/- 2.5% for output values > 120 */ +static OPUS_INLINE opus_int32 silk_SQRT_APPROX( opus_int32 x ) +{ + opus_int32 y, lz, frac_Q7; + + if( x <= 0 ) { + return 0; + } + + silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if( lz & 1 ) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + /* get scaling right */ + y >>= silk_RSHIFT(lz, 1); + + /* increment using fractional part of input */ + y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7)); + + return y; +} + +/* Divide two int32 values and return result as int32 in a given Q-domain */ +static OPUS_INLINE opus_int32 silk_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */ + const opus_int32 a32, /* I numerator (Q0) */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (>= 0) */ +) +{ + opus_int a_headrm, b_headrm, lshift; + opus_int32 b32_inv, a32_nrm, b32_nrm, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres >= 0 ); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = silk_CLZ32( silk_abs(a32) ) - 1; + a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + /* It's OK to overflow because the final value of a32_nrm should always be small */ + a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 )); /* Q: a_headrm */ + + /* Refinement */ + result = silk_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Convert to Qres domain */ + lshift = 29 + a_headrm - b_headrm - Qres; + if( lshift < 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} + +/* Invert int32 value and return result as int32 in a given Q-domain */ +static OPUS_INLINE opus_int32 silk_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (> 0) */ +) +{ + opus_int b_headrm, lshift; + opus_int32 b32_inv, b32_nrm, err_Q32, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres > 0 ); + + /* Compute number of bits head room and normalize input */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = silk_LSHIFT( ((opus_int32)1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */ + + /* Refinement */ + result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if( lshift <= 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + }else{ + /* Avoid undefined result */ + return 0; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_INLINES_H */ diff --git a/native/codec/libraries/opus/silk/LPC_analysis_filter.c b/native/codec/libraries/opus/silk/LPC_analysis_filter.c new file mode 100644 index 0000000..d34b5eb --- /dev/null +++ b/native/codec/libraries/opus/silk/LPC_analysis_filter.c @@ -0,0 +1,111 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "celt_lpc.h" + +/*******************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first d output samples are set to zero */ +/*******************************************/ + +/* OPT: Using celt_fir() for this function should be faster, but it may cause + integer overflows in intermediate values (not final results), which the + current implementation silences by casting to unsigned. Enabling + this should be safe in pretty much all cases, even though it is not technically + C89-compliant. */ +#define USE_CELT_FIR 0 + +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d, /* I Filter order */ + int arch /* I Run-time architecture */ +) +{ + opus_int j; +#if defined(FIXED_POINT) && USE_CELT_FIR + opus_int16 num[SILK_MAX_ORDER_LPC]; +#else + int ix; + opus_int32 out32_Q12, out32; + const opus_int16 *in_ptr; +#endif + + celt_assert( d >= 6 ); + celt_assert( (d & 1) == 0 ); + celt_assert( d <= len ); + +#if defined(FIXED_POINT) && USE_CELT_FIR + celt_assert( d <= SILK_MAX_ORDER_LPC ); + for ( j = 0; j < d; j++ ) { + num[ j ] = -B[ j ]; + } + celt_fir( in + d, num, out + d, len - d, d, arch ); + for ( j = 0; j < d; j++ ) { + out[ j ] = 0; + } +#else + (void)arch; + for( ix = d; ix < len; ix++ ) { + in_ptr = &in[ ix - 1 ]; + + out32_Q12 = silk_SMULBB( in_ptr[ 0 ], B[ 0 ] ); + /* Allowing wrap around so that two wraps can cancel each other. The rare + cases where the result wraps around can only be triggered by invalid streams*/ + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] ); + for( j = 6; j < d; j += 2 ) { + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j ], B[ j ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] ); + } + + /* Subtract prediction */ + out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 ); + + /* Scale to Q0 */ + out32 = silk_RSHIFT_ROUND( out32_Q12, 12 ); + + /* Saturate output */ + out[ ix ] = (opus_int16)silk_SAT16( out32 ); + } + + /* Set first d output samples to zero */ + silk_memset( out, 0, d * sizeof( opus_int16 ) ); +#endif +} diff --git a/native/codec/libraries/opus/silk/LPC_fit.c b/native/codec/libraries/opus/silk/LPC_fit.c new file mode 100644 index 0000000..cdea4f3 --- /dev/null +++ b/native/codec/libraries/opus/silk/LPC_fit.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2013, Koen Vos. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ +void silk_LPC_fit( + opus_int16 *a_QOUT, /* O Output signal */ + opus_int32 *a_QIN, /* I/O Input signal */ + const opus_int QOUT, /* I Input Q domain */ + const opus_int QIN, /* I Input Q domain */ + const opus_int d /* I Filter order */ +) +{ + opus_int i, k, idx = 0; + opus_int32 maxabs, absval, chirp_Q16; + + /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */ + for( i = 0; i < 10; i++ ) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for( k = 0; k < d; k++ ) { + absval = silk_abs( a_QIN[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + maxabs = silk_RSHIFT_ROUND( maxabs, QIN - QOUT ); + + if( maxabs > silk_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */ + chirp_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ), + silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) ); + silk_bwexpander_32( a_QIN, d, chirp_Q16 ); + } else { + break; + } + } + + if( i == 10 ) { + /* Reached the last iteration, clip the coefficients */ + for( k = 0; k < d; k++ ) { + a_QOUT[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ) ); + a_QIN[ k ] = silk_LSHIFT( (opus_int32)a_QOUT[ k ], QIN - QOUT ); + } + } else { + for( k = 0; k < d; k++ ) { + a_QOUT[ k ] = (opus_int16)silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ); + } + } +} diff --git a/native/codec/libraries/opus/silk/LPC_inv_pred_gain.c b/native/codec/libraries/opus/silk/LPC_inv_pred_gain.c new file mode 100644 index 0000000..a3746a6 --- /dev/null +++ b/native/codec/libraries/opus/silk/LPC_inv_pred_gain.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "define.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static opus_int32 LPC_inverse_pred_gain_QA_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2; + + invGain_Q30 = SILK_FIX_CONST( 1, 30 ); + for( k = order - 1; k > 0; k-- ) { + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update AR coefficient */ + for( n = 0; n < (k + 1) >> 1; n++ ) { + opus_int64 tmp64; + tmp1 = A_QA[ n ]; + tmp2 = A_QA[ k - n - 1 ]; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1, + MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ n ] = ( opus_int32 )tmp64; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2, + MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ k - n - 1 ] = ( opus_int32 )tmp64; + } + } + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 DC_resp = 0; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + DC_resp += (opus_int32)A_Q12[ k ]; + Atmp_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 ); + } + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + return 0; + } + return LPC_inverse_pred_gain_QA_c( Atmp_QA, order ); +} diff --git a/native/codec/libraries/opus/silk/LP_variable_cutoff.c b/native/codec/libraries/opus/silk/LP_variable_cutoff.c new file mode 100644 index 0000000..79112ad --- /dev/null +++ b/native/codec/libraries/opus/silk/LP_variable_cutoff.c @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. +*/ + +#include "main.h" + +/* Helper function, interpolates the filter taps */ +static OPUS_INLINE void silk_LP_interpolate_filter_taps( + opus_int32 B_Q28[ TRANSITION_NB ], + opus_int32 A_Q28[ TRANSITION_NA ], + const opus_int ind, + const opus_int32 fac_Q16 +) +{ + opus_int nb, na; + + if( ind < TRANSITION_INT_NUM - 1 ) { + if( fac_Q16 > 0 ) { + if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */ + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 ); + } + } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */ + silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) ); + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) ); + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) ); + } +} + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->mode <> 0; */ +/* Deactivate by setting psEncC->mode = 0; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; + opus_int ind = 0; + + silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES ); + + /* Run filter if needed */ + if( psLP->mode != 0 ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS == 64 ) + fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 ); +#else + fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES ); +#endif + ind = silk_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= silk_LSHIFT( ind, 16 ); + + silk_assert( ind >= 0 ); + silk_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Update transition frame number for next frame */ + psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES ); + + /* ARMA low-pass filtering */ + silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); + silk_biquad_alt_stride1( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length); + } +} diff --git a/native/codec/libraries/opus/silk/MacroCount.h b/native/codec/libraries/opus/silk/MacroCount.h new file mode 100644 index 0000000..78100ff --- /dev/null +++ b/native/codec/libraries/opus/silk/MacroCount.h @@ -0,0 +1,710 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SIGPROCFIX_API_MACROCOUNT_H +#define SIGPROCFIX_API_MACROCOUNT_H +#include + +#ifdef silk_MACRO_COUNT +#define varDefine opus_int64 ops_count = 0; + +extern opus_int64 ops_count; + +static OPUS_INLINE opus_int64 silk_SaveCount(){ + return(ops_count); +} + +static OPUS_INLINE opus_int64 silk_SaveResetCount(){ + opus_int64 ret; + + ret = ops_count; + ops_count = 0; + return(ret); +} + +static OPUS_INLINE silk_PrintCount(){ + printf("ops_count = %d \n ", (opus_int32)ops_count); +} + +#undef silk_MUL +static OPUS_INLINE opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} + +#undef silk_MUL_uint +static OPUS_INLINE opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} +#undef silk_MLA +static OPUS_INLINE opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_MLA_uint +static OPUS_INLINE opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 5; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + return ret; +} +#undef silk_SMLAWB +static OPUS_INLINE opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 5; + ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))); + return ret; +} + +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + return ret; +} +#undef silk_SMLAWT +static OPUS_INLINE opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + return ret; +} + +#undef silk_SMULBB +static OPUS_INLINE opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32); + return ret; +} +#undef silk_SMLABB +static OPUS_INLINE opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + return ret; +} + +#undef silk_SMULBT +static OPUS_INLINE opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){ + opus_int32 ret; + ops_count += 4; + ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16); + return ret; +} + +#undef silk_SMLABT +static OPUS_INLINE opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + return ret; +} + +#undef silk_SMULTT +static OPUS_INLINE opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (a32 >> 16) * (b32 >> 16); + return ret; +} + +#undef silk_SMLATT +static OPUS_INLINE opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (b32 >> 16) * (c32 >> 16); + return ret; +} + + +/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw silk_MLA + +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw silk_SMLABB + +#undef silk_SMLABT_ovflw +#define silk_SMLABT_ovflw silk_SMLABT + +#undef silk_SMLATT_ovflw +#define silk_SMLATT_ovflw silk_SMLATT + +#undef silk_SMLAWB_ovflw +#define silk_SMLAWB_ovflw silk_SMLAWB + +#undef silk_SMLAWT_ovflw +#define silk_SMLAWT_ovflw silk_SMLAWT + +#undef silk_SMULL +static OPUS_INLINE opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){ + opus_int64 ret; + ops_count += 8; + ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32)); + return ret; +} + +#undef silk_SMLAL +static OPUS_INLINE opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){ + opus_int64 ret; + ops_count += 8; + ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32)); + return ret; +} +#undef silk_SMLALBB +static OPUS_INLINE opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){ + opus_int64 ret; + ops_count += 4; + ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16)); + return ret; +} + +#undef SigProcFIX_CLZ16 +static OPUS_INLINE opus_int32 SigProcFIX_CLZ16(opus_int16 in16) +{ + opus_int32 out32 = 0; + ops_count += 10; + if( in16 == 0 ) { + return 16; + } + /* test nibbles */ + if( in16 & 0xFF00 ) { + if( in16 & 0xF000 ) { + in16 >>= 12; + } else { + out32 += 4; + in16 >>= 8; + } + } else { + if( in16 & 0xFFF0 ) { + out32 += 8; + in16 >>= 4; + } else { + out32 += 12; + } + } + /* test bits and return */ + if( in16 & 0xC ) { + if( in16 & 0x8 ) + return out32 + 0; + else + return out32 + 1; + } else { + if( in16 & 0xE ) + return out32 + 2; + else + return out32 + 3; + } +} + +#undef SigProcFIX_CLZ32 +static OPUS_INLINE opus_int32 SigProcFIX_CLZ32(opus_int32 in32) +{ + /* test highest 16 bits and convert to opus_int16 */ + ops_count += 2; + if( in32 & 0xFFFF0000 ) { + return SigProcFIX_CLZ16((opus_int16)(in32 >> 16)); + } else { + return SigProcFIX_CLZ16((opus_int16)in32) + 16; + } +} + +#undef silk_DIV32 +static OPUS_INLINE opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){ + ops_count += 64; + return a32 / b32; +} + +#undef silk_DIV32_16 +static OPUS_INLINE opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){ + ops_count += 32; + return a32 / b32; +} + +#undef silk_SAT8 +static OPUS_INLINE opus_int8 silk_SAT8(opus_int64 a){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))); + return(tmp); +} + +#undef silk_SAT16 +static OPUS_INLINE opus_int16 silk_SAT16(opus_int64 a){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))); + return(tmp); +} +#undef silk_SAT32 +static OPUS_INLINE opus_int32 silk_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))); + return(tmp); +} +#undef silk_POS_SAT32 +static OPUS_INLINE opus_int32 silk_POS_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a)); + return(tmp); +} + +#undef silk_ADD_POS_SAT8 +static OPUS_INLINE opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))); + return(tmp); +} +#undef silk_ADD_POS_SAT16 +static OPUS_INLINE opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_ADD_POS_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_LSHIFT8 +static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){ + opus_int8 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT16 +static OPUS_INLINE opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){ + opus_int16 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT32 +static OPUS_INLINE opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT64 +static OPUS_INLINE opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_ovflw +static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_uint +static OPUS_INLINE opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} + +#undef silk_RSHIFT8 +static OPUS_INLINE opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT16 +static OPUS_INLINE opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT32 +static OPUS_INLINE opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT64 +static OPUS_INLINE opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_RSHIFT_uint +static OPUS_INLINE opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_ADD_LSHIFT +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT32 +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT_uint +static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_RSHIFT +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT32 +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT_uint +static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_SUB_LSHIFT32 +static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_SUB_RSHIFT32 +static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b >> shift); + return ret; /* shift > 0*/ +} + +#undef silk_RSHIFT_ROUND +static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 3; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_RSHIFT_ROUND64 +static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){ + opus_int64 ret; + ops_count += 6; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_abs_int64 +static OPUS_INLINE opus_int64 silk_abs_int64(opus_int64 a){ + ops_count += 1; + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/ +} + +#undef silk_abs_int32 +static OPUS_INLINE opus_int32 silk_abs_int32(opus_int32 a){ + ops_count += 1; + return silk_abs(a); +} + + +#undef silk_min +static silk_min(a, b){ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_max +static silk_max(a, b){ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_sign +static silk_sign(a){ + ops_count += 1; + return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )); +} + +#undef silk_ADD16 +static OPUS_INLINE opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD32 +static OPUS_INLINE opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD64 +static OPUS_INLINE opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a + b; + return ret; +} + +#undef silk_SUB16 +static OPUS_INLINE opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB32 +static OPUS_INLINE opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB64 +static OPUS_INLINE opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a - b; + return ret; +} + +#undef silk_ADD_SAT16 +static OPUS_INLINE opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + /* Nb will be counted in AKP_add32 and silk_SAT16*/ + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_ADD_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){ + opus_int32 res; + ops_count += 1; + res = ((((a32) + (b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + return res; +} + +#undef silk_ADD_SAT64 +static OPUS_INLINE opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + return res; +} + +#undef silk_SUB_SAT16 +static OPUS_INLINE opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + silk_assert(0); + /* Nb will be counted in sub-macros*/ + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_SUB_SAT32 +static OPUS_INLINE opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) { + opus_int32 res; + ops_count += 1; + res = ((((a32)-(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + return res; +} + +#undef silk_SUB_SAT64 +static OPUS_INLINE opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + + return res; +} + +#undef silk_SMULWW +static OPUS_INLINE opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)); + return ret; +} + +#undef silk_SMLAWW +static OPUS_INLINE opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)); + return ret; +} + +#undef silk_min_int +static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +#undef silk_min_16 +static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_32 +static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_64 +static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +#undef silk_max_int +static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_16 +static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_32 +static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + +#undef silk_max_64 +static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + + +#undef silk_LIMIT_int +static OPUS_INLINE opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2) +{ + opus_int ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + + return(ret); +} + +#undef silk_LIMIT_16 +static OPUS_INLINE opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2) +{ + opus_int16 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + +return(ret); +} + + +#undef silk_LIMIT_32 +static OPUS_INLINE opus_int32 silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2) +{ + opus_int32 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + return(ret); +} + +#else +#define varDefine +#define silk_SaveCount() + +#endif +#endif + diff --git a/native/codec/libraries/opus/silk/MacroDebug.h b/native/codec/libraries/opus/silk/MacroDebug.h new file mode 100644 index 0000000..8dd4ce2 --- /dev/null +++ b/native/codec/libraries/opus/silk/MacroDebug.h @@ -0,0 +1,951 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (C) 2012 Xiph.Org Foundation +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef MACRO_DEBUG_H +#define MACRO_DEBUG_H + +/* Redefine macro functions with extensive assertion in DEBUG mode. + As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */ + +#if ( defined (FIXED_DEBUG) || ( 0 && defined (_DEBUG) ) ) && !defined (silk_MACRO_COUNT) + +#undef silk_ADD16 +#define silk_ADD16(a,b) silk_ADD16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_ADD16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT16( a, b ) ) + { + fprintf (stderr, "silk_ADD16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD32 +#define silk_ADD32(a,b) silk_ADD32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT32( a, b ) ) + { + fprintf (stderr, "silk_ADD32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD64 +#define silk_ADD64(a,b) silk_ADD64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_ADD64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT64( a, b ) ) + { + fprintf (stderr, "silk_ADD64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB16 +#define silk_SUB16(a,b) silk_SUB16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_SUB16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT16( a, b ) ) + { + fprintf (stderr, "silk_SUB16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB32 +#define silk_SUB32(a,b) silk_SUB32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT32( a, b ) ) + { + fprintf (stderr, "silk_SUB32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB64 +#define silk_SUB64(a,b) silk_SUB64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SUB64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT64( a, b ) ) + { + fprintf (stderr, "silk_SUB64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD_SAT16 +#define silk_ADD_SAT16(a,b) silk_ADD_SAT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_ADD_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_ADD_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT32 +#define silk_ADD_SAT32(a,b) silk_ADD_SAT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_SAT32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 res; + res = ((((opus_uint32)(a32) + (opus_uint32)(b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_ADD_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT64 +#define silk_ADD_SAT64(a,b) silk_ADD_SAT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_ADD_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line) { + opus_int64 res; + int fail = 0; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + if( res != a64 + b64 ) { + /* Check that we saturated to the correct extreme value */ + if ( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ) ) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 + b64; + } + if ( fail ) + { + fprintf (stderr, "silk_ADD_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT16 +#define silk_SUB_SAT16(a,b) silk_SUB_SAT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_SUB_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line ) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_SUB_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT32 +#define silk_SUB_SAT32(a,b) silk_SUB_SAT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_SAT32_( opus_int32 a32, opus_int32 b32, char *file, int line ) { + opus_int32 res; + res = ((((opus_uint32)(a32)-(opus_uint32)(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_SUB_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT64 +#define silk_SUB_SAT64(a,b) silk_SUB_SAT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SUB_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line ) { + opus_int64 res; + int fail = 0; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + if( res != a64 - b64 ) { + /* Check that we saturated to the correct extreme value */ + if( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) )) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 - b64; + } + if ( fail ) + { + fprintf (stderr, "silk_SUB_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_MUL +#define silk_MUL(a,b) silk_MUL_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MUL_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + opus_int64 ret64; + ret = a32 * b32; + ret64 = (opus_int64)a32 * (opus_int64)b32; + if ( (opus_int64)ret != ret64 ) + { + fprintf (stderr, "silk_MUL(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MUL_uint +#define silk_MUL_uint(a,b) silk_MUL_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_MUL_uint_(opus_uint32 a32, opus_uint32 b32, char *file, int line){ + opus_uint32 ret; + ret = a32 * b32; + if ( (opus_uint64)ret != (opus_uint64)a32 * (opus_uint64)b32 ) + { + fprintf (stderr, "silk_MUL_uint(%u, %u) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA +#define silk_MLA(a,b,c) silk_MLA_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MLA_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA_uint +#define silk_MLA_uint(a,b,c) silk_MLA_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MLA_uint_(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32, char *file, int line){ + opus_uint32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA_uint(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWB +#define silk_SMULWB(a,b) silk_SMULWB_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWB_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (opus_int16)b32) >> 16 ) + { + fprintf (stderr, "silk_SMULWB(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWB +#define silk_SMLAWB(a,b,c) silk_SMLAWB_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) ); + if ( silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) != silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) ) ) + { + fprintf (stderr, "silk_SMLAWB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWT +#define silk_SMULWT(a,b) silk_SMULWT_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWT_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (b32 >> 16)) >> 16 ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWT +#define silk_SMLAWT(a,b,c) silk_SMLAWT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + if ( (opus_int64)ret != (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16) ) + { + fprintf (stderr, "silk_SMLAWT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULL +#define silk_SMULL(a,b) silk_SMULL_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SMULL_(opus_int64 a64, opus_int64 b64, char *file, int line){ + opus_int64 ret64; + int fail = 0; + ret64 = a64 * b64; + if( b64 != 0 ) { + fail = a64 != (ret64 / b64); + } else if( a64 != 0 ) { + fail = b64 != (ret64 / a64); + } + if ( fail ) + { + fprintf (stderr, "silk_SMULL(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret64; +} + +/* no checking needed for silk_SMULBB */ +#undef silk_SMLABB +#define silk_SMLABB(a,b,c) silk_SMLABB_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLABB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32 ) + { + fprintf (stderr, "silk_SMLABB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULBT */ +#undef silk_SMLABT +#define silk_SMLABT(a,b,c) silk_SMLABT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLABT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLABT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULTT */ +#undef silk_SMLATT +#define silk_SMLATT(a,b,c) silk_SMLATT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLATT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (b32 >> 16) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (b32 >> 16) * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLATT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWW +#define silk_SMULWW(a,b) silk_SMULWW_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWW_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret, tmp1, tmp2; + opus_int64 ret64; + int fail = 0; + + ret = silk_SMULWB( a32, b32 ); + tmp1 = silk_RSHIFT_ROUND( b32, 16 ); + tmp2 = silk_MUL( a32, tmp1 ); + + fail |= (opus_int64)tmp2 != (opus_int64) a32 * (opus_int64) tmp1; + + tmp1 = ret; + ret = silk_ADD32( tmp1, tmp2 ); + fail |= silk_ADD32( tmp1, tmp2 ) != silk_ADD_SAT32( tmp1, tmp2 ); + + ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 ); + fail |= (opus_int64)ret != ret64; + + if ( fail ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + + return ret; +} + +#undef silk_SMLAWW +#define silk_SMLAWW(a,b,c) silk_SMLAWW_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWW_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret, tmp; + + tmp = silk_SMULWW( b32, c32 ); + ret = silk_ADD32( a32, tmp ); + if ( ret != silk_ADD_SAT32( a32, tmp ) ) + { + fprintf (stderr, "silk_SMLAWW(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw(a32, b32, c32) ((a32) + ((b32) * (c32))) +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* no checking needed for silk_SMULL + no checking needed for silk_SMLAL + no checking needed for silk_SMLALBB + no checking needed for SigProcFIX_CLZ16 + no checking needed for SigProcFIX_CLZ32*/ + +#undef silk_DIV32 +#define silk_DIV32(a,b) silk_DIV32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_DIV32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + if ( b32 == 0 ) + { + fprintf (stderr, "silk_DIV32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +#undef silk_DIV32_16 +#define silk_DIV32_16(a,b) silk_DIV32_16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, char *file, int line){ + int fail = 0; + fail |= b32 == 0; + fail |= b32 > silk_int16_MAX; + fail |= b32 < silk_int16_MIN; + if ( fail ) + { + fprintf (stderr, "silk_DIV32_16(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +/* no checking needed for silk_SAT8 + no checking needed for silk_SAT16 + no checking needed for silk_SAT32 + no checking needed for silk_POS_SAT32 + no checking needed for silk_ADD_POS_SAT8 + no checking needed for silk_ADD_POS_SAT16 + no checking needed for silk_ADD_POS_SAT32 */ + +#undef silk_LSHIFT8 +#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_LSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + opus_int8 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 8; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT16 +#define silk_LSHIFT16(a,b) silk_LSHIFT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_LSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + opus_int16 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 16; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT32 +#define silk_LSHIFT32(a,b) silk_LSHIFT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_LSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 32; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT64 +#define silk_LSHIFT64(a,b) silk_LSHIFT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_LSHIFT64_(opus_int64 a, opus_int shift, char *file, int line){ + opus_int64 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 64; + fail |= (ret>>shift) != ((opus_int64)a); + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT_ovflw +#define silk_LSHIFT_ovflw(a,b) silk_LSHIFT_ovflw_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift >= 32) ) /* no check for overflow */ + { + fprintf (stderr, "silk_LSHIFT_ovflw(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a << shift; +} + +#undef silk_LSHIFT_uint +#define silk_LSHIFT_uint(a,b) silk_LSHIFT_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_LSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a << shift; + if ( (shift < 0) || ((opus_int64)ret != ((opus_int64)a) << shift)) + { + fprintf (stderr, "silk_LSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT8 +#define silk_RSHITF8(a,b) silk_RSHIFT8_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_RSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=8) ) + { + fprintf (stderr, "silk_RSHITF8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT16 +#define silk_RSHITF16(a,b) silk_RSHIFT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_RSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=16) ) + { + fprintf (stderr, "silk_RSHITF16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT32 +#define silk_RSHIFT32(a,b) silk_RSHIFT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_RSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=32) ) + { + fprintf (stderr, "silk_RSHITF32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT64 +#define silk_RSHIFT64(a,b) silk_RSHIFT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_RSHIFT64_(opus_int64 a, opus_int64 shift, char *file, int line){ + if ( (shift < 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHITF64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT_uint +#define silk_RSHIFT_uint(a,b) silk_RSHIFT_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_RSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>32) ) + { + fprintf (stderr, "silk_RSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_ADD_LSHIFT +#define silk_ADD_LSHIFT(a,b,c) silk_ADD_LSHIFT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE int silk_ADD_LSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT32 +#define silk_ADD_LSHIFT32(a,b,c) silk_ADD_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT_uint +#define silk_ADD_LSHIFT_uint(a,b,c) silk_ADD_LSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_RSHIFT +#define silk_ADD_RSHIFT(a,b,c) silk_ADD_RSHIFT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE int silk_ADD_RSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT32 +#define silk_ADD_RSHIFT32(a,b,c) silk_ADD_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT_uint +#define silk_ADD_RSHIFT_uint(a,b,c) silk_ADD_RSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_SUB_LSHIFT32 +#define silk_SUB_LSHIFT32(a,b,c) silk_SUB_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_SUB_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_SUB_RSHIFT32 +#define silk_SUB_RSHIFT32(a,b,c) silk_SUB_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_SUB_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_RSHIFT_ROUND +#define silk_RSHIFT_ROUND(a,b) silk_RSHIFT_ROUND_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT_ROUND64 +#define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){ + opus_int64 ret; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +/* silk_abs is used on floats also, so doesn't work... */ +/*#undef silk_abs +static OPUS_INLINE opus_int32 silk_abs(opus_int32 a){ + silk_assert(a != 0x80000000); + return (((a) > 0) ? (a) : -(a)); // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN +}*/ + +#undef silk_abs_int64 +#define silk_abs_int64(a) silk_abs_int64_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_abs_int64_(opus_int64 a, char *file, int line){ + if ( a == silk_int64_MIN ) + { + fprintf (stderr, "silk_abs_int64(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +} + +#undef silk_abs_int32 +#define silk_abs_int32(a) silk_abs_int32_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_abs_int32_(opus_int32 a, char *file, int line){ + if ( a == silk_int32_MIN ) + { + fprintf (stderr, "silk_abs_int32(%d) in %s: line %d\n", a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return silk_abs(a); +} + +#undef silk_CHECK_FIT8 +#define silk_CHECK_FIT8(a) silk_CHECK_FIT8_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_CHECK_FIT8_( opus_int64 a, char *file, int line ){ + opus_int8 ret; + ret = (opus_int8)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT8(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT16 +#define silk_CHECK_FIT16(a) silk_CHECK_FIT16_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_CHECK_FIT16_( opus_int64 a, char *file, int line ){ + opus_int16 ret; + ret = (opus_int16)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT16(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT32 +#define silk_CHECK_FIT32(a) silk_CHECK_FIT32_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_CHECK_FIT32_( opus_int64 a, char *file, int line ){ + opus_int32 ret; + ret = (opus_int32)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT32(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +/* no checking for silk_NSHIFT_MUL_32_32 + no checking for silk_NSHIFT_MUL_16_16 + no checking needed for silk_min + no checking needed for silk_max + no checking needed for silk_sign +*/ + +#endif +#endif /* MACRO_DEBUG_H */ diff --git a/native/codec/libraries/opus/silk/NLSF2A.c b/native/codec/libraries/opus/silk/NLSF2A.c new file mode 100644 index 0000000..d5b7730 --- /dev/null +++ b/native/codec/libraries/opus/silk/NLSF2A.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* conversion between prediction filter coefficients and LSFs */ +/* order should be even */ +/* a piecewise linear approximation maps LSF <-> cos(LSF) */ +/* therefore the result is not accurate LSFs, but the two */ +/* functions are accurate inverses of each other */ + +#include "SigProc_FIX.h" +#include "tables.h" + +#define QA 16 + +/* helper function for NLSF2A(..) */ +static OPUS_INLINE void silk_NLSF2A_find_poly( + opus_int32 *out, /* O intermediate polynomial, QA [dd+1] */ + const opus_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */ + opus_int dd /* I polynomial order (= 1/2 * filter order) */ +) +{ + opus_int k, n; + opus_int32 ftmp; + + out[0] = silk_LSHIFT( 1, QA ); + out[1] = -cLSF[0]; + for( k = 1; k < dd; k++ ) { + ftmp = cLSF[2*k]; /* QA*/ + out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA ); + for( n = k; n > 1; n-- ) { + out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA ); + } + out[1] -= ftmp; + } +} + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d, /* I filter order (should be even) */ + int arch /* I Run-time architecture */ +) +{ + /* This ordering was found to maximize quality. It improves numerical accuracy of + silk_NLSF2A_find_poly() compared to "standard" ordering. */ + static const unsigned char ordering16[16] = { + 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1 + }; + static const unsigned char ordering10[10] = { + 0, 9, 6, 3, 4, 5, 8, 1, 2, 7 + }; + const unsigned char *ordering; + opus_int k, i, dd; + opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta; + opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ]; + + silk_assert( LSF_COS_TAB_SZ_FIX == 128 ); + celt_assert( d==10 || d==16 ); + + /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */ + ordering = d == 16 ? ordering16 : ordering10; + for( k = 0; k < d; k++ ) { + silk_assert( NLSF[k] >= 0 ); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = silk_RSHIFT( NLSF[k], 15 - 7 ); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 ); + + silk_assert(f_int >= 0); + silk_assert(f_int < LSF_COS_TAB_SZ_FIX ); + + /* Read start and end value from table */ + cos_val = silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */ + delta = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */ + } + + dd = silk_RSHIFT( d, 1 ); + + /* generate even and odd polynomials using convolution */ + silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd ); + silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd ); + + /* convert even and odd polynomials to opus_int32 Q12 filter coefs */ + for( k = 0; k < dd; k++ ) { + Ptmp = P[ k+1 ] + P[ k ]; + Qtmp = Q[ k+1 ] - Q[ k ]; + + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ + a32_QA1[ k ] = -Qtmp - Ptmp; /* QA+1 */ + a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */ + } + + /* Convert int32 coefficients to Q12 int16 coefs */ + silk_LPC_fit( a_Q12, a32_QA1, 12, QA + 1, d ); + + for( i = 0; silk_LPC_inverse_pred_gain( a_Q12, d, arch ) == 0 && i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */ + /* on the unscaled coefficients, convert to Q12 and measure again */ + silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) ); + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } +} + diff --git a/native/codec/libraries/opus/silk/NLSF_VQ.c b/native/codec/libraries/opus/silk/NLSF_VQ.c new file mode 100644 index 0000000..b83182a --- /dev/null +++ b/native/codec/libraries/opus/silk/NLSF_VQ.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q24[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +) +{ + opus_int i, m; + opus_int32 diff_Q15, diffw_Q24, sum_error_Q24, pred_Q24; + const opus_int16 *w_Q9_ptr; + const opus_uint8 *cb_Q8_ptr; + + celt_assert( ( LPC_order & 1 ) == 0 ); + + /* Loop over codebook */ + cb_Q8_ptr = pCB_Q8; + w_Q9_ptr = pWght_Q9; + for( i = 0; i < K; i++ ) { + sum_error_Q24 = 0; + pred_Q24 = 0; + for( m = LPC_order-2; m >= 0; m -= 2 ) { + /* Compute weighted absolute predictive quantization error for index m + 1 */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m + 1 ], (opus_int32)cb_Q8_ptr[ m + 1 ], 7 ); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m + 1 ] ); + sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) ); + pred_Q24 = diffw_Q24; + + /* Compute weighted absolute predictive quantization error for index m */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)cb_Q8_ptr[ m ], 7 ); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m ] ); + sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) ); + pred_Q24 = diffw_Q24; + + silk_assert( sum_error_Q24 >= 0 ); + } + err_Q24[ i ] = sum_error_Q24; + cb_Q8_ptr += LPC_order; + w_Q9_ptr += LPC_order; + } +} diff --git a/native/codec/libraries/opus/silk/NLSF_VQ_weights_laroia.c b/native/codec/libraries/opus/silk/NLSF_VQ_weights_laroia.c new file mode 100644 index 0000000..9873bcd --- /dev/null +++ b/native/codec/libraries/opus/silk/NLSF_VQ_weights_laroia.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "SigProc_FIX.h" + +/* +R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP +Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech, +Signal Processing, pp. 641-644, 1991. +*/ + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +) +{ + opus_int k; + opus_int32 tmp1_int, tmp2_int; + + celt_assert( D > 0 ); + celt_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 ); + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k ] > 0 ); + + tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 ); + } + + /* Last value */ + tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 ); +} diff --git a/native/codec/libraries/opus/silk/NLSF_decode.c b/native/codec/libraries/opus/silk/NLSF_decode.c new file mode 100644 index 0000000..eeb0ba8 --- /dev/null +++ b/native/codec/libraries/opus/silk/NLSF_decode.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Predictive dequantizer for NLSF residuals */ +static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */ + opus_int16 x_Q10[], /* O Output [ order ] */ + const opus_int8 indices[], /* I Quantization indices [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, out_Q10, pred_Q10; + + out_Q10 = 0; + for( i = order-1; i >= 0; i-- ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 ); + out_Q10 = silk_LSHIFT( indices[ i ], 10 ); + if( out_Q10 > 0 ) { + out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( out_Q10 < 0 ) { + out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out_Q10 = silk_SMLAWB( pred_Q10, (opus_int32)out_Q10, quant_step_size_Q16 ); + x_Q10[ i ] = out_Q10; + } +} + + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +) +{ + opus_int i; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int32 NLSF_Q15_tmp; + const opus_uint8 *pCB_element; + const opus_int16 *pCB_Wght_Q9; + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] ); + + /* Predictive residual dequantizer */ + silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order ); + + /* Apply inverse square-rooted weights to first stage and add to output */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_Q15_tmp = silk_ADD_LSHIFT32( silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), pCB_Wght_Q9[ i ] ), (opus_int16)pCB_element[ i ], 7 ); + pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 ); + } + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); +} diff --git a/native/codec/libraries/opus/silk/NLSF_del_dec_quant.c b/native/codec/libraries/opus/silk/NLSF_del_dec_quant.c new file mode 100644 index 0000000..44a16ac --- /dev/null +++ b/native/codec/libraries/opus/silk/NLSF_del_dec_quant.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10; + opus_int pred_Q10, diff_Q10, rate0_Q5, rate1_Q5; + opus_int16 out0_Q10, out1_Q10; + opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25; + opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ]; + opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + const opus_uint8 *rates_Q5; + + opus_int out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + opus_int out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + + for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT-1; i++) + { + out0_Q10 = silk_LSHIFT( i, 10 ); + out1_Q10 = silk_ADD16( out0_Q10, 1024 ); + if( i > 0 ) { + out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( i == 0 ) { + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( i == -1 ) { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out0_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out0_Q10, quant_step_size_Q16 ), 16 ); + out1_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out1_Q10, quant_step_size_Q16 ), 16 ); + } + + silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */ + + nStates = 1; + RD_Q25[ 0 ] = 0; + prev_out_Q10[ 0 ] = 0; + for( i = order - 1; i >= 0; i-- ) { + rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ]; + in_Q10 = x_Q10[ i ]; + for( j = 0; j < nStates; j++ ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( (opus_int16)pred_coef_Q8[ i ], prev_out_Q10[ j ] ), 8 ); + res_Q10 = silk_SUB16( in_Q10, pred_Q10 ); + ind_tmp = silk_RSHIFT( silk_SMULBB( inv_quant_step_size_Q6, res_Q10 ), 16 ); + ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 ); + ind[ j ][ i ] = (opus_int8)ind_tmp; + + /* compute outputs for ind_tmp and ind_tmp + 1 */ + out0_Q10 = out0_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ]; + out1_Q10 = out1_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ]; + + out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 ); + out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 ); + prev_out_Q10[ j ] = out0_Q10; + prev_out_Q10[ j + nStates ] = out1_Q10; + + /* compute RD for ind_tmp and ind_tmp + 1 */ + if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = 280; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp ); + rate1_Q5 = silk_ADD16( rate0_Q5, 43 ); + } + } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = 280; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp ); + rate1_Q5 = silk_SUB16( rate0_Q5, 43 ); + } + } else { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } + RD_tmp_Q25 = RD_Q25[ j ]; + diff_Q10 = silk_SUB16( in_Q10, out0_Q10 ); + RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 ); + diff_Q10 = silk_SUB16( in_Q10, out1_Q10 ); + RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 ); + } + + if( nStates <= NLSF_QUANT_DEL_DEC_STATES/2 ) { + /* double number of states and copy */ + for( j = 0; j < nStates; j++ ) { + ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1; + } + nStates = silk_LSHIFT( nStates, 1 ); + for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] = ind[ j - nStates ][ i ]; + } + } else { + /* sort lower and upper half of RD_Q25, pairwise */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) { + RD_max_Q25[ j ] = RD_Q25[ j ]; + RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + RD_Q25[ j ] = RD_min_Q25[ j ]; + RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ]; + /* swap prev_out values */ + out0_Q10 = prev_out_Q10[ j ]; + prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10; + ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES; + } else { + RD_min_Q25[ j ] = RD_Q25[ j ]; + RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + ind_sort[ j ] = j; + } + } + /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */ + /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */ + while( 1 ) { + min_max_Q25 = silk_int32_MAX; + max_min_Q25 = 0; + ind_min_max = 0; + ind_max_min = 0; + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_max_Q25 > RD_max_Q25[ j ] ) { + min_max_Q25 = RD_max_Q25[ j ]; + ind_min_max = j; + } + if( max_min_Q25 < RD_min_Q25[ j ] ) { + max_min_Q25 = RD_min_Q25[ j ]; + ind_max_min = j; + } + } + if( min_max_Q25 >= max_min_Q25 ) { + break; + } + /* copy ind_min_max to ind_max_min */ + ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES; + RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + RD_min_Q25[ ind_max_min ] = 0; + RD_max_Q25[ ind_min_max ] = silk_int32_MAX; + silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) ); + } + /* increment index if it comes from the upper half */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + } + } + } + + /* last sample: find winner, copy indices and return RD value */ + ind_tmp = 0; + min_Q25 = silk_int32_MAX; + for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_Q25 > RD_Q25[ j ] ) { + min_Q25 = RD_Q25[ j ]; + ind_tmp = j; + } + } + for( j = 0; j < order; j++ ) { + indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ]; + silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + } + indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( min_Q25 >= 0 ); + return min_Q25; +} diff --git a/native/codec/libraries/opus/silk/NLSF_encode.c b/native/codec/libraries/opus/silk/NLSF_encode.c new file mode 100644 index 0000000..01ac7db --- /dev/null +++ b/native/codec/libraries/opus/silk/NLSF_encode.c @@ -0,0 +1,124 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O (Un)quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_Q2, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +) +{ + opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7; + opus_int32 W_tmp_Q9, ret; + VARDECL( opus_int32, err_Q24 ); + VARDECL( opus_int32, RD_Q25 ); + VARDECL( opus_int, tempIndices1 ); + VARDECL( opus_int8, tempIndices2 ); + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; + opus_int16 W_adj_Q5[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + const opus_uint8 *pCB_element, *iCDF_ptr; + const opus_int16 *pCB_Wght_Q9; + SAVE_STACK; + + celt_assert( signalType >= 0 && signalType <= 2 ); + silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 ); + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); + + /* First stage: VQ */ + ALLOC( err_Q24, psNLSF_CB->nVectors, opus_int32 ); + silk_NLSF_VQ( err_Q24, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->CB1_Wght_Q9, psNLSF_CB->nVectors, psNLSF_CB->order ); + + /* Sort the quantization errors */ + ALLOC( tempIndices1, nSurvivors, opus_int ); + silk_insertion_sort_increasing( err_Q24, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); + + ALLOC( RD_Q25, nSurvivors, opus_int32 ); + ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 ); + + /* Loop over survivors */ + for( s = 0; s < nSurvivors; s++ ) { + ind1 = tempIndices1[ s ]; + + /* Residual after first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ ind1 * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 ); + W_tmp_Q9 = pCB_Wght_Q9[ i ]; + res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ], W_tmp_Q9 ), 14 ); + W_adj_Q5[ i ] = silk_DIV32_varQ( (opus_int32)pW_Q2[ i ], silk_SMULBB( W_tmp_Q9, W_tmp_Q9 ), 21 ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 ); + + /* Trellis quantizer */ + RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix, + psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order ); + + /* Add rate for first stage */ + iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ]; + if( ind1 == 0 ) { + prob_Q8 = 256 - iCDF_ptr[ ind1 ]; + } else { + prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ]; + } + bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 ); + RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) ); + } + + /* Find the lowest rate-distortion error */ + silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 ); + + NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ]; + silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); + + /* Decode */ + silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB ); + + ret = RD_Q25[ 0 ]; + RESTORE_STACK; + return ret; +} diff --git a/native/codec/libraries/opus/silk/NLSF_stabilize.c b/native/codec/libraries/opus/silk/NLSF_stabilize.c new file mode 100644 index 0000000..8f3426b --- /dev/null +++ b/native/codec/libraries/opus/silk/NLSF_stabilize.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* NLSF stabilizer: */ +/* */ +/* - Moves NLSFs further apart if they are too close */ +/* - Moves NLSFs away from borders if they are too close */ +/* - High effort to achieve a modification with minimum */ +/* Euclidean distance to input vector */ +/* - Output are sorted NLSF coefficients */ +/* */ + +#include "SigProc_FIX.h" + +/* Constant Definitions */ +#define MAX_LOOPS 20 + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +) +{ + opus_int i, I=0, k, loops; + opus_int16 center_freq_Q15; + opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15; + + /* This is necessary to ensure an output within range of a opus_int16 */ + silk_assert( NDeltaMin_Q15[L] >= 1 ); + + for( loops = 0; loops < MAX_LOOPS; loops++ ) { + /**************************/ + /* Find smallest distance */ + /**************************/ + /* First element */ + min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; + I = 0; + /* Middle elements */ + for( i = 1; i <= L-1; i++ ) { + diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = i; + } + } + /* Last element */ + diff_Q15 = ( 1 << 15 ) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = L; + } + + /***************************************************/ + /* Now check if the smallest distance non-negative */ + /***************************************************/ + if( min_diff_Q15 >= 0 ) { + return; + } + + if( I == 0 ) { + /* Move away from lower limit */ + NLSF_Q15[0] = NDeltaMin_Q15[0]; + + } else if( I == L) { + /* Move away from higher limit */ + NLSF_Q15[L-1] = ( 1 << 15 ) - NDeltaMin_Q15[L]; + + } else { + /* Find the lower extreme for the location of the current center frequency */ + min_center_Q15 = 0; + for( k = 0; k < I; k++ ) { + min_center_Q15 += NDeltaMin_Q15[k]; + } + min_center_Q15 += silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Find the upper extreme for the location of the current center frequency */ + max_center_Q15 = 1 << 15; + for( k = L; k > I; k-- ) { + max_center_Q15 -= NDeltaMin_Q15[k]; + } + max_center_Q15 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ), + min_center_Q15, max_center_Q15 ); + NLSF_Q15[I-1] = center_freq_Q15 - silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I]; + } + } + + /* Safe and simple fall back method, which is less ideal than the above */ + if( loops == MAX_LOOPS ) + { + /* Insertion sort (fast for already almost sorted arrays): */ + /* Best case: O(n) for an already sorted array */ + /* Worst case: O(n^2) for an inversely sorted array */ + silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L ); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] ); + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) + NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); + + /* Keep NDeltaMin distance between the NLSFs */ + for( i = L-2; i >= 0; i-- ) + NLSF_Q15[i] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] ); + } +} diff --git a/native/codec/libraries/opus/silk/NLSF_unpack.c b/native/codec/libraries/opus/silk/NLSF_unpack.c new file mode 100644 index 0000000..17bd23f --- /dev/null +++ b/native/codec/libraries/opus/silk/NLSF_unpack.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +) +{ + opus_int i; + opus_uint8 entry; + const opus_uint8 *ec_sel_ptr; + + ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ]; + for( i = 0; i < psNLSF_CB->order; i += 2 ) { + entry = *ec_sel_ptr++; + ec_ix [ i ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ]; + ec_ix [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ]; + } +} + diff --git a/native/codec/libraries/opus/silk/NSQ.c b/native/codec/libraries/opus/silk/NSQ.c new file mode 100644 index 0000000..1d64d8e --- /dev/null +++ b/native/codec/libraries/opus/silk/NSQ.c @@ -0,0 +1,437 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" + + +static OPUS_INLINE void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int16 x16[], /* I input */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +); +#endif + +void silk_NSQ_c +( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + SAVE_STACK; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states( psEncC, NSQ, x16, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10, + offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/***********************************/ +/* silk_noise_shape_quantizer */ +/***********************************/ + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE +#endif +void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +) +{ + opus_int i; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; +#ifdef silk_short_prediction_create_arch_coef + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; +#endif + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + +#ifdef silk_short_prediction_create_arch_coef + silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder); +#endif + + for( i = 0; i < length; i++ ) { + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Short-term prediction */ + LPC_pred_Q10 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch); + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q13 = 0; + } + + /* Noise shape feedback */ + celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(&NSQ->sDiff_shp_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch); + + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 ); + + celt_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if( NSQ->rand_seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if (Lambda_Q10 > 2048) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + int rdo_offset = Lambda_Q10/2 - 512; + if (q1_Q10 > rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 ); + } else if (q1_Q10 < -rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 ); + } else if (q1_Q10 < 0) { + q1_Q0 = -1; + } else { + q1_Q0 = 0; + } + } + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* Q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 ); + + if( rd2_Q20 < rd1_Q20 ) { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + if ( NSQ->rand_seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Scale XQ back to normal level before saving */ + xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + NSQ->sDiff_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_sc_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( NSQ->sDiff_shp_Q14, n_AR_Q12, 2 ); + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static OPUS_INLINE void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int16 x16[], /* I input */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + } + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + NSQ->sDiff_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sDiff_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/native/codec/libraries/opus/silk/NSQ.h b/native/codec/libraries/opus/silk/NSQ.h new file mode 100644 index 0000000..971832f --- /dev/null +++ b/native/codec/libraries/opus/silk/NSQ.h @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2014 Vidyo. +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ +#ifndef SILK_NSQ_H +#define SILK_NSQ_H + +#include "SigProc_FIX.h" + +#undef silk_short_prediction_create_arch_coef + +static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(const opus_int32 *buf32, const opus_int16 *coef16, opus_int order) +{ + opus_int32 out; + silk_assert( order == 10 || order == 16 ); + + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + out = silk_RSHIFT( order, 1 ); + out = silk_SMLAWB( out, buf32[ 0 ], coef16[ 0 ] ); + out = silk_SMLAWB( out, buf32[ -1 ], coef16[ 1 ] ); + out = silk_SMLAWB( out, buf32[ -2 ], coef16[ 2 ] ); + out = silk_SMLAWB( out, buf32[ -3 ], coef16[ 3 ] ); + out = silk_SMLAWB( out, buf32[ -4 ], coef16[ 4 ] ); + out = silk_SMLAWB( out, buf32[ -5 ], coef16[ 5 ] ); + out = silk_SMLAWB( out, buf32[ -6 ], coef16[ 6 ] ); + out = silk_SMLAWB( out, buf32[ -7 ], coef16[ 7 ] ); + out = silk_SMLAWB( out, buf32[ -8 ], coef16[ 8 ] ); + out = silk_SMLAWB( out, buf32[ -9 ], coef16[ 9 ] ); + + if( order == 16 ) + { + out = silk_SMLAWB( out, buf32[ -10 ], coef16[ 10 ] ); + out = silk_SMLAWB( out, buf32[ -11 ], coef16[ 11 ] ); + out = silk_SMLAWB( out, buf32[ -12 ], coef16[ 12 ] ); + out = silk_SMLAWB( out, buf32[ -13 ], coef16[ 13 ] ); + out = silk_SMLAWB( out, buf32[ -14 ], coef16[ 14 ] ); + out = silk_SMLAWB( out, buf32[ -15 ], coef16[ 15 ] ); + } + return out; +} + +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order)) + +static OPUS_INLINE opus_int32 silk_NSQ_noise_shape_feedback_loop_c(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order) +{ + opus_int32 out; + opus_int32 tmp1, tmp2; + opus_int j; + + tmp2 = data0[0]; + tmp1 = data1[0]; + data1[0] = tmp2; + + out = silk_RSHIFT(order, 1); + out = silk_SMLAWB(out, tmp2, coef[0]); + + for (j = 2; j < order; j += 2) { + tmp2 = data1[j - 1]; + data1[j - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[j - 1]); + tmp1 = data1[j + 0]; + data1[j + 0] = tmp2; + out = silk_SMLAWB(out, tmp2, coef[j]); + } + data1[order - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[order - 1]); + /* Q11 -> Q12 */ + out = silk_LSHIFT32( out, 1 ); + return out; +} + +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order)) + +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +#include "arm/NSQ_neon.h" +#endif + +#endif /* SILK_NSQ_H */ diff --git a/native/codec/libraries/opus/silk/NSQ_del_dec.c b/native/codec/libraries/opus/silk/NSQ_del_dec.c new file mode 100644 index 0000000..3fd9fa0 --- /dev/null +++ b/native/codec/libraries/opus/silk/NSQ_del_dec.c @@ -0,0 +1,733 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" + + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Diff_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 Diff_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +typedef NSQ_sample_struct NSQ_sample_pair[ 2 ]; + +#if defined(MIPSr1_ASM) +#include "mips/NSQ_del_dec_mipsr1.h" +#endif +static OPUS_INLINE void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +); + +void silk_NSQ_del_dec_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_dec_struct, psDelDec ); + NSQ_del_dec_struct *psDD; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct ); + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Diff_Q14 = NSQ->sDiff_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 ); + silk_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], + Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, + psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay, psEncC->arch ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->sDiff_shp_Q14 = psDD->Diff_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +#ifndef OVERRIDE_silk_noise_shape_quantizer_del_dec +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; +#ifdef silk_short_prediction_create_arch_coef + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; +#endif + + VARDECL( NSQ_sample_pair, psSampleState ); + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + SAVE_STACK; + + celt_assert( nStatesDelayedDecision > 0 ); + ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + +#ifdef silk_short_prediction_create_arch_coef + silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder); +#endif + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + LPC_pred_Q14 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch); + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psDD->Diff_Q14, psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if (Lambda_Q10 > 2048) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + int rdo_offset = Lambda_Q10/2 - 512; + if (q1_Q10 > rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 ); + } else if (q1_Q10 < -rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 ); + } else if (q1_Q10 < 0) { + q1_Q0 = -1; + } else { + q1_Q0 = 0; + } + } + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + psSS[ 0 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB32( psSS[ 0 ].Diff_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + psSS[ 1 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB32( psSS[ 1 ].Diff_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->Diff_Q14 = psSS->Diff_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} +#endif /* OVERRIDE_silk_noise_shape_quantizer_del_dec */ + +static OPUS_INLINE void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + NSQ_del_dec_struct *psDD; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + } + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + psDD->Diff_Q14 = silk_SMULWW( gain_adj_Q16, psDD->Diff_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/native/codec/libraries/opus/silk/PLC.c b/native/codec/libraries/opus/silk/PLC.c new file mode 100644 index 0000000..f893916 --- /dev/null +++ b/native/codec/libraries/opus/silk/PLC.c @@ -0,0 +1,448 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "PLC.h" + +#define NB_ATT 2 +static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ +static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ +static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ + +static OPUS_INLINE void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +); + +static OPUS_INLINE void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* O LPC residual signal */ + int arch /* I Run-time architecture */ +); + + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); + psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.subfr_length = 20; + psDec->sPLC.nb_subfr = 2; +} + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost, /* I Loss flag */ + int arch /* I Run-time architecture */ +) +{ + /* PLC control function */ + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { + silk_PLC_Reset( psDec ); + psDec->sPLC.fs_kHz = psDec->fs_kHz; + } + + if( lost ) { + /****************************/ + /* Generate Signal */ + /****************************/ + silk_PLC_conceal( psDec, psDecCtrl, frame, arch ); + + psDec->lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + silk_PLC_update( psDec, psDecCtrl ); + } +} + +/**************************************************/ +/* Update state of PLC */ +/**************************************************/ +static OPUS_INLINE void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +) +{ + opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; + opus_int i, j; + silk_PLC_struct *psPLC; + + psPLC = &psDec->sPLC; + + /* Update parameters used in case of packet loss */ + psDec->prevSignalType = psDec->indices.signalType; + LTP_Gain_Q14 = 0; + if( psDec->indices.signalType == TYPE_VOICED ) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { + if( j == psDec->nb_subfr ) { + break; + } + temp_LTP_Gain_Q14 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; + } + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + silk_memcpy( psPLC->LTPCoef_Q14, + &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], + LTP_ORDER * sizeof( opus_int16 ) ); + + psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); + } + } + + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; + + /* Limit LT coefs */ + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { + opus_int scale_Q10; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); + scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); + } + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { + opus_int scale_Q14; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); + scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); + } + } + } else { + psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); + } + + /* Save LPC coeficients */ + silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; + + /* Save last two gains */ + silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); + + psPLC->subfr_length = psDec->subfr_length; + psPLC->nb_subfr = psDec->nb_subfr; +} + +static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2, + const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr) +{ + int i, k; + VARDECL( opus_int16, exc_buf ); + opus_int16 *exc_buf_ptr; + SAVE_STACK; + ALLOC( exc_buf, 2*subfr_length, opus_int16 ); + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf; + for( k = 0; k < 2; k++ ) { + for( i = 0; i < subfr_length; i++ ) { + exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( + silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) ); + } + exc_buf_ptr += subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length ); + silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length ); + RESTORE_STACK; +} + +static OPUS_INLINE void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* O LPC residual signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, j, k; + opus_int lag, idx, sLTP_buf_idx, shift1, shift2; + opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; + opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; + opus_int32 LPC_pred_Q10, LTP_pred_Q12; + opus_int16 rand_scale_Q14; + opus_int16 *B_Q14; + opus_int32 *sLPC_Q14_ptr; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; +#ifdef SMALL_FOOTPRINT + opus_int16 *sLTP; +#else + VARDECL( opus_int16, sLTP ); +#endif + VARDECL( opus_int32, sLTP_Q14 ); + silk_PLC_struct *psPLC = &psDec->sPLC; + opus_int32 prevGain_Q10[2]; + SAVE_STACK; + + ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); +#ifdef SMALL_FOOTPRINT + /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */ + sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length; +#else + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); +#endif + + prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); + prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); + + if( psDec->first_frame_after_reset ) { + silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); + } + + silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr); + + if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { + /* First sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } + + /* Set up Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Set up attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + if( psDec->prevSignalType == TYPE_VOICED ) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } + + /* LPC concealment. Apply BWE to previous LPC */ + silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* First Lost frame */ + if( psDec->lossCnt == 0 ) { + rand_scale_Q14 = 1 << 14; + + /* Reduce random noise Gain for voiced frames */ + if( psDec->prevSignalType == TYPE_VOICED ) { + for( i = 0; i < LTP_ORDER; i++ ) { + rand_scale_Q14 -= B_Q14[ i ]; + } + rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ + rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); + } else { + /* Reduce random noise for unvoiced frames with high LPC gain */ + opus_int32 invGain_Q30, down_scale_Q30; + + invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch ); + + down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); + down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); + down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); + + rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); + } + } + + rand_seed = psPLC->rand_seed; + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + sLTP_buf_idx = psDec->ltp_mem_length; + + /* Rewhiten LTP state */ + idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + celt_assert( idx > 0 ); + silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch ); + /* Scale LTP state */ + inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); + inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); + for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { + sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); + } + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + for( k = 0; k < psDec->nb_subfr; k++ ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q12 = 2; + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + rand_seed = silk_RAND( rand_seed ); + idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; + sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); + sLTP_buf_idx++; + } + + /* Gradually reduce LTP gain */ + for( j = 0; j < LTP_ORDER; j++ ) { + B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); + } + if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) { + /* Gradually reduce excitation gain */ + rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); + } + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); + psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ + for( i = 0; i < psDec->frame_length; i++ ) { + /* partly unrolled */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + for( j = 10; j < psDec->LPC_order; j++ ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], + silk_LSHIFT_SAT32( LPC_pred_Q10, 4 )); + + /* Scale with Gain */ + frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for( i = 0; i < MAX_NB_SUBFR; i++ ) { + psDecCtrl->pitchL[ i ] = lag; + } + RESTORE_STACK; +} + +/* Glues concealed frames with new good received frames */ +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +) +{ + opus_int i, energy_shift; + opus_int32 energy; + silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + if( psDec->lossCnt ) { + /* Calculate energy in concealed residual */ + silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); + + psPLC->last_frame_lost = 1; + } else { + if( psDec->sPLC.last_frame_lost ) { + /* Calculate residual in decoded signal if last frame was lost */ + silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); + + /* Normalize energies */ + if( energy_shift > psPLC->conc_energy_shift ) { + psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); + } else if( energy_shift < psPLC->conc_energy_shift ) { + energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); + } + + /* Fade in the energy difference */ + if( energy > psPLC->conc_energy ) { + opus_int32 frac_Q24, LZ; + opus_int32 gain_Q16, slope_Q16; + + LZ = silk_CLZ32( psPLC->conc_energy ); + LZ = LZ - 1; + psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); + energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); + + frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); + + gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); + slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); + /* Make slope 4x steeper to avoid missing onsets after DTX */ + slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); + + for( i = 0; i < length; i++ ) { + frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); + gain_Q16 += slope_Q16; + if( gain_Q16 > (opus_int32)1 << 16 ) { + break; + } + } + } + } + psPLC->last_frame_lost = 0; + } +} diff --git a/native/codec/libraries/opus/silk/PLC.h b/native/codec/libraries/opus/silk/PLC.h new file mode 100644 index 0000000..6438f51 --- /dev/null +++ b/native/codec/libraries/opus/silk/PLC.h @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_PLC_H +#define SILK_PLC_H + +#include "main.h" + +#define BWE_COEF 0.99 +#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */ +#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */ +#define MAX_PITCH_LAG_MS 18 +#define RAND_BUF_SIZE 128 +#define RAND_BUF_MASK ( RAND_BUF_SIZE - 1 ) +#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */ +#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */ +#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */ + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost, /* I Loss flag */ + int arch /* I Run-time architecture */ +); + +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +); + +#endif + diff --git a/native/codec/libraries/opus/silk/SigProc_FIX.h b/native/codec/libraries/opus/silk/SigProc_FIX.h new file mode 100644 index 0000000..f9ae326 --- /dev/null +++ b/native/codec/libraries/opus/silk/SigProc_FIX.h @@ -0,0 +1,641 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_H +#define SILK_SIGPROC_FIX_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */ + +#define SILK_MAX_ORDER_LPC 24 /* max order of the LPC analysis in schur() and k2a() */ + +#include /* for memset(), memcpy(), memmove() */ +#include "typedef.h" +#include "resampler_structs.h" +#include "macros.h" +#include "cpu_support.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/SigProc_FIX_sse.h" +#endif + +#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/biquad_alt_arm.h" +#include "arm/LPC_inv_pred_gain_arm.h" +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/*! + * Initialize/reset the resampler state for a given pair of input/output sampling rates +*/ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +); + +/*! + * Resampler: convert from one sampling rate to another + */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! +* Downsample 2x, mediocre quality +*/ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ len ] */ + const opus_int16 *in, /* I Input signal [ floor(len/2) ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * Downsample by a factor 2/3, low quality +*/ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * second order ARMA filter; + * slower than biquad() but uses more precise coefficients + * can handle (slowly) varying coefficients + */ +void silk_biquad_alt_stride1( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +void silk_biquad_alt_stride2_c( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +/* Variable order MA prediction error filter. */ +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d, /* I Filter order */ + int arch /* I Run-time architecture */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +); + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +/* Split signal in two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +); + +#if !defined(OVERRIDE_silk_biquad_alt_stride2) +#define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_c(in, B_Q28, A_Q28, S, out, len)) +#endif + +#if !defined(OVERRIDE_silk_LPC_inverse_pred_gain) +#define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_c(A_Q12, order)) +#endif + +/********************************************************************/ +/* SCALAR FUNCTIONS */ +/********************************************************************/ + +/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +); + +/* Approximation of a sigmoid function */ +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +); + +/* Approximation of 2^() (exact inverse of approx log2() above) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +); + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* every other sample of window is linearly interpolated, for speed */ +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount, /* I Number of correlation taps to compute */ + int arch /* I Run-time architecture */ +); + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +); + +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I number of 5 ms subframes */ + int arch /* I Run-time architecture */ +); + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +); + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d, /* I filter order (should be even) */ + int arch /* I Run-time architecture */ +); + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ +void silk_LPC_fit( + opus_int16 *a_QOUT, /* O Output signal */ + opus_int32 *a_QIN, /* I/O Input signal */ + const opus_int QOUT, /* I Input Q domain */ + const opus_int QIN, /* I Input Q domain */ + const opus_int d /* I Filter order */ +); + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +); + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +); + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +); + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_c( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +); + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +); + +/* Some for the LTP related function requires Q26 to work.*/ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +); + +/********************************************************************/ +/* INLINE ARM MATH */ +/********************************************************************/ + +/* return sum( inVec1[i] * inVec2[i] ) */ + +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len, /* I vector lengths */ + int arch /* I Run-time architecture */ +); + + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +); + +opus_int64 silk_inner_prod16_aligned_64_c( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating + left. Output is 32bit int. + Note: contemporary compilers recognize the C expression below and + compile it into a 'ror' instruction if available. No need for OPUS_INLINE ASM! */ +static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot ) +{ + opus_uint32 x = (opus_uint32) a32; + opus_uint32 r = (opus_uint32) rot; + opus_uint32 m = (opus_uint32) -rot; + if( rot == 0 ) { + return a32; + } else if( rot < 0 ) { + return (opus_int32) ((x << m) | (x >> (32 - m))); + } else { + return (opus_int32) ((x << (32 - r)) | (x >> r)); + } +} + +/* Allocate opus_int16 aligned to 4-byte memory address */ +#if EMBEDDED_ARM +#define silk_DWORD_ALIGN __attribute__((aligned(4))) +#else +#define silk_DWORD_ALIGN +#endif + +/* Useful Macros that can be adjusted to other platforms */ +#define silk_memcpy(dest, src, size) memcpy((dest), (src), (size)) +#define silk_memset(dest, src, size) memset((dest), (src), (size)) +#define silk_memmove(dest, src, size) memmove((dest), (src), (size)) + +/* Fixed point macros */ + +/* (a32 * b32) output have to be 32bit int */ +#define silk_MUL(a32, b32) ((a32) * (b32)) + +/* (a32 * b32) output have to be 32bit uint */ +#define silk_MUL_uint(a32, b32) silk_MUL(a32, b32) + +/* a32 + (b32 * c32) output have to be 32bit int */ +#define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32))) + +/* a32 + (b32 * c32) output have to be 32bit uint */ +#define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32) + +/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) + +/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) + +#define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16))) + +/* (a32 * b32) */ +#define silk_SMULL(a32, b32) ((opus_int64)(a32) * /*(opus_int64)*/(b32)) + +/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b))) +/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b))) + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32)) +#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))) + +#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16))) +#define silk_DIV32(a32, b32) ((opus_int32)((a32) / (b32))) + +/* These macros enables checking for overflow in silk_API_Debug.h*/ +#define silk_ADD16(a, b) ((a) + (b)) +#define silk_ADD32(a, b) ((a) + (b)) +#define silk_ADD64(a, b) ((a) + (b)) + +#define silk_SUB16(a, b) ((a) - (b)) +#define silk_SUB32(a, b) ((a) - (b)) +#define silk_SUB64(a, b) ((a) - (b)) + +#define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))) +#define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))) +#define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))) + +#define silk_CHECK_FIT8(a) (a) +#define silk_CHECK_FIT16(a) (a) +#define silk_CHECK_FIT32(a) (a) + +#define silk_ADD_SAT16(a, b) (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) ) +#define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \ + ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) ) + +#define silk_SUB_SAT16(a, b) (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) ) +#define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \ + (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \ + ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) ) + +/* Saturation for positive input values */ +#define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a)) + +/* Add with saturation for positive input values */ +#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT32(a, b) ((((opus_uint32)(a)+(opus_uint32)(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))) + +#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */ +#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */ +#define silk_LSHIFT32(a, shift) ((opus_int32)((opus_uint32)(a)<<(shift))) /* shift >= 0, shift < 32 */ +#define silk_LSHIFT64(a, shift) ((opus_int64)((opus_uint64)(a)<<(shift))) /* shift >= 0, shift < 64 */ +#define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +#define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */ +#define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */ +#define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */ +#define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */ +#define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +/* saturates before shifting */ +#define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \ + silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) )) + +#define silk_LSHIFT_ovflw(a, shift) ((opus_int32)((opus_uint32)(a) << (shift))) /* shift >= 0, allowed to overflow */ +#define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */ +#define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */ + +#define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ + +/* Requires that shift > 0 */ +#define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) +#define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + +/* Number of rightshift required to fit the multiplication */ +#define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) ) +#define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) ) + + +#define silk_min(a, b) (((a) < (b)) ? (a) : (b)) +#define silk_max(a, b) (((a) > (b)) ? (a) : (b)) + +/* Macro to convert floating-point constants to fixed-point */ +#define SILK_FIX_CONST( C, Q ) ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5)) + +/* silk_min() versions with typecast in the function call */ +static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +#define silk_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +#define silk_LIMIT_int silk_LIMIT +#define silk_LIMIT_16 silk_LIMIT +#define silk_LIMIT_32 silk_LIMIT + +#define silk_abs(a) (((a) > 0) ? (a) : -(a)) /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +#define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1))) +#define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) +#define silk_abs_int64(a) (((a) > 0) ? (a) : -(a)) + +#define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )) + +/* PSEUDO-RANDOM GENERATOR */ +/* Make sure to store the result as the seed for the next call (also in between */ +/* frames), otherwise result won't be random at all. When only using some of the */ +/* bits, take the most significant bits by right-shifting. */ +#define RAND_MULTIPLIER 196314165 +#define RAND_INCREMENT 907633515 +#define silk_RAND(seed) (silk_MLA_ovflw((RAND_INCREMENT), (seed), (RAND_MULTIPLIER))) + +/* Add some multiplication functions that can be easily mapped to ARM. */ + +/* silk_SMMUL: Signed top word multiply. + ARMv6 2 instruction cycles. + ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/ +/*#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/ +/* the following seems faster on x86 */ +#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32) + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((void)(arch), silk_burg_modified_c(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((void)(arch),silk_inner_prod16_aligned_64_c(inVec1, inVec2, len)) +#endif + +#include "Inlines.h" +#include "MacroCount.h" +#include "MacroDebug.h" + +#ifdef OPUS_ARM_INLINE_ASM +#include "arm/SigProc_FIX_armv4.h" +#endif + +#ifdef OPUS_ARM_INLINE_EDSP +#include "arm/SigProc_FIX_armv5e.h" +#endif + +#if defined(MIPSr1_ASM) +#include "mips/sigproc_fix_mipsr1.h" +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FIX_H */ diff --git a/native/codec/libraries/opus/silk/VAD.c b/native/codec/libraries/opus/silk/VAD.c new file mode 100644 index 0000000..d0cda52 --- /dev/null +++ b/native/codec/libraries/opus/silk/VAD.c @@ -0,0 +1,360 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Silk VAD noise level estimation */ +# if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); +#endif + +/**********************************/ +/* Initialization of the Silk VAD */ +/**********************************/ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int b, ret = 0; + + /* reset state memory */ + silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) ); + + /* init noise levels */ + /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 ); + } + + /* Initialize state */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] ); + psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] ); + } + psSilk_VAD->counter = 15; + + /* init smoothed energy-to-noise ratio*/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */ + } + + return( ret ); +} + +/* Weighting factors for tilt measure */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength1, decimated_framelength2; + opus_int decimated_framelength; + opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + VARDECL( opus_int16, X ); + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int X_offset[ VAD_N_BANDS ]; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + SAVE_STACK; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + celt_assert( psEncC->frame_length <= 512 ); + celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 ); + decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 ); + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + /* Decimate into 4 bands: + 0 L 3L L 3L 5L + - -- - -- -- + 8 8 2 4 4 + + [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz | + + They're arranged to allow the minimal ( frame_length / 4 ) extra + scratch space during the downsampling process */ + X_offset[ 0 ] = 0; + X_offset[ 1 ] = decimated_framelength + decimated_framelength2; + X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength; + X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2; + ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 ); + + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], + X, &X[ X_offset[ 3 ] ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ], + X, &X[ X_offset[ 2 ] ], decimated_framelength1 ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ], + X, &X[ X_offset[ 1 ] ], decimated_framelength2 ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 ); + X[ i ] -= X[ i - 1 ]; + } + X[ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + sumSquared = 0; + for( i = 0; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( + X[ X_offset[ b ] + i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( (opus_int32)1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + if( psEncC->frame_length == 20 * psEncC->fs_kHz ) { + speech_nrg = silk_RSHIFT32( speech_nrg, 1 ); + } + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 16384 ) { + speech_nrg = silk_LSHIFT32( speech_nrg, 16 ); + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + RESTORE_STACK; + return( ret ); +} + +/**************************/ +/* Noise level estimation */ +/**************************/ +# if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE +#endif +void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int k; + opus_int32 nl, nrg, inv_nrg; + opus_int coef, min_coef; + + /* Initially faster smoothing */ + if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */ + min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 ); + /* Increment frame counter */ + psSilk_VAD->counter++; + } else { + min_coef = 0; + } + + for( k = 0; k < VAD_N_BANDS; k++ ) { + /* Get old noise level estimate for current band */ + nl = psSilk_VAD->NL[ k ]; + silk_assert( nl >= 0 ); + + /* Add bias */ + nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] ); + silk_assert( nrg > 0 ); + + /* Invert energies */ + inv_nrg = silk_DIV32( silk_int32_MAX, nrg ); + silk_assert( inv_nrg >= 0 ); + + /* Less update when subband energy is high */ + if( nrg > silk_LSHIFT( nl, 3 ) ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3; + } else if( nrg < nl ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16; + } else { + coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 ); + } + + /* Initially faster smoothing */ + coef = silk_max_int( coef, min_coef ); + + /* Smooth inverse energies */ + psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef ); + silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 ); + + /* Compute noise level by inverting again */ + nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] ); + silk_assert( nl >= 0 ); + + /* Limit noise levels (guarantee 7 bits of head room) */ + nl = silk_min( nl, 0x00FFFFFF ); + + /* Store as part of state */ + psSilk_VAD->NL[ k ] = nl; + } +} diff --git a/native/codec/libraries/opus/silk/VQ_WMat_EC.c b/native/codec/libraries/opus/silk/VQ_WMat_EC.c new file mode 100644 index 0000000..0f3d545 --- /dev/null +++ b/native/codec/libraries/opus/silk/VQ_WMat_EC.c @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC_c( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *res_nrg_Q15, /* O best residual energy */ + opus_int32 *rate_dist_Q8, /* O best total bitrate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int32 *XX_Q17, /* I correlation matrix */ + const opus_int32 *xX_Q17, /* I correlation vector */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int subfr_len, /* I number of samples per subframe */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k, gain_tmp_Q7; + const opus_int8 *cb_row_Q7; + opus_int32 neg_xX_Q24[ 5 ]; + opus_int32 sum1_Q15, sum2_Q24; + opus_int32 bits_res_Q8, bits_tot_Q8; + + /* Negate and convert to new Q domain */ + neg_xX_Q24[ 0 ] = -silk_LSHIFT32( xX_Q17[ 0 ], 7 ); + neg_xX_Q24[ 1 ] = -silk_LSHIFT32( xX_Q17[ 1 ], 7 ); + neg_xX_Q24[ 2 ] = -silk_LSHIFT32( xX_Q17[ 2 ], 7 ); + neg_xX_Q24[ 3 ] = -silk_LSHIFT32( xX_Q17[ 3 ], 7 ); + neg_xX_Q24[ 4 ] = -silk_LSHIFT32( xX_Q17[ 4 ], 7 ); + + /* Loop over codebook */ + *rate_dist_Q8 = silk_int32_MAX; + *res_nrg_Q15 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + /* In things go really bad, at least *ind is set to something safe. */ + *ind = 0; + for( k = 0; k < L; k++ ) { + opus_int32 penalty; + gain_tmp_Q7 = cb_gain_Q7[k]; + /* Weighted rate */ + /* Quantization error: 1 - 2 * xX * cb + cb' * XX * cb */ + sum1_Q15 = SILK_FIX_CONST( 1.001, 15 ); + + /* Penalty for too large gain */ + penalty = silk_LSHIFT32( silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 11 ); + + /* first row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 0 ], XX_Q17[ 1 ], cb_row_Q7[ 1 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 2 ], cb_row_Q7[ 2 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 3 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 4 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 0 ], cb_row_Q7[ 0 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 0 ] ); + + /* second row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 1 ], XX_Q17[ 7 ], cb_row_Q7[ 2 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 8 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 9 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 6 ], cb_row_Q7[ 1 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 1 ] ); + + /* third row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 2 ], XX_Q17[ 13 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 14 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 12 ], cb_row_Q7[ 2 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 2 ] ); + + /* fourth row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 3 ], XX_Q17[ 19 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 18 ], cb_row_Q7[ 3 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 3 ] ); + + /* last row of XX_Q17 */ + sum2_Q24 = silk_LSHIFT32( neg_xX_Q24[ 4 ], 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 24 ], cb_row_Q7[ 4 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 4 ] ); + + /* find best */ + if( sum1_Q15 >= 0 ) { + /* Translate residual energy to bits using high-rate assumption (6 dB ==> 1 bit/sample) */ + bits_res_Q8 = silk_SMULBB( subfr_len, silk_lin2log( sum1_Q15 + penalty) - (15 << 7) ); + /* In the following line we reduce the codelength component by half ("-1"); seems to slghtly improve quality */ + bits_tot_Q8 = silk_ADD_LSHIFT32( bits_res_Q8, cl_Q5[ k ], 3-1 ); + if( bits_tot_Q8 <= *rate_dist_Q8 ) { + *rate_dist_Q8 = bits_tot_Q8; + *res_nrg_Q15 = sum1_Q15 + penalty; + *ind = (opus_int8)k; + *gain_Q7 = gain_tmp_Q7; + } + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/native/codec/libraries/opus/silk/ana_filt_bank_1.c b/native/codec/libraries/opus/silk/ana_filt_bank_1.c new file mode 100644 index 0000000..24cfb03 --- /dev/null +++ b/native/codec/libraries/opus/silk/ana_filt_bank_1.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Coefficients for 2-band filter bank based on first-order allpass filters */ +static opus_int16 A_fb1_20 = 5394 << 1; +static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */ + +/* Split signal into two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +) +{ + opus_int k, N2 = silk_RSHIFT( N, 1 ); + opus_int32 in32, X, Y, out_1, out_2; + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < N2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, A_fb1_21 ); + out_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, A_fb1_20 ); + out_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add/subtract, convert back to int16 and store to output */ + outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) ); + outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) ); + } +} diff --git a/native/codec/libraries/opus/silk/arm/LPC_inv_pred_gain_arm.h b/native/codec/libraries/opus/silk/arm/LPC_inv_pred_gain_arm.h new file mode 100644 index 0000000..9895b55 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/LPC_inv_pred_gain_arm.h @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_LPC_INV_PRED_GAIN_ARM_H +# define SILK_LPC_INV_PRED_GAIN_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +opus_int32 silk_LPC_inverse_pred_gain_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), PRESUME_NEON(silk_LPC_inverse_pred_gain)(A_Q12, order)) +# endif +# endif + +# if !defined(OVERRIDE_silk_LPC_inverse_pred_gain) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK+1])(const opus_int16 *A_Q12, const opus_int order); +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((*SILK_LPC_INVERSE_PRED_GAIN_IMPL[(arch)&OPUS_ARCHMASK])(A_Q12, order)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_neon(A_Q12, order)) +# endif +# endif + +#endif /* end SILK_LPC_INV_PRED_GAIN_ARM_H */ diff --git a/native/codec/libraries/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c b/native/codec/libraries/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c new file mode 100644 index 0000000..ab426bc --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c @@ -0,0 +1,280 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "SigProc_FIX.h" +#include "define.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* The difficulty is how to judge a 64-bit signed integer tmp64 is 32-bit overflowed, + * since NEON has no 64-bit min, max or comparison instructions. + * A failed idea is to compare the results of vmovn(tmp64) and vqmovn(tmp64) whether they are equal or not. + * However, this idea fails when the tmp64 is something like 0xFFFFFFF980000000. + * Here we know that mult2Q >= 1, so the highest bit (bit 63, sign bit) of tmp64 must equal to bit 62. + * tmp64 was shifted left by 1 and we got tmp64'. If high_half(tmp64') != 0 and high_half(tmp64') != -1, + * then we know that bit 31 to bit 63 of tmp64 can not all be the sign bit, and therefore tmp64 is 32-bit overflowed. + * That is, we judge if tmp64' > 0x00000000FFFFFFFF, or tmp64' <= 0xFFFFFFFF00000000. + * We use narrowing shift right 31 bits to tmp32' to save data bandwidth and instructions. + * That is, we judge if tmp32' > 0x00000000, or tmp32' <= 0xFFFFFFFF. + */ + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static OPUS_INLINE opus_int32 LPC_inverse_pred_gain_QA_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2; + opus_int32 max, min; + int32x4_t max_s32x4, min_s32x4; + int32x2_t max_s32x2, min_s32x2; + + max_s32x4 = vdupq_n_s32( silk_int32_MIN ); + min_s32x4 = vdupq_n_s32( silk_int32_MAX ); + invGain_Q30 = SILK_FIX_CONST( 1, 30 ); + for( k = order - 1; k > 0; k-- ) { + int32x2_t rc_Q31_s32x2, rc_mult2_s32x2; + int64x2_t mult2Q_s64x2; + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update AR coefficient */ + rc_Q31_s32x2 = vdup_n_s32( rc_Q31 ); + mult2Q_s64x2 = vdupq_n_s64( -mult2Q ); + rc_mult2_s32x2 = vdup_n_s32( rc_mult2 ); + + for( n = 0; n < ( ( k + 1 ) >> 1 ) - 3; n += 4 ) { + /* We always calculate extra elements of A_QA buffer when ( k % 4 ) != 0, to take the advantage of SIMD parallelization. */ + int32x4_t tmp1_s32x4, tmp2_s32x4, t0_s32x4, t1_s32x4, s0_s32x4, s1_s32x4, t_QA0_s32x4, t_QA1_s32x4; + int64x2_t t0_s64x2, t1_s64x2, t2_s64x2, t3_s64x2; + tmp1_s32x4 = vld1q_s32( A_QA + n ); + tmp2_s32x4 = vld1q_s32( A_QA + k - n - 4 ); + tmp2_s32x4 = vrev64q_s32( tmp2_s32x4 ); + tmp2_s32x4 = vcombine_s32( vget_high_s32( tmp2_s32x4 ), vget_low_s32( tmp2_s32x4 ) ); + t0_s32x4 = vqrdmulhq_lane_s32( tmp2_s32x4, rc_Q31_s32x2, 0 ); + t1_s32x4 = vqrdmulhq_lane_s32( tmp1_s32x4, rc_Q31_s32x2, 0 ); + t_QA0_s32x4 = vqsubq_s32( tmp1_s32x4, t0_s32x4 ); + t_QA1_s32x4 = vqsubq_s32( tmp2_s32x4, t1_s32x4 ); + t0_s64x2 = vmull_s32( vget_low_s32 ( t_QA0_s32x4 ), rc_mult2_s32x2 ); + t1_s64x2 = vmull_s32( vget_high_s32( t_QA0_s32x4 ), rc_mult2_s32x2 ); + t2_s64x2 = vmull_s32( vget_low_s32 ( t_QA1_s32x4 ), rc_mult2_s32x2 ); + t3_s64x2 = vmull_s32( vget_high_s32( t_QA1_s32x4 ), rc_mult2_s32x2 ); + t0_s64x2 = vrshlq_s64( t0_s64x2, mult2Q_s64x2 ); + t1_s64x2 = vrshlq_s64( t1_s64x2, mult2Q_s64x2 ); + t2_s64x2 = vrshlq_s64( t2_s64x2, mult2Q_s64x2 ); + t3_s64x2 = vrshlq_s64( t3_s64x2, mult2Q_s64x2 ); + t0_s32x4 = vcombine_s32( vmovn_s64( t0_s64x2 ), vmovn_s64( t1_s64x2 ) ); + t1_s32x4 = vcombine_s32( vmovn_s64( t2_s64x2 ), vmovn_s64( t3_s64x2 ) ); + s0_s32x4 = vcombine_s32( vshrn_n_s64( t0_s64x2, 31 ), vshrn_n_s64( t1_s64x2, 31 ) ); + s1_s32x4 = vcombine_s32( vshrn_n_s64( t2_s64x2, 31 ), vshrn_n_s64( t3_s64x2, 31 ) ); + max_s32x4 = vmaxq_s32( max_s32x4, s0_s32x4 ); + min_s32x4 = vminq_s32( min_s32x4, s0_s32x4 ); + max_s32x4 = vmaxq_s32( max_s32x4, s1_s32x4 ); + min_s32x4 = vminq_s32( min_s32x4, s1_s32x4 ); + t1_s32x4 = vrev64q_s32( t1_s32x4 ); + t1_s32x4 = vcombine_s32( vget_high_s32( t1_s32x4 ), vget_low_s32( t1_s32x4 ) ); + vst1q_s32( A_QA + n, t0_s32x4 ); + vst1q_s32( A_QA + k - n - 4, t1_s32x4 ); + } + for( ; n < (k + 1) >> 1; n++ ) { + opus_int64 tmp64; + tmp1 = A_QA[ n ]; + tmp2 = A_QA[ k - n - 1 ]; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1, + MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ n ] = ( opus_int32 )tmp64; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2, + MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ k - n - 1 ] = ( opus_int32 )tmp64; + } + } + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + max_s32x2 = vmax_s32( vget_low_s32( max_s32x4 ), vget_high_s32( max_s32x4 ) ); + min_s32x2 = vmin_s32( vget_low_s32( min_s32x4 ), vget_high_s32( min_s32x4 ) ); + max_s32x2 = vmax_s32( max_s32x2, vreinterpret_s32_s64( vshr_n_s64( vreinterpret_s64_s32( max_s32x2 ), 32 ) ) ); + min_s32x2 = vmin_s32( min_s32x2, vreinterpret_s32_s64( vshr_n_s64( vreinterpret_s64_s32( min_s32x2 ), 32 ) ) ); + max = vget_lane_s32( max_s32x2, 0 ); + min = vget_lane_s32( min_s32x2, 0 ); + if( ( max > 0 ) || ( min < -1 ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ +#ifdef OPUS_CHECK_ASM + const opus_int32 invGain_Q30_c = silk_LPC_inverse_pred_gain_c( A_Q12, order ); +#endif + + opus_int32 invGain_Q30; + if( ( SILK_MAX_ORDER_LPC != 24 ) || ( order & 1 )) { + invGain_Q30 = silk_LPC_inverse_pred_gain_c( A_Q12, order ); + } + else { + opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 DC_resp; + int16x8_t t0_s16x8, t1_s16x8, t2_s16x8; + int32x4_t t0_s32x4; + const opus_int leftover = order & 7; + + /* Increase Q domain of the AR coefficients */ + t0_s16x8 = vld1q_s16( A_Q12 + 0 ); + t1_s16x8 = vld1q_s16( A_Q12 + 8 ); + t2_s16x8 = vld1q_s16( A_Q12 + 16 ); + t0_s32x4 = vpaddlq_s16( t0_s16x8 ); + + switch( order - leftover ) + { + case 24: + t0_s32x4 = vpadalq_s16( t0_s32x4, t2_s16x8 ); + /* FALLTHROUGH */ + + case 16: + t0_s32x4 = vpadalq_s16( t0_s32x4, t1_s16x8 ); + vst1q_s32( Atmp_QA + 16, vshll_n_s16( vget_low_s16 ( t2_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 20, vshll_n_s16( vget_high_s16( t2_s16x8 ), QA - 12 ) ); + /* FALLTHROUGH */ + + case 8: + { + const int32x2_t t_s32x2 = vpadd_s32( vget_low_s32( t0_s32x4 ), vget_high_s32( t0_s32x4 ) ); + const int64x1_t t_s64x1 = vpaddl_s32( t_s32x2 ); + DC_resp = vget_lane_s32( vreinterpret_s32_s64( t_s64x1 ), 0 ); + vst1q_s32( Atmp_QA + 8, vshll_n_s16( vget_low_s16 ( t1_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 12, vshll_n_s16( vget_high_s16( t1_s16x8 ), QA - 12 ) ); + } + break; + + default: + DC_resp = 0; + break; + } + A_Q12 += order - leftover; + + switch( leftover ) + { + case 6: + DC_resp += (opus_int32)A_Q12[ 5 ]; + DC_resp += (opus_int32)A_Q12[ 4 ]; + /* FALLTHROUGH */ + + case 4: + DC_resp += (opus_int32)A_Q12[ 3 ]; + DC_resp += (opus_int32)A_Q12[ 2 ]; + /* FALLTHROUGH */ + + case 2: + DC_resp += (opus_int32)A_Q12[ 1 ]; + DC_resp += (opus_int32)A_Q12[ 0 ]; + /* FALLTHROUGH */ + + default: + break; + } + + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + invGain_Q30 = 0; + } else { + vst1q_s32( Atmp_QA + 0, vshll_n_s16( vget_low_s16 ( t0_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 4, vshll_n_s16( vget_high_s16( t0_s16x8 ), QA - 12 ) ); + invGain_Q30 = LPC_inverse_pred_gain_QA_neon( Atmp_QA, order ); + } + } + +#ifdef OPUS_CHECK_ASM + silk_assert( invGain_Q30_c == invGain_Q30 ); +#endif + + return invGain_Q30; +} diff --git a/native/codec/libraries/opus/silk/arm/NSQ_del_dec_arm.h b/native/codec/libraries/opus/silk/arm/NSQ_del_dec_arm.h new file mode 100644 index 0000000..9e76e16 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/NSQ_del_dec_arm.h @@ -0,0 +1,100 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_NSQ_DEL_DEC_ARM_H +#define SILK_NSQ_DEL_DEC_ARM_H + +#include "celt/arm/armcpu.h" + +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_NSQ_del_dec_neon( + const silk_encoder_state *psEncC, silk_nsq_state *NSQ, + SideInfoIndices *psIndices, const opus_int16 x16[], opus_int8 pulses[], + const opus_int16 PredCoef_Q12[2 * MAX_LPC_ORDER], + const opus_int16 LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR], + const opus_int16 AR_Q13[MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER], + const opus_int HarmShapeGain_Q14[MAX_NB_SUBFR], + const opus_int Tilt_Q14[MAX_NB_SUBFR], + const opus_int32 LF_shp_Q14[MAX_NB_SUBFR], + const opus_int32 Gains_Q16[MAX_NB_SUBFR], + const opus_int pitchL[MAX_NB_SUBFR], const opus_int Lambda_Q10, + const opus_int LTP_scale_Q14); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((void)(arch), \ + PRESUME_NEON(silk_NSQ_del_dec)( \ + psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, \ + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, \ + Lambda_Q10, LTP_scale_Q14)) +#endif +#endif + +#if !defined(OVERRIDE_silk_NSQ_del_dec) +/*Is run-time CPU detection enabled on this platform?*/ +#if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \ + !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, silk_nsq_state *NSQ, + SideInfoIndices *psIndices, const opus_int16 x16[], opus_int8 pulses[], + const opus_int16 PredCoef_Q12[2 * MAX_LPC_ORDER], + const opus_int16 LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR], + const opus_int16 AR_Q13[MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER], + const opus_int HarmShapeGain_Q14[MAX_NB_SUBFR], + const opus_int Tilt_Q14[MAX_NB_SUBFR], + const opus_int32 LF_shp_Q14[MAX_NB_SUBFR], + const opus_int32 Gains_Q16[MAX_NB_SUBFR], + const opus_int pitchL[MAX_NB_SUBFR], const opus_int Lambda_Q10, + const opus_int LTP_scale_Q14); +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((*SILK_NSQ_DEL_DEC_IMPL[(arch)&OPUS_ARCHMASK])( \ + psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, \ + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, \ + Lambda_Q10, LTP_scale_Q14)) +#elif defined(OPUS_ARM_PRESUME_NEON_INTR) +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((void)(arch), \ + silk_NSQ_del_dec_neon(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14)) +#endif +#endif + +#endif /* end SILK_NSQ_DEL_DEC_ARM_H */ diff --git a/native/codec/libraries/opus/silk/arm/NSQ_del_dec_neon_intr.c b/native/codec/libraries/opus/silk/arm/NSQ_del_dec_neon_intr.c new file mode 100644 index 0000000..212410f --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/NSQ_del_dec_neon_intr.c @@ -0,0 +1,1124 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +#endif +#include "main.h" +#include "stack_alloc.h" + +/* NEON intrinsics optimization now can only parallelize up to 4 delay decision states. */ +/* If there are more states, C function is called, and this optimization must be expanded. */ +#define NEON_MAX_DEL_DEC_STATES 4 + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RandState[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Q_Q10[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Xq_Q14[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Pred_Q15[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Shape_Q14[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LF_AR_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Diff_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Seed[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 SeedInit[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RD_Q10[ NEON_MAX_DEL_DEC_STATES ]; +} NSQ_del_decs_struct; + +typedef struct { + opus_int32 Q_Q10[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RD_Q10[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 xq_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LF_AR_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Diff_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 sLTP_shp_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LPC_exc_Q14[ NEON_MAX_DEL_DEC_STATES ]; +} NSQ_samples_struct; + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_neon( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +); + +static OPUS_INLINE void copy_winner_state_kernel( + const NSQ_del_decs_struct *psDelDec, + const opus_int offset, + const opus_int last_smple_idx, + const opus_int Winner_ind, + const int32x2_t gain_lo_s32x2, + const int32x2_t gain_hi_s32x2, + const int32x4_t shift_s32x4, + int32x4_t t0_s32x4, + int32x4_t t1_s32x4, + opus_int8 *const pulses, + opus_int16 *pxq, + silk_nsq_state *NSQ +) +{ + int16x8_t t_s16x8; + int32x4_t o0_s32x4, o1_s32x4; + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + t_s16x8 = vcombine_s16( vrshrn_n_s32( t0_s32x4, 10 ), vrshrn_n_s32( t1_s32x4, 10 ) ); + vst1_s8( &pulses[ offset ], vmovn_s16( t_s16x8 ) ); + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + o0_s32x4 = vqdmulhq_lane_s32( t0_s32x4, gain_lo_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( t1_s32x4, gain_lo_s32x2, 0 ); + o0_s32x4 = vmlaq_lane_s32( o0_s32x4, t0_s32x4, gain_hi_s32x2, 0 ); + o1_s32x4 = vmlaq_lane_s32( o1_s32x4, t1_s32x4, gain_hi_s32x2, 0 ); + o0_s32x4 = vrshlq_s32( o0_s32x4, shift_s32x4 ); + o1_s32x4 = vrshlq_s32( o1_s32x4, shift_s32x4 ); + vst1_s16( &pxq[ offset + 0 ], vqmovn_s32( o0_s32x4 ) ); + vst1_s16( &pxq[ offset + 4 ], vqmovn_s32( o1_s32x4 ) ); + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + vst1q_s32( &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx + offset + 0 ], t0_s32x4 ); + vst1q_s32( &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx + offset + 4 ], t1_s32x4 ); +} + +static OPUS_INLINE void copy_winner_state( + const NSQ_del_decs_struct *psDelDec, + const opus_int decisionDelay, + const opus_int smpl_buf_idx, + const opus_int Winner_ind, + const opus_int32 gain, + const opus_int32 shift, + opus_int8 *const pulses, + opus_int16 *pxq, + silk_nsq_state *NSQ +) +{ + opus_int i, last_smple_idx; + const int32x2_t gain_lo_s32x2 = vdup_n_s32( silk_LSHIFT32( gain & 0x0000FFFF, 15 ) ); + const int32x2_t gain_hi_s32x2 = vdup_n_s32( gain >> 16 ); + const int32x4_t shift_s32x4 = vdupq_n_s32( -shift ); + int32x4_t t0_s32x4, t1_s32x4; + + t0_s32x4 = t1_s32x4 = vdupq_n_s32( 0 ); /* initialization */ + last_smple_idx = smpl_buf_idx + decisionDelay - 1 + DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + + for( i = 0; ( i < ( decisionDelay - 7 ) ) && ( last_smple_idx >= 7 ); i += 8, last_smple_idx -= 8 ) { + copy_winner_state_kernel( psDelDec, i - decisionDelay, last_smple_idx, Winner_ind, gain_lo_s32x2, gain_hi_s32x2, shift_s32x4, t0_s32x4, t1_s32x4, pulses, pxq, NSQ ); + } + for( ; ( i < decisionDelay ) && ( last_smple_idx >= 0 ); i++, last_smple_idx-- ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], gain ), shift ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + } + + last_smple_idx += DECISION_DELAY; + for( ; i < ( decisionDelay - 7 ); i++, last_smple_idx-- ) { + copy_winner_state_kernel( psDelDec, i - decisionDelay, last_smple_idx, Winner_ind, gain_lo_s32x2, gain_hi_s32x2, shift_s32x4, t0_s32x4, t1_s32x4, pulses, pxq, NSQ ); + } + for( ; i < decisionDelay; i++, last_smple_idx-- ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], gain ), shift ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + } +} + +void silk_NSQ_del_dec_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ +#ifdef OPUS_CHECK_ASM + silk_nsq_state NSQ_c; + SideInfoIndices psIndices_c; + opus_int8 pulses_c[ MAX_FRAME_LENGTH ]; + const opus_int8 *const pulses_a = pulses; + + ( void )pulses_a; + silk_memcpy( &NSQ_c, NSQ, sizeof( NSQ_c ) ); + silk_memcpy( &psIndices_c, psIndices, sizeof( psIndices_c ) ); + silk_memcpy( pulses_c, pulses, sizeof( pulses_c ) ); + silk_NSQ_del_dec_c( psEncC, &NSQ_c, &psIndices_c, x16, pulses_c, PredCoef_Q12, LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, + pitchL, Lambda_Q10, LTP_scale_Q14 ); +#endif + + /* The optimization parallelizes the different delay decision states. */ + if(( psEncC->nStatesDelayedDecision > NEON_MAX_DEL_DEC_STATES ) || ( psEncC->nStatesDelayedDecision <= 2 )) { + /* NEON intrinsics optimization now can only parallelize up to 4 delay decision states. */ + /* If there are more states, C function is called, and this optimization must be expanded. */ + /* When the number of delay decision states is less than 3, there are penalties using this */ + /* optimization, and C function is called. */ + /* When the number of delay decision states is 2, it's better to specialize another */ + /* structure NSQ_del_dec2_struct and optimize with shorter NEON registers. (Low priority) */ + silk_NSQ_del_dec_c( psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, + Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14 ); + } else { + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_decs_struct, psDelDec ); + int32x4_t t_s32x4; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, 1, NSQ_del_decs_struct ); + /* Only RandState and RD_Q10 need to be initialized to 0. */ + silk_memset( psDelDec->RandState, 0, sizeof( psDelDec->RandState ) ); + vst1q_s32( psDelDec->RD_Q10, vdupq_n_s32( 0 ) ); + + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDelDec->SeedInit[ k ] = psDelDec->Seed[ k ] = ( k + psIndices->Seed ) & 3; + } + vst1q_s32( psDelDec->LF_AR_Q14, vld1q_dup_s32( &NSQ->sLF_AR_shp_Q14 ) ); + vst1q_s32( psDelDec->Diff_Q14, vld1q_dup_s32( &NSQ->sDiff_shp_Q14 ) ); + vst1q_s32( psDelDec->Shape_Q14[ 0 ], vld1q_dup_s32( &NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ] ) ); + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + vst1q_s32( psDelDec->sLPC_Q14[ i ], vld1q_dup_s32( &NSQ->sLPC_Q14[ i ] ) ); + } + for( i = 0; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) ); i++ ) { + vst1q_s32( psDelDec->sAR2_Q14[ i ], vld1q_dup_s32( &NSQ->sAR2_Q14[ i ] ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + opus_int pitch_min = pitchL[ 0 ]; + for( k = 1; k < psEncC->nb_subfr; k++ ) { + pitch_min = silk_min_int( pitch_min, pitchL[ k ] ); + } + decisionDelay = silk_min_int( decisionDelay, pitch_min - LTP_ORDER / 2 - 1 ); + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + int32x4_t RD_Q10_s32x4; + RDmin_Q10 = psDelDec->RD_Q10[ 0 ]; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec->RD_Q10[ i ] < RDmin_Q10 ) { + RDmin_Q10 = psDelDec->RD_Q10[ i ]; + Winner_ind = i; + } + } + psDelDec->RD_Q10[ Winner_ind ] -= ( silk_int32_MAX >> 4 ); + RD_Q10_s32x4 = vld1q_s32( psDelDec->RD_Q10 ); + RD_Q10_s32x4 = vaddq_s32( RD_Q10_s32x4, vdupq_n_s32( silk_int32_MAX >> 4 ) ); + vst1q_s32( psDelDec->RD_Q10, RD_Q10_s32x4 ); + + /* Copy final part of signals from winner state to output and long-term filter states */ + copy_winner_state( psDelDec, decisionDelay, smpl_buf_idx, Winner_ind, Gains_Q16[ 1 ], 14, pulses, pxq, NSQ ); + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states_neon( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k, + LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec_neon( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], + Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, + psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec->RD_Q10[ 0 ]; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec->RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psDelDec->RD_Q10[ k ]; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psIndices->Seed = psDelDec->SeedInit[ Winner_ind ]; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + copy_winner_state( psDelDec, decisionDelay, smpl_buf_idx, Winner_ind, Gain_Q10, 8, pulses, pxq, NSQ ); + + t_s32x4 = vdupq_n_s32( 0 ); /* initialization */ + for( i = 0; i < ( NSQ_LPC_BUF_LENGTH - 3 ); i += 4 ) { + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 0 ][ Winner_ind ], t_s32x4, 0 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 1 ][ Winner_ind ], t_s32x4, 1 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 2 ][ Winner_ind ], t_s32x4, 2 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 3 ][ Winner_ind ], t_s32x4, 3 ); + vst1q_s32( &NSQ->sLPC_Q14[ i ], t_s32x4 ); + } + + for( ; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = psDelDec->sLPC_Q14[ i ][ Winner_ind ]; + } + + for( i = 0; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) - 3 ); i += 4 ) { + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 0 ][ Winner_ind ], t_s32x4, 0 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 1 ][ Winner_ind ], t_s32x4, 1 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 2 ][ Winner_ind ], t_s32x4, 2 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 3 ][ Winner_ind ], t_s32x4, 3 ); + vst1q_s32( &NSQ->sAR2_Q14[ i ], t_s32x4 ); + } + + for( ; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) ); i++ ) { + NSQ->sAR2_Q14[ i ] = psDelDec->sAR2_Q14[ i ][ Winner_ind ]; + } + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDelDec->LF_AR_Q14[ Winner_ind ]; + NSQ->sDiff_shp_Q14 = psDelDec->Diff_Q14[ Winner_ind ]; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; + } + +#ifdef OPUS_CHECK_ASM + silk_assert( !memcmp( &NSQ_c, NSQ, sizeof( NSQ_c ) ) ); + silk_assert( !memcmp( &psIndices_c, psIndices, sizeof( psIndices_c ) ) ); + silk_assert( !memcmp( pulses_c, pulses_a, sizeof( pulses_c ) ) ); +#endif +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +/* Note: Function silk_short_prediction_create_arch_coef_neon() defined in NSQ_neon.h is actually a hacking C function. */ +/* Therefore here we append "_local" to the NEON function name to avoid confusion. */ +static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon_local(opus_int32 *out, const opus_int16 *in, opus_int order) +{ + int16x8_t t_s16x8; + int32x4_t t0_s32x4, t1_s32x4, t2_s32x4, t3_s32x4; + silk_assert( order == 10 || order == 16 ); + + t_s16x8 = vld1q_s16( in + 0 ); /* 7 6 5 4 3 2 1 0 */ + t_s16x8 = vrev64q_s16( t_s16x8 ); /* 4 5 6 7 0 1 2 3 */ + t2_s32x4 = vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ); /* 4 5 6 7 */ + t3_s32x4 = vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ); /* 0 1 2 3 */ + + if( order == 16 ) { + t_s16x8 = vld1q_s16( in + 8 ); /* F E D C B A 9 8 */ + t_s16x8 = vrev64q_s16( t_s16x8 ); /* C D E F 8 9 A B */ + t0_s32x4 = vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ); /* C D E F */ + t1_s32x4 = vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ); /* 8 9 A B */ + } else { + int16x4_t t_s16x4; + + t0_s32x4 = vdupq_n_s32( 0 ); /* zero zero zero zero */ + t_s16x4 = vld1_s16( in + 6 ); /* 9 8 7 6 */ + t_s16x4 = vrev64_s16( t_s16x4 ); /* 6 7 8 9 */ + t1_s32x4 = vshll_n_s16( t_s16x4, 15 ); + t1_s32x4 = vcombine_s32( vget_low_s32(t0_s32x4), vget_low_s32( t1_s32x4 ) ); /* 8 9 zero zero */ + } + vst1q_s32( out + 0, t0_s32x4 ); + vst1q_s32( out + 4, t1_s32x4 ); + vst1q_s32( out + 8, t2_s32x4 ); + vst1q_s32( out + 12, t3_s32x4 ); +} + +static OPUS_INLINE int32x4_t silk_SMLAWB_lane0_neon( + const int32x4_t out_s32x4, + const int32x4_t in_s32x4, + const int32x2_t coef_s32x2 +) +{ + return vaddq_s32( out_s32x4, vqdmulhq_lane_s32( in_s32x4, coef_s32x2, 0 ) ); +} + +static OPUS_INLINE int32x4_t silk_SMLAWB_lane1_neon( + const int32x4_t out_s32x4, + const int32x4_t in_s32x4, + const int32x2_t coef_s32x2 +) +{ + return vaddq_s32( out_s32x4, vqdmulhq_lane_s32( in_s32x4, coef_s32x2, 1 ) ); +} + +/* Note: This function has different return value than silk_noise_shape_quantizer_short_prediction_neon(). */ +/* Therefore here we append "_local" to the function name to avoid confusion. */ +static OPUS_INLINE int32x4_t silk_noise_shape_quantizer_short_prediction_neon_local(const opus_int32 *buf32, const opus_int32 *a_Q12_arch, opus_int order) +{ + const int32x4_t a_Q12_arch0_s32x4 = vld1q_s32( a_Q12_arch + 0 ); + const int32x4_t a_Q12_arch1_s32x4 = vld1q_s32( a_Q12_arch + 4 ); + const int32x4_t a_Q12_arch2_s32x4 = vld1q_s32( a_Q12_arch + 8 ); + const int32x4_t a_Q12_arch3_s32x4 = vld1q_s32( a_Q12_arch + 12 ); + int32x4_t LPC_pred_Q14_s32x4; + + silk_assert( order == 10 || order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q14_s32x4 = vdupq_n_s32( silk_RSHIFT( order, 1 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 0 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 1 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 2 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 3 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 4 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 5 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 6 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 7 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 8 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 9 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 10 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 11 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 12 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 13 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 14 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 15 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch3_s32x4 ) ); + + return LPC_pred_Q14_s32x4; +} + +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_neon( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, n_LTP_Q14; + opus_int32 RDmin_Q10, RDmax_Q10; + opus_int32 Gain_Q10; + opus_int32 *pred_lag_ptr, *shp_lag_ptr; + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; + const int32x2_t warping_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( warping_Q16, 16 ) >> 1 ); + const opus_int32 LF_shp_Q29 = silk_LSHIFT32( LF_shp_Q14, 16 ) >> 1; + opus_int32 AR_shp_Q28[ MAX_SHAPE_LPC_ORDER ]; + const uint32x4_t rand_multiplier_u32x4 = vdupq_n_u32( RAND_MULTIPLIER ); + const uint32x4_t rand_increment_u32x4 = vdupq_n_u32( RAND_INCREMENT ); + + VARDECL( NSQ_samples_struct, psSampleState ); + SAVE_STACK; + + silk_assert( nStatesDelayedDecision > 0 ); + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + ALLOC( psSampleState, 2, NSQ_samples_struct ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + for( i = 0; i < ( MAX_SHAPE_LPC_ORDER - 7 ); i += 8 ) { + const int16x8_t t_s16x8 = vld1q_s16( AR_shp_Q13 + i ); + vst1q_s32( AR_shp_Q28 + i + 0, vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ) ); + vst1q_s32( AR_shp_Q28 + i + 4, vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ) ); + } + + for( ; i < MAX_SHAPE_LPC_ORDER; i++ ) { + AR_shp_Q28[i] = silk_LSHIFT32( AR_shp_Q13[i], 15 ); + } + + silk_short_prediction_create_arch_coef_neon_local( a_Q12_arch, a_Q12, predictLPCOrder ); + + for( i = 0; i < length; i++ ) { + int32x4_t Seed_s32x4, LPC_pred_Q14_s32x4; + int32x4_t sign_s32x4, tmp1_s32x4, tmp2_s32x4; + int32x4_t n_AR_Q14_s32x4, n_LF_Q14_s32x4; + int32x2_t AR_shp_Q28_s32x2; + int16x4_t r_Q10_s16x4, rr_Q10_s16x4; + + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + /* Generate dither */ + Seed_s32x4 = vld1q_s32( psDelDec->Seed ); + Seed_s32x4 = vreinterpretq_s32_u32( vmlaq_u32( rand_increment_u32x4, vreinterpretq_u32_s32( Seed_s32x4 ), rand_multiplier_u32x4 ) ); + vst1q_s32( psDelDec->Seed, Seed_s32x4 ); + + /* Short-term prediction */ + LPC_pred_Q14_s32x4 = silk_noise_shape_quantizer_short_prediction_neon_local(psDelDec->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 16 + i ], a_Q12_arch, predictLPCOrder); + LPC_pred_Q14_s32x4 = vshlq_n_s32( LPC_pred_Q14_s32x4, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + /* Output of lowpass section */ + tmp2_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->Diff_Q14 ), vld1q_s32( psDelDec->sAR2_Q14[ 0 ] ), warping_Q16_s32x2 ); + /* Output of allpass section */ + tmp1_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ 1 ] ), tmp2_s32x4 ); + tmp1_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ 0 ] ), tmp1_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ 0 ], tmp2_s32x4 ); + AR_shp_Q28_s32x2 = vld1_s32( AR_shp_Q28 ); + n_AR_Q14_s32x4 = vaddq_s32( vdupq_n_s32( silk_RSHIFT( shapingLPCOrder, 1 ) ), vqdmulhq_lane_s32( tmp2_s32x4, AR_shp_Q28_s32x2, 0 ) ); + + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ j + 0 ] ), tmp1_s32x4 ); + tmp2_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ j - 1 ] ), tmp2_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ j - 1 ], tmp1_s32x4 ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp1_s32x4, AR_shp_Q28_s32x2, 1 ) ); + /* Output of allpass section */ + tmp1_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ j + 1 ] ), tmp2_s32x4 ); + tmp1_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ j + 0 ] ), tmp1_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ j + 0 ], tmp2_s32x4 ); + AR_shp_Q28_s32x2 = vld1_s32( &AR_shp_Q28[ j ] ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp2_s32x4, AR_shp_Q28_s32x2, 0 ) ); + } + vst1q_s32( psDelDec->sAR2_Q14[ shapingLPCOrder - 1 ], tmp1_s32x4 ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp1_s32x4, AR_shp_Q28_s32x2, 1 ) ); + n_AR_Q14_s32x4 = vshlq_n_s32( n_AR_Q14_s32x4, 1 ); /* Q11 -> Q12 */ + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_n_s32( vld1q_s32( psDelDec->LF_AR_Q14 ), silk_LSHIFT32( Tilt_Q14, 16 ) >> 1 ) ); /* Q12 */ + n_AR_Q14_s32x4 = vshlq_n_s32( n_AR_Q14_s32x4, 2 ); /* Q12 -> Q14 */ + n_LF_Q14_s32x4 = vqdmulhq_n_s32( vld1q_s32( psDelDec->Shape_Q14[ *smpl_buf_idx ] ), LF_shp_Q29 ); /* Q12 */ + n_LF_Q14_s32x4 = vaddq_s32( n_LF_Q14_s32x4, vqdmulhq_n_s32( vld1q_s32( psDelDec->LF_AR_Q14 ), silk_LSHIFT32( LF_shp_Q14 >> 16 , 15 ) ) ); /* Q12 */ + n_LF_Q14_s32x4 = vshlq_n_s32( n_LF_Q14_s32x4, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1_s32x4 = vaddq_s32( n_AR_Q14_s32x4, n_LF_Q14_s32x4 ); /* Q14 */ + tmp2_s32x4 = vaddq_s32( vdupq_n_s32( n_LTP_Q14 ), LPC_pred_Q14_s32x4 ); /* Q13 */ + tmp1_s32x4 = vsubq_s32( tmp2_s32x4, tmp1_s32x4 ); /* Q13 */ + tmp1_s32x4 = vrshrq_n_s32( tmp1_s32x4, 4 ); /* Q10 */ + tmp1_s32x4 = vsubq_s32( vdupq_n_s32( x_Q10[ i ] ), tmp1_s32x4 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + sign_s32x4 = vreinterpretq_s32_u32( vcltq_s32( Seed_s32x4, vdupq_n_s32( 0 ) ) ); + tmp1_s32x4 = veorq_s32( tmp1_s32x4, sign_s32x4 ); + tmp1_s32x4 = vsubq_s32( tmp1_s32x4, sign_s32x4 ); + tmp1_s32x4 = vmaxq_s32( tmp1_s32x4, vdupq_n_s32( -( 31 << 10 ) ) ); + tmp1_s32x4 = vminq_s32( tmp1_s32x4, vdupq_n_s32( 30 << 10 ) ); + r_Q10_s16x4 = vmovn_s32( tmp1_s32x4 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + { + int16x4_t q1_Q10_s16x4 = vsub_s16( r_Q10_s16x4, vdup_n_s16( offset_Q10 ) ); + int16x4_t q1_Q0_s16x4 = vshr_n_s16( q1_Q10_s16x4, 10 ); + int16x4_t q2_Q10_s16x4; + int32x4_t rd1_Q10_s32x4, rd2_Q10_s32x4; + uint32x4_t t_u32x4; + + if( Lambda_Q10 > 2048 ) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + const int rdo_offset = Lambda_Q10/2 - 512; + const uint16x4_t greaterThanRdo = vcgt_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ); + const uint16x4_t lessThanMinusRdo = vclt_s16( q1_Q10_s16x4, vdup_n_s16( -rdo_offset ) ); + /* If Lambda_Q10 > 32767, then q1_Q0, q1_Q10 and q2_Q10 must change to 32-bit. */ + silk_assert( Lambda_Q10 <= 32767 ); + + q1_Q0_s16x4 = vreinterpret_s16_u16( vclt_s16( q1_Q10_s16x4, vdup_n_s16( 0 ) ) ); + q1_Q0_s16x4 = vbsl_s16( greaterThanRdo, vsub_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ), q1_Q0_s16x4 ); + q1_Q0_s16x4 = vbsl_s16( lessThanMinusRdo, vadd_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ), q1_Q0_s16x4 ); + q1_Q0_s16x4 = vshr_n_s16( q1_Q0_s16x4, 10 ); + } + { + const uint16x4_t equal0_u16x4 = vceq_s16( q1_Q0_s16x4, vdup_n_s16( 0 ) ); + const uint16x4_t equalMinus1_u16x4 = vceq_s16( q1_Q0_s16x4, vdup_n_s16( -1 ) ); + const uint16x4_t lessThanMinus1_u16x4 = vclt_s16( q1_Q0_s16x4, vdup_n_s16( -1 ) ); + int16x4_t tmp1_s16x4, tmp2_s16x4; + + q1_Q10_s16x4 = vshl_n_s16( q1_Q0_s16x4, 10 ); + tmp1_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( offset_Q10 - QUANT_LEVEL_ADJUST_Q10 ) ); + q1_Q10_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( offset_Q10 + QUANT_LEVEL_ADJUST_Q10 ) ); + q1_Q10_s16x4 = vbsl_s16( lessThanMinus1_u16x4, q1_Q10_s16x4, tmp1_s16x4 ); + q1_Q10_s16x4 = vbsl_s16( equal0_u16x4, vdup_n_s16( offset_Q10 ), q1_Q10_s16x4 ); + q1_Q10_s16x4 = vbsl_s16( equalMinus1_u16x4, vdup_n_s16( offset_Q10 - ( 1024 - QUANT_LEVEL_ADJUST_Q10 ) ), q1_Q10_s16x4 ); + q2_Q10_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( 1024 ) ); + q2_Q10_s16x4 = vbsl_s16( equal0_u16x4, vdup_n_s16( offset_Q10 + 1024 - QUANT_LEVEL_ADJUST_Q10 ), q2_Q10_s16x4 ); + q2_Q10_s16x4 = vbsl_s16( equalMinus1_u16x4, vdup_n_s16( offset_Q10 ), q2_Q10_s16x4 ); + tmp1_s16x4 = q1_Q10_s16x4; + tmp2_s16x4 = q2_Q10_s16x4; + tmp1_s16x4 = vbsl_s16( vorr_u16( equalMinus1_u16x4, lessThanMinus1_u16x4 ), vneg_s16( tmp1_s16x4 ), tmp1_s16x4 ); + tmp2_s16x4 = vbsl_s16( lessThanMinus1_u16x4, vneg_s16( tmp2_s16x4 ), tmp2_s16x4 ); + rd1_Q10_s32x4 = vmull_s16( tmp1_s16x4, vdup_n_s16( Lambda_Q10 ) ); + rd2_Q10_s32x4 = vmull_s16( tmp2_s16x4, vdup_n_s16( Lambda_Q10 ) ); + } + + rr_Q10_s16x4 = vsub_s16( r_Q10_s16x4, q1_Q10_s16x4 ); + rd1_Q10_s32x4 = vmlal_s16( rd1_Q10_s32x4, rr_Q10_s16x4, rr_Q10_s16x4 ); + rd1_Q10_s32x4 = vshrq_n_s32( rd1_Q10_s32x4, 10 ); + + rr_Q10_s16x4 = vsub_s16( r_Q10_s16x4, q2_Q10_s16x4 ); + rd2_Q10_s32x4 = vmlal_s16( rd2_Q10_s32x4, rr_Q10_s16x4, rr_Q10_s16x4 ); + rd2_Q10_s32x4 = vshrq_n_s32( rd2_Q10_s32x4, 10 ); + + tmp2_s32x4 = vld1q_s32( psDelDec->RD_Q10 ); + tmp1_s32x4 = vaddq_s32( tmp2_s32x4, vminq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ) ); + tmp2_s32x4 = vaddq_s32( tmp2_s32x4, vmaxq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ) ); + vst1q_s32( psSampleState[ 0 ].RD_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].RD_Q10, tmp2_s32x4 ); + t_u32x4 = vcltq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ); + tmp1_s32x4 = vbslq_s32( t_u32x4, vmovl_s16( q1_Q10_s16x4 ), vmovl_s16( q2_Q10_s16x4 ) ); + tmp2_s32x4 = vbslq_s32( t_u32x4, vmovl_s16( q2_Q10_s16x4 ), vmovl_s16( q1_Q10_s16x4 ) ); + vst1q_s32( psSampleState[ 0 ].Q_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].Q_Q10, tmp2_s32x4 ); + } + + { + /* Update states for best quantization */ + int32x4_t exc_Q14_s32x4, LPC_exc_Q14_s32x4, xq_Q14_s32x4, sLF_AR_shp_Q14_s32x4; + + /* Quantized excitation */ + exc_Q14_s32x4 = vshlq_n_s32( tmp1_s32x4, 4 ); + exc_Q14_s32x4 = veorq_s32( exc_Q14_s32x4, sign_s32x4 ); + exc_Q14_s32x4 = vsubq_s32( exc_Q14_s32x4, sign_s32x4 ); + + /* Add predictions */ + LPC_exc_Q14_s32x4 = vaddq_s32( exc_Q14_s32x4, vdupq_n_s32( LTP_pred_Q14 ) ); + xq_Q14_s32x4 = vaddq_s32( LPC_exc_Q14_s32x4, LPC_pred_Q14_s32x4 ); + + /* Update states */ + tmp1_s32x4 = vsubq_s32( xq_Q14_s32x4, vshlq_n_s32( vdupq_n_s32( x_Q10[ i ] ), 4 ) ); + vst1q_s32( psSampleState[ 0 ].Diff_Q14, tmp1_s32x4 ); + sLF_AR_shp_Q14_s32x4 = vsubq_s32( tmp1_s32x4, n_AR_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].sLTP_shp_Q14, vsubq_s32( sLF_AR_shp_Q14_s32x4, n_LF_Q14_s32x4 ) ); + vst1q_s32( psSampleState[ 0 ].LF_AR_Q14, sLF_AR_shp_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].LPC_exc_Q14, LPC_exc_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].xq_Q14, xq_Q14_s32x4 ); + + /* Quantized excitation */ + exc_Q14_s32x4 = vshlq_n_s32( tmp2_s32x4, 4 ); + exc_Q14_s32x4 = veorq_s32( exc_Q14_s32x4, sign_s32x4 ); + exc_Q14_s32x4 = vsubq_s32( exc_Q14_s32x4, sign_s32x4 ); + + /* Add predictions */ + LPC_exc_Q14_s32x4 = vaddq_s32( exc_Q14_s32x4, vdupq_n_s32( LTP_pred_Q14 ) ); + xq_Q14_s32x4 = vaddq_s32( LPC_exc_Q14_s32x4, LPC_pred_Q14_s32x4 ); + + /* Update states */ + tmp1_s32x4 = vsubq_s32( xq_Q14_s32x4, vshlq_n_s32( vdupq_n_s32( x_Q10[ i ] ), 4 ) ); + vst1q_s32( psSampleState[ 1 ].Diff_Q14, tmp1_s32x4 ); + sLF_AR_shp_Q14_s32x4 = vsubq_s32( tmp1_s32x4, n_AR_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].sLTP_shp_Q14, vsubq_s32( sLF_AR_shp_Q14_s32x4, n_LF_Q14_s32x4 ) ); + vst1q_s32( psSampleState[ 1 ].LF_AR_Q14, sLF_AR_shp_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].LPC_exc_Q14, LPC_exc_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].xq_Q14, xq_Q14_s32x4 ); + } + + *smpl_buf_idx = *smpl_buf_idx ? ( *smpl_buf_idx - 1 ) : ( DECISION_DELAY - 1); + last_smple_idx = *smpl_buf_idx + decisionDelay + DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ].RD_Q10[ 0 ]; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ 0 ].RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ 0 ].RD_Q10[ k ]; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + { + uint32x4_t t_u32x4; + Winner_rand_state = psDelDec->RandState[ last_smple_idx ][ Winner_ind ]; + t_u32x4 = vceqq_s32( vld1q_s32( psDelDec->RandState[ last_smple_idx ] ), vdupq_n_s32( Winner_rand_state ) ); + t_u32x4 = vmvnq_u32( t_u32x4 ); + t_u32x4 = vshrq_n_u32( t_u32x4, 5 ); + tmp1_s32x4 = vld1q_s32( psSampleState[ 0 ].RD_Q10 ); + tmp2_s32x4 = vld1q_s32( psSampleState[ 1 ].RD_Q10 ); + tmp1_s32x4 = vaddq_s32( tmp1_s32x4, vreinterpretq_s32_u32( t_u32x4 ) ); + tmp2_s32x4 = vaddq_s32( tmp2_s32x4, vreinterpretq_s32_u32( t_u32x4 ) ); + vst1q_s32( psSampleState[ 0 ].RD_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].RD_Q10, tmp2_s32x4 ); + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ].RD_Q10[ 0 ]; + RDmin_Q10 = psSampleState[ 1 ].RD_Q10[ 0 ]; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ 0 ].RD_Q10[ k ] > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ 0 ].RD_Q10[ k ]; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ 1 ].RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ 1 ].RD_Q10[ k ]; + RDmin_ind = k; + } + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + opus_int32 (*ptr)[NEON_MAX_DEL_DEC_STATES] = psDelDec->RandState; + const int numOthers = (int)( ( sizeof( NSQ_del_decs_struct ) - sizeof( ( (NSQ_del_decs_struct *)0 )->sLPC_Q14 ) ) + / ( NEON_MAX_DEL_DEC_STATES * sizeof( opus_int32 ) ) ); + /* Only ( predictLPCOrder - 1 ) of sLPC_Q14 buffer need to be updated, though the first several */ + /* useless sLPC_Q14[] will be different comparing with C when predictLPCOrder < NSQ_LPC_BUF_LENGTH. */ + /* Here just update constant ( NSQ_LPC_BUF_LENGTH - 1 ) for simplicity. */ + for( j = i + 1; j < i + NSQ_LPC_BUF_LENGTH; j++ ) { + psDelDec->sLPC_Q14[ j ][ RDmax_ind ] = psDelDec->sLPC_Q14[ j ][ RDmin_ind ]; + } + for( j = 0; j < numOthers; j++ ) { + ptr[ j ][ RDmax_ind ] = ptr[ j ][ RDmin_ind ]; + } + + psSampleState[ 0 ].Q_Q10[ RDmax_ind ] = psSampleState[ 1 ].Q_Q10[ RDmin_ind ]; + psSampleState[ 0 ].RD_Q10[ RDmax_ind ] = psSampleState[ 1 ].RD_Q10[ RDmin_ind ]; + psSampleState[ 0 ].xq_Q14[ RDmax_ind ] = psSampleState[ 1 ].xq_Q14[ RDmin_ind ]; + psSampleState[ 0 ].LF_AR_Q14[ RDmax_ind ] = psSampleState[ 1 ].LF_AR_Q14[ RDmin_ind ]; + psSampleState[ 0 ].Diff_Q14[ RDmax_ind ] = psSampleState[ 1 ].Diff_Q14[ RDmin_ind ]; + psSampleState[ 0 ].sLTP_shp_Q14[ RDmax_ind ] = psSampleState[ 1 ].sLTP_shp_Q14[ RDmin_ind ]; + psSampleState[ 0 ].LPC_exc_Q14[ RDmax_ind ] = psSampleState[ 1 ].LPC_exc_Q14[ RDmin_ind ]; + } + + /* Write samples from winner to output and long-term filter states */ + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDelDec->Pred_Q15[ last_smple_idx ][ Winner_ind ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + vst1q_s32( psDelDec->LF_AR_Q14, vld1q_s32( psSampleState[ 0 ].LF_AR_Q14 ) ); + vst1q_s32( psDelDec->Diff_Q14, vld1q_s32( psSampleState[ 0 ].Diff_Q14 ) ); + vst1q_s32( psDelDec->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ], vld1q_s32( psSampleState[ 0 ].xq_Q14 ) ); + vst1q_s32( psDelDec->Xq_Q14[ *smpl_buf_idx ], vld1q_s32( psSampleState[ 0 ].xq_Q14 ) ); + tmp1_s32x4 = vld1q_s32( psSampleState[ 0 ].Q_Q10 ); + vst1q_s32( psDelDec->Q_Q10[ *smpl_buf_idx ], tmp1_s32x4 ); + vst1q_s32( psDelDec->Pred_Q15[ *smpl_buf_idx ], vshlq_n_s32( vld1q_s32( psSampleState[ 0 ].LPC_exc_Q14 ), 1 ) ); + vst1q_s32( psDelDec->Shape_Q14[ *smpl_buf_idx ], vld1q_s32( psSampleState[ 0 ].sLTP_shp_Q14 ) ); + tmp1_s32x4 = vrshrq_n_s32( tmp1_s32x4, 10 ); + tmp1_s32x4 = vaddq_s32( vld1q_s32( psDelDec->Seed ), tmp1_s32x4 ); + vst1q_s32( psDelDec->Seed, tmp1_s32x4 ); + vst1q_s32( psDelDec->RandState[ *smpl_buf_idx ], tmp1_s32x4 ); + vst1q_s32( psDelDec->RD_Q10, vld1q_s32( psSampleState[ 0 ].RD_Q10 ) ); + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + silk_memcpy( psDelDec->sLPC_Q14[ 0 ], psDelDec->sLPC_Q14[ length ], NEON_MAX_DEL_DEC_STATES * NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + + RESTORE_STACK; +} + +static OPUS_INLINE void silk_SMULWB_8_neon( + const opus_int16 *a, + const int32x2_t b, + opus_int32 *o +) +{ + const int16x8_t a_s16x8 = vld1q_s16( a ); + int32x4_t o0_s32x4, o1_s32x4; + + o0_s32x4 = vshll_n_s16( vget_low_s16( a_s16x8 ), 15 ); + o1_s32x4 = vshll_n_s16( vget_high_s16( a_s16x8 ), 15 ); + o0_s32x4 = vqdmulhq_lane_s32( o0_s32x4, b, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( o1_s32x4, b, 0 ); + vst1q_s32( o, o0_s32x4 ); + vst1q_s32( o + 4, o1_s32x4 ); +} + +/* Only works when ( b >= -65536 ) && ( b < 65536 ). */ +static OPUS_INLINE void silk_SMULWW_small_b_4_neon( + opus_int32 *a, + const int32x2_t b_s32x2) +{ + int32x4_t o_s32x4; + + o_s32x4 = vld1q_s32( a ); + o_s32x4 = vqdmulhq_lane_s32( o_s32x4, b_s32x2, 0 ); + vst1q_s32( a, o_s32x4 ); +} + +/* Only works when ( b >= -65536 ) && ( b < 65536 ). */ +static OPUS_INLINE void silk_SMULWW_small_b_8_neon( + opus_int32 *a, + const int32x2_t b_s32x2 +) +{ + int32x4_t o0_s32x4, o1_s32x4; + + o0_s32x4 = vld1q_s32( a ); + o1_s32x4 = vld1q_s32( a + 4 ); + o0_s32x4 = vqdmulhq_lane_s32( o0_s32x4, b_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( o1_s32x4, b_s32x2, 0 ); + vst1q_s32( a, o0_s32x4 ); + vst1q_s32( a + 4, o1_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_4_neon( + opus_int32 *a, + const int32x2_t b_s32x2) +{ + int32x4_t a_s32x4, o_s32x4; + + a_s32x4 = vld1q_s32( a ); + o_s32x4 = vqdmulhq_lane_s32( a_s32x4, b_s32x2, 0 ); + o_s32x4 = vmlaq_lane_s32( o_s32x4, a_s32x4, b_s32x2, 1 ); + vst1q_s32( a, o_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_8_neon( + opus_int32 *a, + const int32x2_t b_s32x2 +) +{ + int32x4_t a0_s32x4, a1_s32x4, o0_s32x4, o1_s32x4; + + a0_s32x4 = vld1q_s32( a ); + a1_s32x4 = vld1q_s32( a + 4 ); + o0_s32x4 = vqdmulhq_lane_s32( a0_s32x4, b_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( a1_s32x4, b_s32x2, 0 ); + o0_s32x4 = vmlaq_lane_s32( o0_s32x4, a0_s32x4, b_s32x2, 1 ); + o1_s32x4 = vmlaq_lane_s32( o1_s32x4, a1_s32x4, b_s32x2, 1 ); + vst1q_s32( a, o0_s32x4 ); + vst1q_s32( a + 4, o1_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_loop_neon( + const opus_int16 *a, + const opus_int32 b, + opus_int32 *o, + const opus_int loop_num +) +{ + opus_int i; + int32x2_t b_s32x2; + + b_s32x2 = vdup_n_s32( b ); + for( i = 0; i < loop_num - 7; i += 8 ) { + silk_SMULWB_8_neon( a + i, b_s32x2, o + i ); + } + for( ; i < loop_num; i++ ) { + o[ i ] = silk_SMULWW( a[ i ], b ); + } +} + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + silk_SMULWW_loop_neon( x16, inv_gain_Q26, x_sc_Q10, psEncC->subfr_length ); + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + silk_SMULWW_loop_neon( sLTP + NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2, inv_gain_Q31, sLTP_Q15 + NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2, lag + LTP_ORDER / 2 ); + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + int32x2_t gain_adj_Q16_s32x2; + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + if( ( gain_adj_Q16 >= -65536 ) && ( gain_adj_Q16 < 65536 ) ) { + gain_adj_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( gain_adj_Q16, 15 ) ); + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 7; i += 8 ) { + silk_SMULWW_small_b_8_neon( NSQ->sLTP_shp_Q14 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay - 7; i += 8 ) { + silk_SMULWW_small_b_8_neon( sLTP_Q15 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + /* Scale scalar states */ + silk_SMULWW_small_b_4_neon( psDelDec->LF_AR_Q14, gain_adj_Q16_s32x2 ); + silk_SMULWW_small_b_4_neon( psDelDec->Diff_Q14, gain_adj_Q16_s32x2 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->sLPC_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->sAR2_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < DECISION_DELAY; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->Pred_Q15[ i ], gain_adj_Q16_s32x2 ); + silk_SMULWW_small_b_4_neon( psDelDec->Shape_Q14[ i ], gain_adj_Q16_s32x2 ); + } + } else { + gain_adj_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( gain_adj_Q16 & 0x0000FFFF, 15 ) ); + gain_adj_Q16_s32x2 = vset_lane_s32( gain_adj_Q16 >> 16, gain_adj_Q16_s32x2, 1 ); + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 7; i += 8 ) { + silk_SMULWW_8_neon( NSQ->sLTP_shp_Q14 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay - 7; i += 8 ) { + silk_SMULWW_8_neon( sLTP_Q15 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + /* Scale scalar states */ + silk_SMULWW_4_neon( psDelDec->LF_AR_Q14, gain_adj_Q16_s32x2 ); + silk_SMULWW_4_neon( psDelDec->Diff_Q14, gain_adj_Q16_s32x2 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + silk_SMULWW_4_neon( psDelDec->sLPC_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + silk_SMULWW_4_neon( psDelDec->sAR2_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < DECISION_DELAY; i++ ) { + silk_SMULWW_4_neon( psDelDec->Pred_Q15[ i ], gain_adj_Q16_s32x2 ); + silk_SMULWW_4_neon( psDelDec->Shape_Q14[ i ], gain_adj_Q16_s32x2 ); + } + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/native/codec/libraries/opus/silk/arm/NSQ_neon.c b/native/codec/libraries/opus/silk/arm/NSQ_neon.c new file mode 100644 index 0000000..9642529 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/NSQ_neon.c @@ -0,0 +1,112 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" +#include "celt/cpu_support.h" +#include "celt/arm/armcpu.h" + +opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order) +{ + int32x4_t coef0 = vld1q_s32(coef32); + int32x4_t coef1 = vld1q_s32(coef32 + 4); + int32x4_t coef2 = vld1q_s32(coef32 + 8); + int32x4_t coef3 = vld1q_s32(coef32 + 12); + + int32x4_t a0 = vld1q_s32(buf32 - 15); + int32x4_t a1 = vld1q_s32(buf32 - 11); + int32x4_t a2 = vld1q_s32(buf32 - 7); + int32x4_t a3 = vld1q_s32(buf32 - 3); + + int32x4_t b0 = vqdmulhq_s32(coef0, a0); + int32x4_t b1 = vqdmulhq_s32(coef1, a1); + int32x4_t b2 = vqdmulhq_s32(coef2, a2); + int32x4_t b3 = vqdmulhq_s32(coef3, a3); + + int32x4_t c0 = vaddq_s32(b0, b1); + int32x4_t c1 = vaddq_s32(b2, b3); + + int32x4_t d = vaddq_s32(c0, c1); + + int64x2_t e = vpaddlq_s32(d); + + int64x1_t f = vadd_s64(vget_low_s64(e), vget_high_s64(e)); + + opus_int32 out = vget_lane_s32(vreinterpret_s32_s64(f), 0); + + out += silk_RSHIFT( order, 1 ); + + return out; +} + + +opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order) +{ + opus_int32 out; + if (order == 8) + { + int32x4_t a00 = vdupq_n_s32(data0[0]); + int32x4_t a01 = vld1q_s32(data1); /* data1[0] ... [3] */ + + int32x4_t a0 = vextq_s32 (a00, a01, 3); /* data0[0] data1[0] ...[2] */ + int32x4_t a1 = vld1q_s32(data1 + 3); /* data1[3] ... [6] */ + + /*TODO: Convert these once in advance instead of once per sample, like + silk_noise_shape_quantizer_short_prediction_neon() does.*/ + int16x8_t coef16 = vld1q_s16(coef); + int32x4_t coef0 = vmovl_s16(vget_low_s16(coef16)); + int32x4_t coef1 = vmovl_s16(vget_high_s16(coef16)); + + /*This is not bit-exact with the C version, since we do not drop the + lower 16 bits of each multiply, but wait until the end to truncate + precision. This is an encoder-specific calculation (and unlike + silk_noise_shape_quantizer_short_prediction_neon(), is not meant to + simulate what the decoder will do). We still could use vqdmulhq_s32() + like silk_noise_shape_quantizer_short_prediction_neon() and save + half the multiplies, but the speed difference is not large, since we + then need two extra adds.*/ + int64x2_t b0 = vmull_s32(vget_low_s32(a0), vget_low_s32(coef0)); + int64x2_t b1 = vmlal_s32(b0, vget_high_s32(a0), vget_high_s32(coef0)); + int64x2_t b2 = vmlal_s32(b1, vget_low_s32(a1), vget_low_s32(coef1)); + int64x2_t b3 = vmlal_s32(b2, vget_high_s32(a1), vget_high_s32(coef1)); + + int64x1_t c = vadd_s64(vget_low_s64(b3), vget_high_s64(b3)); + int64x1_t cS = vrshr_n_s64(c, 15); + int32x2_t d = vreinterpret_s32_s64(cS); + + out = vget_lane_s32(d, 0); + vst1q_s32(data1, a0); + vst1q_s32(data1 + 4, a1); + return out; + } + return silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order); +} diff --git a/native/codec/libraries/opus/silk/arm/NSQ_neon.h b/native/codec/libraries/opus/silk/arm/NSQ_neon.h new file mode 100644 index 0000000..b31d944 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/NSQ_neon.h @@ -0,0 +1,114 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ +#ifndef SILK_NSQ_NEON_H +#define SILK_NSQ_NEON_H + +#include "cpu_support.h" +#include "SigProc_FIX.h" + +#undef silk_short_prediction_create_arch_coef +/* For vectorized calc, reverse a_Q12 coefs, convert to 32-bit, and shift for vqdmulhq_s32. */ +static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon(opus_int32 *out, const opus_int16 *in, opus_int order) +{ + out[15] = silk_LSHIFT32(in[0], 15); + out[14] = silk_LSHIFT32(in[1], 15); + out[13] = silk_LSHIFT32(in[2], 15); + out[12] = silk_LSHIFT32(in[3], 15); + out[11] = silk_LSHIFT32(in[4], 15); + out[10] = silk_LSHIFT32(in[5], 15); + out[9] = silk_LSHIFT32(in[6], 15); + out[8] = silk_LSHIFT32(in[7], 15); + out[7] = silk_LSHIFT32(in[8], 15); + out[6] = silk_LSHIFT32(in[9], 15); + + if (order == 16) + { + out[5] = silk_LSHIFT32(in[10], 15); + out[4] = silk_LSHIFT32(in[11], 15); + out[3] = silk_LSHIFT32(in[12], 15); + out[2] = silk_LSHIFT32(in[13], 15); + out[1] = silk_LSHIFT32(in[14], 15); + out[0] = silk_LSHIFT32(in[15], 15); + } + else + { + out[5] = 0; + out[4] = 0; + out[3] = 0; + out[2] = 0; + out[1] = 0; + out[0] = 0; + } +} + +#if defined(OPUS_ARM_PRESUME_NEON_INTR) + +#define silk_short_prediction_create_arch_coef(out, in, order) \ + (silk_short_prediction_create_arch_coef_neon(out, in, order)) + +#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + +#define silk_short_prediction_create_arch_coef(out, in, order) \ + do { if (arch == OPUS_ARCH_ARM_NEON) { silk_short_prediction_create_arch_coef_neon(out, in, order); } } while (0) + +#endif + +opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order); + +opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order); + +#if defined(OPUS_ARM_PRESUME_NEON_INTR) +#undef silk_noise_shape_quantizer_short_prediction +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \ + ((void)arch,silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order)) + +#undef silk_NSQ_noise_shape_feedback_loop +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_neon(data0, data1, coef, order)) + +#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + +/* silk_noise_shape_quantizer_short_prediction implementations take different parameters based on arch + (coef vs. coefRev) so can't use the usual IMPL table implementation */ +#undef silk_noise_shape_quantizer_short_prediction +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \ + (arch == OPUS_ARCH_ARM_NEON ? \ + silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order) : \ + silk_noise_shape_quantizer_short_prediction_c(in, coef, order)) + +extern opus_int32 + (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])( + const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, + opus_int order); + +#undef silk_NSQ_noise_shape_feedback_loop +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) \ + (SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[(arch)&OPUS_ARCHMASK](data0, data1, \ + coef, order)) + +#endif + +#endif /* SILK_NSQ_NEON_H */ diff --git a/native/codec/libraries/opus/silk/arm/SigProc_FIX_armv4.h b/native/codec/libraries/opus/silk/arm/SigProc_FIX_armv4.h new file mode 100644 index 0000000..ff62b1e --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/SigProc_FIX_armv4.h @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (C) 2013 Xiph.Org Foundation and contributors +Copyright (c) 2013 Parrot +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_ARMv4_H +#define SILK_SIGPROC_FIX_ARMv4_H + +#undef silk_MLA +static OPUS_INLINE opus_int32 silk_MLA_armv4(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + opus_int32 res; + __asm__( + "#silk_MLA\n\t" + "mla %0, %1, %2, %3\n\t" + : "=&r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_MLA(a, b, c) (silk_MLA_armv4(a, b, c)) + +#endif diff --git a/native/codec/libraries/opus/silk/arm/SigProc_FIX_armv5e.h b/native/codec/libraries/opus/silk/arm/SigProc_FIX_armv5e.h new file mode 100644 index 0000000..617a09c --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/SigProc_FIX_armv5e.h @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (c) 2013 Parrot +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_ARMv5E_H +#define SILK_SIGPROC_FIX_ARMv5E_H + +#undef silk_SMULTT +static OPUS_INLINE opus_int32 silk_SMULTT_armv5e(opus_int32 a, opus_int32 b) +{ + opus_int32 res; + __asm__( + "#silk_SMULTT\n\t" + "smultt %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_SMULTT(a, b) (silk_SMULTT_armv5e(a, b)) + +#undef silk_SMLATT +static OPUS_INLINE opus_int32 silk_SMLATT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + opus_int32 res; + __asm__( + "#silk_SMLATT\n\t" + "smlatt %0, %1, %2, %3\n\t" + : "=r"(res) + : "%r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLATT(a, b, c) (silk_SMLATT_armv5e(a, b, c)) + +#endif diff --git a/native/codec/libraries/opus/silk/arm/arm_silk_map.c b/native/codec/libraries/opus/silk/arm/arm_silk_map.c new file mode 100644 index 0000000..0b9bfec --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/arm_silk_map.c @@ -0,0 +1,123 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "main_FIX.h" +#include "NSQ.h" +#include "SigProc_FIX.h" + +#if defined(OPUS_HAVE_RTCD) + +# if (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \ + !defined(OPUS_ARM_PRESUME_NEON_INTR)) + +void (*const SILK_BIQUAD_ALT_STRIDE2_IMPL[OPUS_ARCHMASK + 1])( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) = { + silk_biquad_alt_stride2_c, /* ARMv4 */ + silk_biquad_alt_stride2_c, /* EDSP */ + silk_biquad_alt_stride2_c, /* Media */ + silk_biquad_alt_stride2_neon, /* Neon */ +}; + +opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK + 1])( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) = { + silk_LPC_inverse_pred_gain_c, /* ARMv4 */ + silk_LPC_inverse_pred_gain_c, /* EDSP */ + silk_LPC_inverse_pred_gain_c, /* Media */ + silk_LPC_inverse_pred_gain_neon, /* Neon */ +}; + +void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_del_dec_c, /* ARMv4 */ + silk_NSQ_del_dec_c, /* EDSP */ + silk_NSQ_del_dec_c, /* Media */ + silk_NSQ_del_dec_neon, /* Neon */ +}; + +/*There is no table for silk_noise_shape_quantizer_short_prediction because the + NEON version takes different parameters than the C version. + Instead RTCD is done via if statements at the call sites. + See NSQ_neon.h for details.*/ + +opus_int32 + (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])( + const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, + opus_int order) = { + silk_NSQ_noise_shape_feedback_loop_c, /* ARMv4 */ + silk_NSQ_noise_shape_feedback_loop_c, /* EDSP */ + silk_NSQ_noise_shape_feedback_loop_c, /* Media */ + silk_NSQ_noise_shape_feedback_loop_neon, /* NEON */ +}; + +# endif + +# if defined(FIXED_POINT) && \ + defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) + +void (*const SILK_WARPED_AUTOCORRELATION_FIX_IMPL[OPUS_ARCHMASK + 1])( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) = { + silk_warped_autocorrelation_FIX_c, /* ARMv4 */ + silk_warped_autocorrelation_FIX_c, /* EDSP */ + silk_warped_autocorrelation_FIX_c, /* Media */ + silk_warped_autocorrelation_FIX_neon, /* Neon */ +}; + +# endif + +#endif /* OPUS_HAVE_RTCD */ diff --git a/native/codec/libraries/opus/silk/arm/biquad_alt_arm.h b/native/codec/libraries/opus/silk/arm/biquad_alt_arm.h new file mode 100644 index 0000000..66ea9f4 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/biquad_alt_arm.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_BIQUAD_ALT_ARM_H +# define SILK_BIQUAD_ALT_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_biquad_alt_stride2_neon( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), PRESUME_NEON(silk_biquad_alt_stride2)(in, B_Q28, A_Q28, S, out, len)) +# endif +# endif + +# if !defined(OVERRIDE_silk_biquad_alt_stride2) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_BIQUAD_ALT_STRIDE2_IMPL[OPUS_ARCHMASK+1])( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ + ); +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((*SILK_BIQUAD_ALT_STRIDE2_IMPL[(arch)&OPUS_ARCHMASK])(in, B_Q28, A_Q28, S, out, len)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_neon(in, B_Q28, A_Q28, S, out, len)) +# endif +# endif + +#endif /* end SILK_BIQUAD_ALT_ARM_H */ diff --git a/native/codec/libraries/opus/silk/arm/biquad_alt_neon_intr.c b/native/codec/libraries/opus/silk/arm/biquad_alt_neon_intr.c new file mode 100644 index 0000000..9715733 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/biquad_alt_neon_intr.c @@ -0,0 +1,156 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +# include "stack_alloc.h" +#endif +#include "SigProc_FIX.h" + +static inline void silk_biquad_alt_stride2_kernel( const int32x4_t A_L_s32x4, const int32x4_t A_U_s32x4, const int32x4_t B_Q28_s32x4, const int32x2_t t_s32x2, const int32x4_t in_s32x4, int32x4_t *S_s32x4, int32x2_t *out32_Q14_s32x2 ) +{ + int32x4_t t_s32x4, out32_Q14_s32x4; + + *out32_Q14_s32x2 = vadd_s32( vget_low_s32( *S_s32x4 ), t_s32x2 ); /* silk_SMLAWB( S{0,1}, B_Q28[ 0 ], in{0,1} ) */ + *S_s32x4 = vcombine_s32( vget_high_s32( *S_s32x4 ), vdup_n_s32( 0 ) ); /* S{0,1} = S{2,3}; S{2,3} = 0; */ + *out32_Q14_s32x2 = vshl_n_s32( *out32_Q14_s32x2, 2 ); /* out32_Q14_{0,1} = silk_LSHIFT( silk_SMLAWB( S{0,1}, B_Q28[ 0 ], in{0,1} ), 2 ); */ + out32_Q14_s32x4 = vcombine_s32( *out32_Q14_s32x2, *out32_Q14_s32x2 ); /* out32_Q14_{0,1,0,1} */ + t_s32x4 = vqdmulhq_s32( out32_Q14_s32x4, A_L_s32x4 ); /* silk_SMULWB( out32_Q14_{0,1,0,1}, A{0,0,1,1}_L_Q28 ) */ + *S_s32x4 = vrsraq_n_s32( *S_s32x4, t_s32x4, 14 ); /* S{0,1} = S{2,3} + silk_RSHIFT_ROUND(); S{2,3} = silk_RSHIFT_ROUND(); */ + t_s32x4 = vqdmulhq_s32( out32_Q14_s32x4, A_U_s32x4 ); /* silk_SMULWB( out32_Q14_{0,1,0,1}, A{0,0,1,1}_U_Q28 ) */ + *S_s32x4 = vaddq_s32( *S_s32x4, t_s32x4 ); /* S0 = silk_SMLAWB( S{0,1,2,3}, out32_Q14_{0,1,0,1}, A{0,0,1,1}_U_Q28 ); */ + t_s32x4 = vqdmulhq_s32( in_s32x4, B_Q28_s32x4 ); /* silk_SMULWB( B_Q28[ {1,1,2,2} ], in{0,1,0,1} ) */ + *S_s32x4 = vaddq_s32( *S_s32x4, t_s32x4 ); /* S0 = silk_SMLAWB( S0, B_Q28[ {1,1,2,2} ], in{0,1,0,1} ); */ +} + +void silk_biquad_alt_stride2_neon( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k = 0; + const int32x2_t offset_s32x2 = vdup_n_s32( (1<<14) - 1 ); + const int32x4_t offset_s32x4 = vcombine_s32( offset_s32x2, offset_s32x2 ); + int16x4_t in_s16x4 = vdup_n_s16( 0 ); + int16x4_t out_s16x4; + int32x2_t A_Q28_s32x2, A_L_s32x2, A_U_s32x2, B_Q28_s32x2, t_s32x2; + int32x4_t A_L_s32x4, A_U_s32x4, B_Q28_s32x4, S_s32x4, out32_Q14_s32x4; + int32x2x2_t t0_s32x2x2, t1_s32x2x2, t2_s32x2x2, S_s32x2x2; + +#ifdef OPUS_CHECK_ASM + opus_int32 S_c[ 4 ]; + VARDECL( opus_int16, out_c ); + SAVE_STACK; + ALLOC( out_c, 2 * len, opus_int16 ); + + silk_memcpy( &S_c, S, sizeof( S_c ) ); + silk_biquad_alt_stride2_c( in, B_Q28, A_Q28, S_c, out_c, len ); +#endif + + /* Negate A_Q28 values and split in two parts */ + A_Q28_s32x2 = vld1_s32( A_Q28 ); + A_Q28_s32x2 = vneg_s32( A_Q28_s32x2 ); + A_L_s32x2 = vshl_n_s32( A_Q28_s32x2, 18 ); /* ( -A_Q28[] & 0x00003FFF ) << 18 */ + A_L_s32x2 = vreinterpret_s32_u32( vshr_n_u32( vreinterpret_u32_s32( A_L_s32x2 ), 3 ) ); /* ( -A_Q28[] & 0x00003FFF ) << 15 */ + A_U_s32x2 = vshr_n_s32( A_Q28_s32x2, 14 ); /* silk_RSHIFT( -A_Q28[], 14 ) */ + A_U_s32x2 = vshl_n_s32( A_U_s32x2, 16 ); /* silk_RSHIFT( -A_Q28[], 14 ) << 16 (Clip two leading bits to conform to C function.) */ + A_U_s32x2 = vshr_n_s32( A_U_s32x2, 1 ); /* silk_RSHIFT( -A_Q28[], 14 ) << 15 */ + + B_Q28_s32x2 = vld1_s32( B_Q28 ); + t_s32x2 = vld1_s32( B_Q28 + 1 ); + t0_s32x2x2 = vzip_s32( A_L_s32x2, A_L_s32x2 ); + t1_s32x2x2 = vzip_s32( A_U_s32x2, A_U_s32x2 ); + t2_s32x2x2 = vzip_s32( t_s32x2, t_s32x2 ); + A_L_s32x4 = vcombine_s32( t0_s32x2x2.val[ 0 ], t0_s32x2x2.val[ 1 ] ); /* A{0,0,1,1}_L_Q28 */ + A_U_s32x4 = vcombine_s32( t1_s32x2x2.val[ 0 ], t1_s32x2x2.val[ 1 ] ); /* A{0,0,1,1}_U_Q28 */ + B_Q28_s32x4 = vcombine_s32( t2_s32x2x2.val[ 0 ], t2_s32x2x2.val[ 1 ] ); /* B_Q28[ {1,1,2,2} ] */ + S_s32x4 = vld1q_s32( S ); /* S0 = S[ 0 ]; S3 = S[ 3 ]; */ + S_s32x2x2 = vtrn_s32( vget_low_s32( S_s32x4 ), vget_high_s32( S_s32x4 ) ); /* S2 = S[ 1 ]; S1 = S[ 2 ]; */ + S_s32x4 = vcombine_s32( S_s32x2x2.val[ 0 ], S_s32x2x2.val[ 1 ] ); + + for( ; k < len - 1; k += 2 ) { + int32x4_t in_s32x4[ 2 ], t_s32x4; + int32x2_t out32_Q14_s32x2[ 2 ]; + + /* S[ 2 * i + 0 ], S[ 2 * i + 1 ], S[ 2 * i + 2 ], S[ 2 * i + 3 ]: Q12 */ + in_s16x4 = vld1_s16( &in[ 2 * k ] ); /* in{0,1,2,3} = in[ 2 * k + {0,1,2,3} ]; */ + in_s32x4[ 0 ] = vshll_n_s16( in_s16x4, 15 ); /* in{0,1,2,3} << 15 */ + t_s32x4 = vqdmulhq_lane_s32( in_s32x4[ 0 ], B_Q28_s32x2, 0 ); /* silk_SMULWB( B_Q28[ 0 ], in{0,1,2,3} ) */ + in_s32x4[ 1 ] = vcombine_s32( vget_high_s32( in_s32x4[ 0 ] ), vget_high_s32( in_s32x4[ 0 ] ) ); /* in{2,3,2,3} << 15 */ + in_s32x4[ 0 ] = vcombine_s32( vget_low_s32 ( in_s32x4[ 0 ] ), vget_low_s32 ( in_s32x4[ 0 ] ) ); /* in{0,1,0,1} << 15 */ + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, vget_low_s32 ( t_s32x4 ), in_s32x4[ 0 ], &S_s32x4, &out32_Q14_s32x2[ 0 ] ); + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, vget_high_s32( t_s32x4 ), in_s32x4[ 1 ], &S_s32x4, &out32_Q14_s32x2[ 1 ] ); + + /* Scale back to Q0 and saturate */ + out32_Q14_s32x4 = vcombine_s32( out32_Q14_s32x2[ 0 ], out32_Q14_s32x2[ 1 ] ); /* out32_Q14_{0,1,2,3} */ + out32_Q14_s32x4 = vaddq_s32( out32_Q14_s32x4, offset_s32x4 ); /* out32_Q14_{0,1,2,3} + (1<<14) - 1 */ + out_s16x4 = vqshrn_n_s32( out32_Q14_s32x4, 14 ); /* (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,2,3} + (1<<14) - 1, 14 ) ) */ + vst1_s16( &out[ 2 * k ], out_s16x4 ); /* out[ 2 * k + {0,1,2,3} ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,2,3} + (1<<14) - 1, 14 ) ); */ + } + + /* Process leftover. */ + if( k < len ) { + int32x4_t in_s32x4; + int32x2_t out32_Q14_s32x2; + + /* S[ 2 * i + 0 ], S[ 2 * i + 1 ]: Q12 */ + in_s16x4 = vld1_lane_s16( &in[ 2 * k + 0 ], in_s16x4, 0 ); /* in{0,1} = in[ 2 * k + {0,1} ]; */ + in_s16x4 = vld1_lane_s16( &in[ 2 * k + 1 ], in_s16x4, 1 ); /* in{0,1} = in[ 2 * k + {0,1} ]; */ + in_s32x4 = vshll_n_s16( in_s16x4, 15 ); /* in{0,1} << 15 */ + t_s32x2 = vqdmulh_lane_s32( vget_low_s32( in_s32x4 ), B_Q28_s32x2, 0 ); /* silk_SMULWB( B_Q28[ 0 ], in{0,1} ) */ + in_s32x4 = vcombine_s32( vget_low_s32( in_s32x4 ), vget_low_s32( in_s32x4 ) ); /* in{0,1,0,1} << 15 */ + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, t_s32x2, in_s32x4, &S_s32x4, &out32_Q14_s32x2 ); + + /* Scale back to Q0 and saturate */ + out32_Q14_s32x2 = vadd_s32( out32_Q14_s32x2, offset_s32x2 ); /* out32_Q14_{0,1} + (1<<14) - 1 */ + out32_Q14_s32x4 = vcombine_s32( out32_Q14_s32x2, out32_Q14_s32x2 ); /* out32_Q14_{0,1,0,1} + (1<<14) - 1 */ + out_s16x4 = vqshrn_n_s32( out32_Q14_s32x4, 14 ); /* (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,0,1} + (1<<14) - 1, 14 ) ) */ + vst1_lane_s16( &out[ 2 * k + 0 ], out_s16x4, 0 ); /* out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_0 + (1<<14) - 1, 14 ) ); */ + vst1_lane_s16( &out[ 2 * k + 1 ], out_s16x4, 1 ); /* out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_1 + (1<<14) - 1, 14 ) ); */ + } + + vst1q_lane_s32( &S[ 0 ], S_s32x4, 0 ); /* S[ 0 ] = S0; */ + vst1q_lane_s32( &S[ 1 ], S_s32x4, 2 ); /* S[ 1 ] = S2; */ + vst1q_lane_s32( &S[ 2 ], S_s32x4, 1 ); /* S[ 2 ] = S1; */ + vst1q_lane_s32( &S[ 3 ], S_s32x4, 3 ); /* S[ 3 ] = S3; */ + +#ifdef OPUS_CHECK_ASM + silk_assert( !memcmp( S_c, S, sizeof( S_c ) ) ); + silk_assert( !memcmp( out_c, out, 2 * len * sizeof( opus_int16 ) ) ); + RESTORE_STACK; +#endif +} diff --git a/native/codec/libraries/opus/silk/arm/macros_arm64.h b/native/codec/libraries/opus/silk/arm/macros_arm64.h new file mode 100644 index 0000000..ed03041 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/macros_arm64.h @@ -0,0 +1,39 @@ +/*********************************************************************** +Copyright (C) 2015 Vidyo +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MACROS_ARM64_H +#define SILK_MACROS_ARM64_H + +#include + +#undef silk_ADD_SAT32 +#define silk_ADD_SAT32(a, b) (vqadds_s32((a), (b))) + +#undef silk_SUB_SAT32 +#define silk_SUB_SAT32(a, b) (vqsubs_s32((a), (b))) + +#endif /* SILK_MACROS_ARM64_H */ diff --git a/native/codec/libraries/opus/silk/arm/macros_armv4.h b/native/codec/libraries/opus/silk/arm/macros_armv4.h new file mode 100644 index 0000000..877eb18 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/macros_armv4.h @@ -0,0 +1,110 @@ +/*********************************************************************** +Copyright (C) 2013 Xiph.Org Foundation and contributors. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MACROS_ARMv4_H +#define SILK_MACROS_ARMv4_H + +/* This macro only avoids the undefined behaviour from a left shift of + a negative value. It should only be used in macros that can't include + SigProc_FIX.h. In other cases, use silk_LSHIFT32(). */ +#define SAFE_SHL(a,b) ((opus_int32)((opus_uint32)(a) << (b))) + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWB\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(SAFE_SHL(b,16)) + ); + return rd_hi; +} +#define silk_SMULWB(a, b) (silk_SMULWB_armv4(a, b)) + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#undef silk_SMLAWB +#define silk_SMLAWB(a, b, c) ((a) + silk_SMULWB(b, c)) + +/* (a32 * (b32 >> 16)) >> 16 */ +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT_armv4(opus_int32 a, opus_int32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWT\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(b&~0xFFFF) + ); + return rd_hi; +} +#define silk_SMULWT(a, b) (silk_SMULWT_armv4(a, b)) + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#undef silk_SMLAWT +#define silk_SMLAWT(a, b, c) ((a) + silk_SMULWT(b, c)) + +/* (a32 * b32) >> 16 */ +#undef silk_SMULWW +static OPUS_INLINE opus_int32 silk_SMULWW_armv4(opus_int32 a, opus_int32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWW\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(b) + ); + return SAFE_SHL(rd_hi,16)+(rd_lo>>16); +} +#define silk_SMULWW(a, b) (silk_SMULWW_armv4(a, b)) + +#undef silk_SMLAWW +static OPUS_INLINE opus_int32 silk_SMLAWW_armv4(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMLAWW\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b), "r"(c) + ); + return a+SAFE_SHL(rd_hi,16)+(rd_lo>>16); +} +#define silk_SMLAWW(a, b, c) (silk_SMLAWW_armv4(a, b, c)) + +#undef SAFE_SHL + +#endif /* SILK_MACROS_ARMv4_H */ diff --git a/native/codec/libraries/opus/silk/arm/macros_armv5e.h b/native/codec/libraries/opus/silk/arm/macros_armv5e.h new file mode 100644 index 0000000..b14ec65 --- /dev/null +++ b/native/codec/libraries/opus/silk/arm/macros_armv5e.h @@ -0,0 +1,220 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (c) 2013 Parrot +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MACROS_ARMv5E_H +#define SILK_MACROS_ARMv5E_H + +/* This macro only avoids the undefined behaviour from a left shift of + a negative value. It should only be used in macros that can't include + SigProc_FIX.h. In other cases, use silk_LSHIFT32(). */ +#define SAFE_SHL(a,b) ((opus_int32)((opus_uint32)(a) << (b))) + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB_armv5e(opus_int32 a, opus_int16 b) +{ + int res; + __asm__( + "#silk_SMULWB\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULWB(a, b) (silk_SMULWB_armv5e(a, b)) + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#undef silk_SMLAWB +static OPUS_INLINE opus_int32 silk_SMLAWB_armv5e(opus_int32 a, opus_int32 b, + opus_int16 c) +{ + int res; + __asm__( + "#silk_SMLAWB\n\t" + "smlawb %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLAWB(a, b, c) (silk_SMLAWB_armv5e(a, b, c)) + +/* (a32 * (b32 >> 16)) >> 16 */ +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULWT\n\t" + "smulwt %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULWT(a, b) (silk_SMULWT_armv5e(a, b)) + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#undef silk_SMLAWT +static OPUS_INLINE opus_int32 silk_SMLAWT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLAWT\n\t" + "smlawt %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLAWT(a, b, c) (silk_SMLAWT_armv5e(a, b, c)) + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#undef silk_SMULBB +static OPUS_INLINE opus_int32 silk_SMULBB_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULBB\n\t" + "smulbb %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_SMULBB(a, b) (silk_SMULBB_armv5e(a, b)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#undef silk_SMLABB +static OPUS_INLINE opus_int32 silk_SMLABB_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLABB\n\t" + "smlabb %0, %1, %2, %3\n\t" + : "=r"(res) + : "%r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLABB(a, b, c) (silk_SMLABB_armv5e(a, b, c)) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#undef silk_SMULBT +static OPUS_INLINE opus_int32 silk_SMULBT_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULBT\n\t" + "smulbt %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULBT(a, b) (silk_SMULBT_armv5e(a, b)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#undef silk_SMLABT +static OPUS_INLINE opus_int32 silk_SMLABT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLABT\n\t" + "smlabt %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLABT(a, b, c) (silk_SMLABT_armv5e(a, b, c)) + +/* add/subtract with output saturated */ +#undef silk_ADD_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_SAT32_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_ADD_SAT32\n\t" + "qadd %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_ADD_SAT32(a, b) (silk_ADD_SAT32_armv5e(a, b)) + +#undef silk_SUB_SAT32 +static OPUS_INLINE opus_int32 silk_SUB_SAT32_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SUB_SAT32\n\t" + "qsub %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SUB_SAT32(a, b) (silk_SUB_SAT32_armv5e(a, b)) + +#undef silk_CLZ16 +static OPUS_INLINE opus_int32 silk_CLZ16_armv5(opus_int16 in16) +{ + int res; + __asm__( + "#silk_CLZ16\n\t" + "clz %0, %1;\n" + : "=r"(res) + : "r"(SAFE_SHL(in16,16)|0x8000) + ); + return res; +} +#define silk_CLZ16(in16) (silk_CLZ16_armv5(in16)) + +#undef silk_CLZ32 +static OPUS_INLINE opus_int32 silk_CLZ32_armv5(opus_int32 in32) +{ + int res; + __asm__( + "#silk_CLZ32\n\t" + "clz %0, %1\n\t" + : "=r"(res) + : "r"(in32) + ); + return res; +} +#define silk_CLZ32(in32) (silk_CLZ32_armv5(in32)) + +#undef SAFE_SHL + +#endif /* SILK_MACROS_ARMv5E_H */ diff --git a/native/codec/libraries/opus/silk/biquad_alt.c b/native/codec/libraries/opus/silk/biquad_alt.c new file mode 100644 index 0000000..54566a4 --- /dev/null +++ b/native/codec/libraries/opus/silk/biquad_alt.c @@ -0,0 +1,121 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * silk_biquad_alt.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Second order ARMA filter, alternative implementation */ +void silk_biquad_alt_stride1( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k ]; + out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 ); + + S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval ); + + /* Scale back to Q0 and saturate */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); + } +} + +void silk_biquad_alt_stride2_c( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14[ 2 ]; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ], S[ 2 ], S[ 3 ]: Q12 */ + out32_Q14[ 0 ] = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], in[ 2 * k + 0 ] ), 2 ); + out32_Q14[ 1 ] = silk_LSHIFT( silk_SMLAWB( S[ 2 ], B_Q28[ 0 ], in[ 2 * k + 1 ] ), 2 ); + + S[ 0 ] = S[ 1 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A0_L_Q28 ), 14 ); + S[ 2 ] = S[ 3 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14[ 0 ], A0_U_Q28 ); + S[ 2 ] = silk_SMLAWB( S[ 2 ], out32_Q14[ 1 ], A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], in[ 2 * k + 0 ] ); + S[ 2 ] = silk_SMLAWB( S[ 2 ], B_Q28[ 1 ], in[ 2 * k + 1 ] ); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A1_L_Q28 ), 14 ); + S[ 3 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14[ 0 ], A1_U_Q28 ); + S[ 3 ] = silk_SMLAWB( S[ 3 ], out32_Q14[ 1 ], A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], in[ 2 * k + 0 ] ); + S[ 3 ] = silk_SMLAWB( S[ 3 ], B_Q28[ 2 ], in[ 2 * k + 1 ] ); + + /* Scale back to Q0 and saturate */ + out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 0 ] + (1<<14) - 1, 14 ) ); + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 1 ] + (1<<14) - 1, 14 ) ); + } +} diff --git a/native/codec/libraries/opus/silk/bwexpander.c b/native/codec/libraries/opus/silk/bwexpander.c new file mode 100644 index 0000000..afa9790 --- /dev/null +++ b/native/codec/libraries/opus/silk/bwexpander.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */ + /* Bias in silk_SMULWB can lead to unstable filters */ + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 ); +} diff --git a/native/codec/libraries/opus/silk/bwexpander_32.c b/native/codec/libraries/opus/silk/bwexpander_32.c new file mode 100644 index 0000000..d0010f7 --- /dev/null +++ b/native/codec/libraries/opus/silk/bwexpander_32.c @@ -0,0 +1,50 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = silk_SMULWW( chirp_Q16, ar[ i ] ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] ); +} + diff --git a/native/codec/libraries/opus/silk/check_control_input.c b/native/codec/libraries/opus/silk/check_control_input.c new file mode 100644 index 0000000..739fb01 --- /dev/null +++ b/native/codec/libraries/opus/silk/check_control_input.c @@ -0,0 +1,106 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "control.h" +#include "errors.h" + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + celt_assert( encControl != NULL ); + + if( ( ( encControl->API_sampleRate != 8000 ) && + ( encControl->API_sampleRate != 12000 ) && + ( encControl->API_sampleRate != 16000 ) && + ( encControl->API_sampleRate != 24000 ) && + ( encControl->API_sampleRate != 32000 ) && + ( encControl->API_sampleRate != 44100 ) && + ( encControl->API_sampleRate != 48000 ) ) || + ( ( encControl->desiredInternalSampleRate != 8000 ) && + ( encControl->desiredInternalSampleRate != 12000 ) && + ( encControl->desiredInternalSampleRate != 16000 ) ) || + ( ( encControl->maxInternalSampleRate != 8000 ) && + ( encControl->maxInternalSampleRate != 12000 ) && + ( encControl->maxInternalSampleRate != 16000 ) ) || + ( ( encControl->minInternalSampleRate != 8000 ) && + ( encControl->minInternalSampleRate != 12000 ) && + ( encControl->minInternalSampleRate != 16000 ) ) || + ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) || + ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) || + ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) { + celt_assert( 0 ); + return SILK_ENC_FS_NOT_SUPPORTED; + } + if( encControl->payloadSize_ms != 10 && + encControl->payloadSize_ms != 20 && + encControl->payloadSize_ms != 40 && + encControl->payloadSize_ms != 60 ) { + celt_assert( 0 ); + return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_LOSS_RATE; + } + if( encControl->useDTX < 0 || encControl->useDTX > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_DTX_SETTING; + } + if( encControl->useCBR < 0 || encControl->useCBR > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_CBR_SETTING; + } + if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal > encControl->nChannelsAPI ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->complexity < 0 || encControl->complexity > 10 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + return SILK_NO_ERROR; +} diff --git a/native/codec/libraries/opus/silk/code_signs.c b/native/codec/libraries/opus/silk/code_signs.c new file mode 100644 index 0000000..dfd1dca --- /dev/null +++ b/native/codec/libraries/opus/silk/code_signs.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*#define silk_enc_map(a) ((a) > 0 ? 1 : 0)*/ +/*#define silk_dec_map(a) ((a) > 0 ? 1 : -1)*/ +/* shifting avoids if-statement */ +#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 ) +#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 ) + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + const opus_int8 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] != 0 ) { + ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 ); + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + opus_int16 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] > 0 ) { + /* attach sign */ +#if 0 + /* conditional implementation */ + if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) { + q_ptr[ j ] = -q_ptr[ j ]; + } +#else + /* implementation with shift, subtraction, multiplication */ + q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) ); +#endif + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} diff --git a/native/codec/libraries/opus/silk/control.h b/native/codec/libraries/opus/silk/control.h new file mode 100644 index 0000000..b76ec33 --- /dev/null +++ b/native/codec/libraries/opus/silk/control.h @@ -0,0 +1,150 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_CONTROL_H +#define SILK_CONTROL_H + +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decoder API flags */ +#define FLAG_DECODE_NORMAL 0 +#define FLAG_PACKET_LOST 1 +#define FLAG_DECODE_LBRR 2 + +/***********************************************/ +/* Structure for controlling encoder operation */ +/***********************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 maxInternalSampleRate; + + /* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 minInternalSampleRate; + + /* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 desiredInternalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* I: Bitrate during active speech in bits/second; internally limited */ + opus_int32 bitRate; + + /* I: Uplink packet loss in percent (0-100) */ + opus_int packetLossPercentage; + + /* I: Complexity mode; 0 is lowest, 10 is highest complexity */ + opus_int complexity; + + /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */ + opus_int useInBandFEC; + + /* I: Flag to actually code in-band Forward Error Correction (FEC) in the current packet; 0/1 */ + opus_int LBRR_coded; + + /* I: Flag to enable discontinuous transmission (DTX); 0/1 */ + opus_int useDTX; + + /* I: Flag to use constant bitrate */ + opus_int useCBR; + + /* I: Maximum number of bits allowed for the frame */ + opus_int maxBits; + + /* I: Causes a smooth downmix to mono */ + opus_int toMono; + + /* I: Opus encoder is allowing us to switch bandwidth */ + opus_int opusCanSwitch; + + /* I: Make frames as independent as possible (but still use LPC) */ + opus_int reducedDependency; + + /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* O: Flag that bandwidth switching is allowed (because low voice activity) */ + opus_int allowBandwidthSwitch; + + /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */ + opus_int inWBmodeWithoutVariableLP; + + /* O: Stereo width */ + opus_int stereoWidth_Q14; + + /* O: Tells the Opus encoder we're ready to switch */ + opus_int switchReady; + + /* O: SILK Signal type */ + opus_int signalType; + + /* O: SILK offset (dithering) */ + opus_int offset; +} silk_EncControlStruct; + +/**************************************************************************/ +/* Structure for controlling decoder operation and reading decoder status */ +/**************************************************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */ + opus_int prevPitchLag; +} silk_DecControlStruct; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/control_SNR.c b/native/codec/libraries/opus/silk/control_SNR.c new file mode 100644 index 0000000..9a6db27 --- /dev/null +++ b/native/codec/libraries/opus/silk/control_SNR.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* These tables hold SNR values divided by 21 (so they fit in 8 bits) + for different target bitrates spaced at 400 bps interval. The first + 10 values are omitted (0-4 kb/s) because they're all zeros. + These tables were obtained by running different SNRs through the + encoder and measuring the active bitrate. */ +static const unsigned char silk_TargetRate_NB_21[117 - 10] = { + 0, 15, 39, 52, 61, 68, + 74, 79, 84, 88, 92, 95, 99,102,105,108,111,114,117,119,122,124, + 126,129,131,133,135,137,139,142,143,145,147,149,151,153,155,157, + 158,160,162,163,165,167,168,170,171,173,174,176,177,179,180,182, + 183,185,186,187,189,190,192,193,194,196,197,199,200,201,203,204, + 205,207,208,209,211,212,213,215,216,217,219,220,221,223,224,225, + 227,228,230,231,232,234,235,236,238,239,241,242,243,245,246,248, + 249,250,252,253,255 +}; + +static const unsigned char silk_TargetRate_MB_21[165 - 10] = { + 0, 0, 28, 43, 52, 59, + 65, 70, 74, 78, 81, 85, 87, 90, 93, 95, 98,100,102,105,107,109, + 111,113,115,116,118,120,122,123,125,127,128,130,131,133,134,136, + 137,138,140,141,143,144,145,147,148,149,151,152,153,154,156,157, + 158,159,160,162,163,164,165,166,167,168,169,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,188,189,190, + 191,192,193,194,195,196,197,198,199,200,201,202,203,203,204,205, + 206,207,208,209,210,211,212,213,214,214,215,216,217,218,219,220, + 221,222,223,224,224,225,226,227,228,229,230,231,232,233,234,235, + 236,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250, + 251,252,253,254,255 +}; + +static const unsigned char silk_TargetRate_WB_21[201 - 10] = { + 0, 0, 0, 8, 29, 41, + 49, 56, 62, 66, 70, 74, 77, 80, 83, 86, 88, 91, 93, 95, 97, 99, + 101,103,105,107,108,110,112,113,115,116,118,119,121,122,123,125, + 126,127,129,130,131,132,134,135,136,137,138,140,141,142,143,144, + 145,146,147,148,149,150,151,152,153,154,156,157,158,159,159,160, + 161,162,163,164,165,166,167,168,169,170,171,171,172,173,174,175, + 176,177,177,178,179,180,181,181,182,183,184,185,185,186,187,188, + 189,189,190,191,192,192,193,194,195,195,196,197,198,198,199,200, + 200,201,202,203,203,204,205,206,206,207,208,209,209,210,211,211, + 212,213,214,214,215,216,216,217,218,219,219,220,221,221,222,223, + 224,224,225,226,226,227,228,229,229,230,231,232,232,233,234,234, + 235,236,237,237,238,239,240,240,241,242,243,243,244,245,246,246, + 247,248,249,249,250,251,252,253,255 +}; + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +) +{ + int id; + int bound; + const unsigned char *snr_table; + + psEncC->TargetRate_bps = TargetRate_bps; + if( psEncC->nb_subfr == 2 ) { + TargetRate_bps -= 2000 + psEncC->fs_kHz/16; + } + if( psEncC->fs_kHz == 8 ) { + bound = sizeof(silk_TargetRate_NB_21); + snr_table = silk_TargetRate_NB_21; + } else if( psEncC->fs_kHz == 12 ) { + bound = sizeof(silk_TargetRate_MB_21); + snr_table = silk_TargetRate_MB_21; + } else { + bound = sizeof(silk_TargetRate_WB_21); + snr_table = silk_TargetRate_WB_21; + } + id = (TargetRate_bps+200)/400; + id = silk_min(id - 10, bound-1); + if( id <= 0 ) { + psEncC->SNR_dB_Q7 = 0; + } else { + psEncC->SNR_dB_Q7 = snr_table[id]*21; + } + return SILK_NO_ERROR; +} diff --git a/native/codec/libraries/opus/silk/control_audio_bandwidth.c b/native/codec/libraries/opus/silk/control_audio_bandwidth.c new file mode 100644 index 0000000..f6d22d8 --- /dev/null +++ b/native/codec/libraries/opus/silk/control_audio_bandwidth.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + opus_int fs_kHz; + opus_int orig_kHz; + opus_int32 fs_Hz; + + orig_kHz = psEncC->fs_kHz; + /* Handle a bandwidth-switching reset where we need to be aware what the last sampling rate was. */ + if( orig_kHz == 0 ) { + orig_kHz = psEncC->sLP.saved_fs_kHz; + } + fs_kHz = orig_kHz; + fs_Hz = silk_SMULBB( fs_kHz, 1000 ); + if( fs_Hz == 0 ) { + /* Encoder has just been initialized */ + fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) { + /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */ + fs_Hz = psEncC->API_fs_Hz; + fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz ); + fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else { + /* State machine for the internal sampling rate switching */ + if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + } + if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) { + /* Check if we should switch down */ + if( silk_SMULBB( orig_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz ) + { + /* Switch down */ + if( psEncC->sLP.mode == 0 ) { + /* New transition */ + psEncC->sLP.transition_frame_no = TRANSITION_FRAMES; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + } + if( encControl->opusCanSwitch ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + + /* Switch to a lower sample frequency */ + fs_kHz = orig_kHz == 16 ? 12 : 8; + } else { + if( psEncC->sLP.transition_frame_no <= 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: down (at double speed) */ + psEncC->sLP.mode = -2; + } + } + } + else + /* Check if we should switch up */ + if( silk_SMULBB( orig_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz ) + { + /* Switch up */ + if( encControl->opusCanSwitch ) { + /* Switch to a higher sample frequency */ + fs_kHz = orig_kHz == 8 ? 12 : 16; + + /* New transition */ + psEncC->sLP.transition_frame_no = 0; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + + /* Direction: up */ + psEncC->sLP.mode = 1; + } else { + if( psEncC->sLP.mode == 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: up */ + psEncC->sLP.mode = 1; + } + } + } else { + if (psEncC->sLP.mode<0) + psEncC->sLP.mode = 1; + } + } + } + + return fs_kHz; +} diff --git a/native/codec/libraries/opus/silk/control_codec.c b/native/codec/libraries/opus/silk/control_codec.c new file mode 100644 index 0000000..52aa8fd --- /dev/null +++ b/native/codec/libraries/opus/silk/control_codec.c @@ -0,0 +1,423 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#else +#include "main_FLP.h" +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#endif +#include "stack_alloc.h" +#include "tuning_parameters.h" +#include "pitch_est_defines.h" + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +); + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +); + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +); + +static OPUS_INLINE opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const silk_EncControlStruct *encControl /* I */ +); + + +/* Control encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +) +{ + opus_int fs_kHz, ret = 0; + + psEnc->sCmn.useDTX = encControl->useDTX; + psEnc->sCmn.useCBR = encControl->useCBR; + psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate; + psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate; + psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate; + psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate; + psEnc->sCmn.useInBandFEC = encControl->useInBandFEC; + psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI; + psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal; + psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch; + psEnc->sCmn.channelNb = channelNb; + + if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) { + if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) { + /* Change in API sampling rate in the middle of encoding a packet */ + ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz ); + } + return ret; + } + + /* Beyond this point we know that there are no previously coded frames in the payload buffer */ + + /********************************************/ + /* Determine internal sampling rate */ + /********************************************/ + fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl ); + if( force_fs_kHz ) { + fs_kHz = force_fs_kHz; + } + /********************************************/ + /* Prepare resampler and buffered data */ + /********************************************/ + ret += silk_setup_resamplers( psEnc, fs_kHz ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity ); + + /********************************************/ + /* Set packet loss rate measured by farend */ + /********************************************/ + psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage; + + /********************************************/ + /* Set LBRR usage */ + /********************************************/ + ret += silk_setup_LBRR( &psEnc->sCmn, encControl ); + + psEnc->sCmn.controlled_since_last_payload = 1; + + return ret; +} + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + SAVE_STACK; + + if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz ) + { + if( psEnc->sCmn.fs_kHz == 0 ) { + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 ); + } else { + VARDECL( opus_int16, x_buf_API_fs_Hz ); + VARDECL( silk_resampler_state_struct, temp_resampler_state ); +#ifdef FIXED_POINT + opus_int16 *x_bufFIX = psEnc->x_buf; +#else + VARDECL( opus_int16, x_bufFIX ); + opus_int32 new_buf_samples; +#endif + opus_int32 api_buf_samples; + opus_int32 old_buf_samples; + opus_int32 buf_length_ms; + + buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS; + old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz; + +#ifndef FIXED_POINT + new_buf_samples = buf_length_ms * fs_kHz; + ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ), + opus_int16 ); + silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples ); +#endif + + /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */ + ALLOC( temp_resampler_state, 1, silk_resampler_state_struct ); + ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 ); + + /* Calculate number of samples to temporarily upsample */ + api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 ); + + /* Temporary resampling of x_buf data to API_fs_Hz */ + ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 ); + ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples ); + + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 ); + + /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */ + ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples ); + +#ifndef FIXED_POINT + silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples); +#endif + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + RESTORE_STACK; + return ret; +} + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + + /* Set packet size */ + if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) { + if( ( PacketSize_ms != 10 ) && + ( PacketSize_ms != 20 ) && + ( PacketSize_ms != 40 ) && + ( PacketSize_ms != 60 ) ) { + ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( PacketSize_ms <= 10 ) { + psEnc->sCmn.nFramesPerPacket = 1; + psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1; + psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } else { + psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS ); + psEnc->sCmn.nb_subfr = MAX_NB_SUBFR; + psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } + } + psEnc->sCmn.PacketSize_ms = PacketSize_ms; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + } + + /* Set internal sampling frequency */ + celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + celt_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 ); + if( psEnc->sCmn.fs_kHz != fs_kHz ) { + /* reset part of the state */ + silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) ); + silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) ); + silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) ); + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.nFramesEncoded = 0; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + + /* Initialize non-zero parameters */ + psEnc->sCmn.prevLag = 100; + psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sShape.LastGainIndex = 10; + psEnc->sCmn.sNSQ.lagPrev = 100; + psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + + psEnc->sCmn.fs_kHz = fs_kHz; + if( psEnc->sCmn.fs_kHz == 8 ) { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB; + } + psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz; + psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz ); + psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz ); + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + } else { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + } + if( psEnc->sCmn.fs_kHz == 16 ) { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } + } + + /* Check that settings are valid */ + celt_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length ); + + return ret; +} + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +) +{ + opus_int ret = 0; + + /* Set encoding complexity */ + celt_assert( Complexity >= 0 && Complexity <= 10 ); + if( Complexity < 1 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 2 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 3; + psEncC->warping_Q16 = 0; + } else if( Complexity < 3 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 4 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 4; + psEncC->warping_Q16 = 0; + } else if( Complexity < 6 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 ); + psEncC->pitchEstimationLPCOrder = 10; + psEncC->shapingLPCOrder = 16; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 6; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else if( Complexity < 8 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 ); + psEncC->pitchEstimationLPCOrder = 12; + psEncC->shapingLPCOrder = 20; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 3; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 8; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else { + psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 ); + psEncC->pitchEstimationLPCOrder = 16; + psEncC->shapingLPCOrder = 24; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 16; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } + + /* Do not allow higher pitch estimation LPC order than predict LPC order */ + psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder ); + psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape; + psEncC->Complexity = Complexity; + + celt_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + celt_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + celt_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + celt_assert( psEncC->warping_Q16 <= 32767 ); + celt_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + celt_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + + return ret; +} + +static OPUS_INLINE opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const silk_EncControlStruct *encControl /* I */ +) +{ + opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR; + + LBRR_in_previous_packet = psEncC->LBRR_enabled; + psEncC->LBRR_enabled = encControl->LBRR_coded; + if( psEncC->LBRR_enabled ) { + /* Set gain increase for coding LBRR excitation */ + if( LBRR_in_previous_packet == 0 ) { + /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */ + psEncC->LBRR_GainIncreases = 7; + } else { + psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); + } + } + + return ret; +} diff --git a/native/codec/libraries/opus/silk/debug.c b/native/codec/libraries/opus/silk/debug.c new file mode 100644 index 0000000..9253faf --- /dev/null +++ b/native/codec/libraries/opus/silk/debug.c @@ -0,0 +1,170 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "debug.h" +#include "SigProc_FIX.h" + +#if SILK_TIC_TOC + +#ifdef _WIN32 + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/ +{ + /* Returns a time counter in microsec */ + /* the resolution is platform dependent */ + /* but is typically 1.62 us resolution */ + LARGE_INTEGER lpPerformanceCount; + LARGE_INTEGER lpFrequency; + QueryPerformanceCounter(&lpPerformanceCount); + QueryPerformanceFrequency(&lpFrequency); + return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart); +} +#else /* Linux or Mac*/ +unsigned long GetHighResolutionTime(void) /* O time in usec*/ +{ + struct timeval tv; + gettimeofday(&tv, 0); + return((tv.tv_sec*1000000)+(tv.tv_usec)); +} +#endif + +int silk_Timer_nTimers = 0; +int silk_Timer_depth_ctr = 0; +char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef WIN32 +LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +#ifdef WIN32 +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + LARGE_INTEGER lpFrequency; + LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2; + int del = 0x7FFFFFFF; + double avg, sum_avg; + /* estimate overhead of calling performance counters */ + for( k = 0; k < 1000; k++ ) { + QueryPerformanceCounter(&lpPerformanceCount1); + QueryPerformanceCounter(&lpPerformanceCount2); + lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart; + if( (int)lpPerformanceCount2.LowPart < del ) + del = lpPerformanceCount2.LowPart; + } + QueryPerformanceFrequency(&lpFrequency); + /* print results to file */ + sum_avg = 0.0f; + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k]; + } + } + fp = fopen(file_name, "w"); + fprintf(fp, " min avg %% max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart; + fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]); + fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#else +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + /* print results to file */ + fp = fopen(file_name, "w"); + fprintf(fp, " min avg max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) + { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + fprintf(fp, "%d ", silk_Timer_min[k]); + fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]); + fprintf(fp, "%d ", silk_Timer_max[k]); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#endif + +#endif /* SILK_TIC_TOC */ + +#if SILK_DEBUG +FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +int silk_debug_store_count = 0; +#endif /* SILK_DEBUG */ + diff --git a/native/codec/libraries/opus/silk/debug.h b/native/codec/libraries/opus/silk/debug.h new file mode 100644 index 0000000..6f68c1c --- /dev/null +++ b/native/codec/libraries/opus/silk/debug.h @@ -0,0 +1,266 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_DEBUG_H +#define SILK_DEBUG_H + +#include "typedef.h" +#include /* file writing */ +#include /* strcpy, strcmp */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +unsigned long GetHighResolutionTime(void); /* O time in usec*/ + +/* Set to 1 to enable DEBUG_STORE_DATA() macros for dumping + * intermediate signals from the codec. + */ +#define SILK_DEBUG 0 + +/* Flag for using timers */ +#define SILK_TIC_TOC 0 + + +#if SILK_TIC_TOC + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +/*********************************/ +/* timer functions for profiling */ +/*********************************/ +/* example: */ +/* */ +/* TIC(LPC) */ +/* do_LPC(in_vec, order, acoef); // do LPC analysis */ +/* TOC(LPC) */ +/* */ +/* and call the following just before exiting (from main) */ +/* */ +/* silk_TimerSave("silk_TimingData.txt"); */ +/* */ +/* results are now in silk_TimingData.txt */ + +void silk_TimerSave(char *file_name); + +/* max number of timers (in different locations) */ +#define silk_NUM_TIMERS_MAX 50 +/* max length of name tags in TIC(..), TOC(..) */ +#define silk_NUM_TIMERS_MAX_TAG_LEN 30 + +extern int silk_Timer_nTimers; +extern int silk_Timer_depth_ctr; +extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef _WIN32 +extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */ +#ifdef _WIN32 +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + QueryPerformanceCounter(&silk_Timer_start[ID]); \ +} +#else +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + silk_Timer_start[ID] = GetHighResolutionTime(); \ +} +#endif + +#ifdef _WIN32 +#define TOC(TAG_NAME) { \ + LARGE_INTEGER lpPerformanceCount; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + QueryPerformanceCounter(&lpPerformanceCount); \ + lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \ + if((lpPerformanceCount.QuadPart < 100000000) && \ + (lpPerformanceCount.QuadPart >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \ + } \ + silk_Timer_depth_ctr--; \ +} +#else +#define TOC(TAG_NAME) { \ + unsigned long endTime; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + endTime = GetHighResolutionTime(); \ + endTime -= silk_Timer_start[ID]; \ + if((endTime < 100000000) && \ + (endTime >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += endTime; \ + if( endTime > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = endTime; \ + if( endTime < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = endTime; \ + } \ + silk_Timer_depth_ctr--; \ +} +#endif + +#else /* SILK_TIC_TOC */ + +/* define macros as empty strings */ +#define TIC(TAG_NAME) +#define TOC(TAG_NAME) +#define silk_TimerSave(FILE_NAME) + +#endif /* SILK_TIC_TOC */ + + +#if SILK_DEBUG +/************************************/ +/* write data to file for debugging */ +/************************************/ +/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */ + +#define silk_NUM_STORES_MAX 100 +extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +extern int silk_debug_store_count; + +/* Faster way of storing the data */ +#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \ + static opus_int init = 0, cnt = 0; \ + static FILE **fp; \ + if (init == 0) { \ + init = 1; \ + cnt = silk_debug_store_count++; \ + silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \ + } \ + fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \ +} + +/* Call this at the end of main() */ +#define SILK_DEBUG_STORE_CLOSE_FILES { \ + opus_int i; \ + for( i = 0; i < silk_debug_store_count; i++ ) { \ + fclose( silk_debug_store_fp[ i ] ); \ + } \ +} + +#else /* SILK_DEBUG */ + +/* define macros as empty strings */ +#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES) +#define SILK_DEBUG_STORE_CLOSE_FILES + +#endif /* SILK_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_DEBUG_H */ diff --git a/native/codec/libraries/opus/silk/dec_API.c b/native/codec/libraries/opus/silk/dec_API.c new file mode 100644 index 0000000..7d5ca7f --- /dev/null +++ b/native/codec/libraries/opus/silk/dec_API.c @@ -0,0 +1,419 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "API.h" +#include "main.h" +#include "stack_alloc.h" +#include "os_support.h" + +/************************/ +/* Decoder Super Struct */ +/************************/ +typedef struct { + silk_decoder_state channel_state[ DECODER_NUM_CHANNELS ]; + stereo_dec_state sStereo; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int prev_decode_only_middle; +} silk_decoder; + +/*********************/ +/* Decoder functions */ +/*********************/ + +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *decSizeBytes = sizeof( silk_decoder ); + + return ret; +} + +/* Reset decoder state */ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +) +{ + opus_int n, ret = SILK_NO_ERROR; + silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state; + + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } + silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo)); + /* Not strictly needed, but it's cleaner that way */ + ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; +} + +/* Decode a frame */ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut, /* O Number of samples decoded */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR; + opus_int32 nSamplesOutDec, LBRR_symbol; + opus_int16 *samplesOut1_tmp[ 2 ]; + VARDECL( opus_int16, samplesOut1_tmp_storage1 ); + VARDECL( opus_int16, samplesOut1_tmp_storage2 ); + VARDECL( opus_int16, samplesOut2_tmp ); + opus_int32 MS_pred_Q13[ 2 ] = { 0 }; + opus_int16 *resample_out_ptr; + silk_decoder *psDec = ( silk_decoder * )decState; + silk_decoder_state *channel_state = psDec->channel_state; + opus_int has_side; + opus_int stereo_to_mono; + int delay_stack_alloc; + SAVE_STACK; + + celt_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 ); + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if( newPacketFlag ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + channel_state[ n ].nFramesDecoded = 0; /* Used to count frames in packet */ + } + } + + /* If Mono -> Stereo transition in bitstream: init state of second channel */ + if( decControl->nChannelsInternal > psDec->nChannelsInternal ) { + ret += silk_init_decoder( &channel_state[ 1 ] ); + } + + stereo_to_mono = decControl->nChannelsInternal == 1 && psDec->nChannelsInternal == 2 && + ( decControl->internalSampleRate == 1000*channel_state[ 0 ].fs_kHz ); + + if( channel_state[ 0 ].nFramesDecoded == 0 ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + opus_int fs_kHz_dec; + if( decControl->payloadSize_ms == 0 ) { + /* Assuming packet loss, use 10 ms */ + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 10 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 20 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 40 ) { + channel_state[ n ].nFramesPerPacket = 2; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 60 ) { + channel_state[ n ].nFramesPerPacket = 3; + channel_state[ n ].nb_subfr = 4; + } else { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_FRAME_SIZE; + } + fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1; + if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_SAMPLING_FREQUENCY; + } + ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate ); + } + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) { + silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) ); + silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) ); + silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) ); + } + psDec->nChannelsAPI = decControl->nChannelsAPI; + psDec->nChannelsInternal = decControl->nChannelsInternal; + + if( decControl->API_sampleRate > (opus_int32)MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) { + ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY; + RESTORE_STACK; + return( ret ); + } + + if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) { + /* First decoder call for this payload */ + /* Decode VAD flags and LBRR flag */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1); + } + channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1); + } + /* Decode LBRR flags */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) ); + if( channel_state[ n ].LBRR_flag ) { + if( channel_state[ n ].nFramesPerPacket == 1 ) { + channel_state[ n ].LBRR_flags[ 0 ] = 1; + } else { + LBRR_symbol = ec_dec_icdf( psRangeDec, silk_LBRR_flags_iCDF_ptr[ channel_state[ n ].nFramesPerPacket - 2 ], 8 ) + 1; + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].LBRR_flags[ i ] = silk_RSHIFT( LBRR_symbol, i ) & 1; + } + } + } + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + /* Regular decoding: skip all LBRR data */ + for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( channel_state[ n ].LBRR_flags[ i ] ) { + opus_int16 pulses[ MAX_FRAME_LENGTH ]; + opus_int condCoding; + + if( decControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding ); + silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType, + channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length ); + } + } + } + } + } + + /* Get MS predictor index */ + if( decControl->nChannelsInternal == 2 ) { + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) ) + { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */ + if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ) + { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } else { + decode_only_middle = 0; + } + } else { + for( n = 0; n < 2; n++ ) { + MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ]; + } + } + } + + /* Reset side channel decoder prediction memory for first frame with side coding */ + if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) { + silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) ); + silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) ); + psDec->channel_state[ 1 ].lagPrev = 100; + psDec->channel_state[ 1 ].LastGainIndex = 10; + psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psDec->channel_state[ 1 ].first_frame_after_reset = 1; + } + + /* Check if the temp buffer fits into the output PCM buffer. If it fits, + we can delay allocating the temp buffer until after the SILK peak stack + usage. We need to use a < and not a <= because of the two extra samples. */ + delay_stack_alloc = decControl->internalSampleRate*decControl->nChannelsInternal + < decControl->API_sampleRate*decControl->nChannelsAPI; + ALLOC( samplesOut1_tmp_storage1, delay_stack_alloc ? ALLOC_NONE + : decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ), + opus_int16 ); + if ( delay_stack_alloc ) + { + samplesOut1_tmp[ 0 ] = samplesOut; + samplesOut1_tmp[ 1 ] = samplesOut + channel_state[ 0 ].frame_length + 2; + } else { + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage1; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage1 + channel_state[ 0 ].frame_length + 2; + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + has_side = !decode_only_middle; + } else { + has_side = !psDec->prev_decode_only_middle + || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 ); + } + /* Call decoder for one frame */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( n == 0 || has_side ) { + opus_int FrameIndex; + opus_int condCoding; + + FrameIndex = channel_state[ 0 ].nFramesDecoded - n; + /* Use independent coding if no previous frame available */ + if( FrameIndex <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( lostFlag == FLAG_DECODE_LBRR ) { + condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY; + } else if( n > 0 && psDec->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding, arch); + } else { + silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) ); + } + channel_state[ n ].nFramesDecoded++; + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) { + /* Convert Mid/Side to Left/Right */ + silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec ); + } else { + /* Buffering */ + silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) ); + } + + /* Number of output samples */ + *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) ); + + /* Set up pointers to temp buffers */ + ALLOC( samplesOut2_tmp, + decControl->nChannelsAPI == 2 ? *nSamplesOut : ALLOC_NONE, opus_int16 ); + if( decControl->nChannelsAPI == 2 ) { + resample_out_ptr = samplesOut2_tmp; + } else { + resample_out_ptr = samplesOut; + } + + ALLOC( samplesOut1_tmp_storage2, delay_stack_alloc + ? decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ) + : ALLOC_NONE, + opus_int16 ); + if ( delay_stack_alloc ) { + OPUS_COPY(samplesOut1_tmp_storage2, samplesOut, decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2)); + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage2; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage2 + channel_state[ 0 ].frame_length + 2; + } + for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) { + + /* Resample decoded signal to API_sampleRate */ + ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec ); + + /* Interleave if stereo output and stereo stream */ + if( decControl->nChannelsAPI == 2 ) { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ n + 2 * i ] = resample_out_ptr[ i ]; + } + } + } + + /* Create two channel output from mono stream */ + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) { + if ( stereo_to_mono ){ + /* Resample right channel for newly collapsed stereo just in case + we weren't doing collapsing when switching to mono */ + ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec ); + + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ]; + } + } else { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ]; + } + } + } + + /* Export pitch lag, measured at 48 kHz sampling rate */ + if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) { + int mult_tab[ 3 ] = { 6, 4, 3 }; + decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ]; + } else { + decControl->prevPitchLag = 0; + } + + if( lostFlag == FLAG_PACKET_LOST ) { + /* On packet loss, remove the gain clamping to prevent having the energy "bounce back" + if we lose packets when the energy is going down */ + for ( i = 0; i < psDec->nChannelsInternal; i++ ) + psDec->channel_state[ i ].LastGainIndex = 10; + } else { + psDec->prev_decode_only_middle = decode_only_middle; + } + RESTORE_STACK; + return ret; +} + +#if 0 +/* Getting table of contents for a packet */ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +) +{ + opus_int i, flags, ret = SILK_NO_ERROR; + + if( nBytesIn < 1 ) { + return -1; + } + if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) { + return -1; + } + + silk_memset( Silk_TOC, 0, sizeof( *Silk_TOC ) ); + + /* For stereo, extract the flags for the mid channel */ + flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 ); + + Silk_TOC->inbandFECFlag = flags & 1; + for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) { + flags = silk_RSHIFT( flags, 1 ); + Silk_TOC->VADFlags[ i ] = flags & 1; + Silk_TOC->VADFlag |= flags & 1; + } + + return ret; +} +#endif diff --git a/native/codec/libraries/opus/silk/decode_core.c b/native/codec/libraries/opus/silk/decode_core.c new file mode 100644 index 0000000..1c352a6 --- /dev/null +++ b/native/codec/libraries/opus/silk/decode_core.c @@ -0,0 +1,237 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/**********************************************************/ +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +/**********************************************************/ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType; + opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ]; + VARDECL( opus_int16, sLTP ); + VARDECL( opus_int32, sLTP_Q15 ); + opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10; + opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14; + VARDECL( opus_int32, res_Q14 ); + VARDECL( opus_int32, sLPC_Q14 ); + SAVE_STACK; + + silk_assert( psDec->prev_gain_Q16 != 0 ); + + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); + ALLOC( sLTP_Q15, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); + ALLOC( res_Q14, psDec->subfr_length, opus_int32 ); + ALLOC( sLPC_Q14, psDec->subfr_length + MAX_LPC_ORDER, opus_int32 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ]; + + if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + /* Decode excitation */ + rand_seed = psDec->indices.Seed; + for( i = 0; i < psDec->frame_length; i++ ) { + rand_seed = silk_RAND( rand_seed ); + psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 ); + if( psDec->exc_Q14[ i ] > 0 ) { + psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4; + } else + if( psDec->exc_Q14[ i ] < 0 ) { + psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4; + } + psDec->exc_Q14[ i ] += offset_Q10 << 4; + if( rand_seed < 0 ) { + psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ]; + } + + rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] ); + } + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + pexc_Q14 = psDec->exc_Q14; + pxq = xq; + sLTP_buf_idx = psDec->ltp_mem_length; + /* Loop over subframes */ + for( k = 0; k < psDec->nb_subfr; k++ ) { + pres_Q14 = res_Q14; + A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ]; + signalType = psDec->indices.signalType; + + Gain_Q10 = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 ); + inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 ); + + /* Calculate gain adjustment factor */ + if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 ); + + /* Scale short term state */ + for( i = 0; i < MAX_LPC_ORDER; i++ ) { + sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] ); + } + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Save inv_gain */ + silk_assert( inv_gain_Q31 != 0 ); + psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ]; + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED && + psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) { + + silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 ); + + signalType = TYPE_VOICED; + psDecCtrl->pitchL[ k ] = psDec->lagPrev; + } + + if( signalType == TYPE_VOICED ) { + /* Voiced */ + lag = psDecCtrl->pitchL[ k ]; + + /* Re-whitening */ + if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) { + /* Rewhiten with new A coefs */ + start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + if( k == 2 ) { + silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) ); + } + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ], + A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order, arch ); + + /* After rewhitening the LTP state is unscaled */ + if( k == 0 ) { + /* Do LTP downscaling to reduce inter-packet dependency */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 ); + } + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] ); + } + } else { + /* Update LTP state when Gain changes */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] ); + } + } + } + } + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 ); + + /* Update states */ + sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 ); + sLTP_buf_idx++; + } + } else { + pres_Q14 = pexc_Q14; + } + + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Short-term prediction */ + celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( pres_Q14[ i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) ); + + /* Scale with gain */ + pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) ); + } + + /* Update LPC filter state */ + silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + pexc_Q14 += psDec->subfr_length; + pxq += psDec->subfr_length; + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/decode_frame.c b/native/codec/libraries/opus/silk/decode_frame.c new file mode 100644 index 0000000..e73825b --- /dev/null +++ b/native/codec/libraries/opus/silk/decode_frame.c @@ -0,0 +1,130 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "PLC.h" + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding, /* I The type of conditional coding to use */ + int arch /* I Run-time architecture */ +) +{ + VARDECL( silk_decoder_control, psDecCtrl ); + opus_int L, mv_len, ret = 0; + SAVE_STACK; + + L = psDec->frame_length; + ALLOC( psDecCtrl, 1, silk_decoder_control ); + psDecCtrl->LTP_scale_Q14 = 0; + + /* Safety checks */ + celt_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) ) + { + VARDECL( opus_int16, pulses ); + ALLOC( pulses, (L + SHELL_CODEC_FRAME_LENGTH - 1) & + ~(SHELL_CODEC_FRAME_LENGTH - 1), opus_int16 ); + /*********************************************/ + /* Decode quantization indices of side info */ + /*********************************************/ + silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding ); + + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType, + psDec->indices.quantOffsetType, psDec->frame_length ); + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + silk_decode_parameters( psDec, psDecCtrl, condCoding ); + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + silk_decode_core( psDec, psDecCtrl, pOut, pulses, arch ); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + silk_PLC( psDec, psDecCtrl, pOut, 0, arch ); + + psDec->lossCnt = 0; + psDec->prevSignalType = psDec->indices.signalType; + celt_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 ); + + /* A frame has been decoded without errors */ + psDec->first_frame_after_reset = 0; + } else { + /* Handle packet loss by extrapolation */ + psDec->indices.signalType = psDec->prevSignalType; + silk_PLC( psDec, psDecCtrl, pOut, 1, arch ); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + celt_assert( psDec->ltp_mem_length >= psDec->frame_length ); + mv_len = psDec->ltp_mem_length - psDec->frame_length; + silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) ); + silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) ); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + silk_CNG( psDec, psDecCtrl, pOut, L ); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + silk_PLC_glue_frames( psDec, pOut, L ); + + /* Update some decoder state variables */ + psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; + + /* Set output frame length */ + *pN = L; + + RESTORE_STACK; + return ret; +} diff --git a/native/codec/libraries/opus/silk/decode_indices.c b/native/codec/libraries/opus/silk/decode_indices.c new file mode 100644 index 0000000..0bb4a99 --- /dev/null +++ b/native/codec/libraries/opus/silk/decode_indices.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode side-information parameters from payload */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int decode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2; + } else { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 ); + } + psDec->indices.signalType = (opus_int8)silk_RSHIFT( Ix, 1 ); + psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 ); + + /****************/ + /* Decode gains */ + /****************/ + /* First subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* Conditional coding */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } else { + /* Independent coding, in two stages: MSB bits followed by 3 LSBs */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 ); + psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 ); + } + + /* Remaining subframes */ + for( i = 1; i < psDec->nb_subfr; i++ ) { + psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } + + /**********************/ + /* Decode LSF Indices */ + /**********************/ + psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] ); + celt_assert( psDec->psNLSF_CB->order == psDec->LPC_order ); + for( i = 0; i < psDec->psNLSF_CB->order; i++ ) { + Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + if( Ix == 0 ) { + Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) { + Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } + psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE ); + } + + /* Decode LSF interpolation factor */ + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 ); + } else { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.signalType == TYPE_VOICED ) + { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + decode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) { + /* Decode Delta index */ + delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 ); + if( delta_lagIndex > 0 ) { + delta_lagIndex = delta_lagIndex - 9; + psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex ); + decode_absolute_lagIndex = 0; + } + } + if( decode_absolute_lagIndex ) { + /* Absolute decoding */ + psDec->indices.lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 ); + psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 ); + } + psDec->ec_prevLagIndex = psDec->indices.lagIndex; + + /* Get countour index */ + psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 ); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 ); + + for( k = 0; k < psDec->nb_subfr; k++ ) { + psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 ); + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 ); + } else { + psDec->indices.LTP_scaleIndex = 0; + } + } + psDec->ec_prevSignalType = psDec->indices.signalType; + + /***************/ + /* Decode seed */ + /***************/ + psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 ); +} diff --git a/native/codec/libraries/opus/silk/decode_parameters.c b/native/codec/libraries/opus/silk/decode_parameters.c new file mode 100644 index 0000000..a56a409 --- /dev/null +++ b/native/codec/libraries/opus/silk/decode_parameters.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ]; + const opus_int8 *cbk_ptr_Q7; + + /* Dequant Gains */ + silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices, + &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr ); + + /****************/ + /* Decode NLSFs */ + /****************/ + silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB ); + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order, psDec->arch ); + + /* If just reset, e.g., because internal Fs changed, do not allow interpolation */ + /* improves the case of packet loss in the first frame after a switch */ + if( psDec->first_frame_after_reset == 1 ) { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.NLSFInterpCoef_Q2 < 4 ) { + /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */ + /* the previous NLSF1, and the current NLSF1 */ + for( i = 0; i < psDec->LPC_order; i++ ) { + pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2, + pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 ); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order, psDec->arch ); + } else { + /* Copy LPC coefficients for first half from second half */ + silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + } + + silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* After a packet loss do BWE of LPC coefs */ + if( psDec->lossCnt ) { + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + } + + if( psDec->indices.signalType == TYPE_VOICED ) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + + /* Decode pitch values */ + silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr ); + + /* Decode Codebook Index */ + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */ + + for( k = 0; k < psDec->nb_subfr; k++ ) { + Ix = psDec->indices.LTPIndex[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 ); + } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + Ix = psDec->indices.LTP_scaleIndex; + psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ]; + } else { + silk_memset( psDecCtrl->pitchL, 0, psDec->nb_subfr * sizeof( opus_int ) ); + silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) ); + psDec->indices.PERIndex = 0; + psDecCtrl->LTP_scale_Q14 = 0; + } +} diff --git a/native/codec/libraries/opus/silk/decode_pitch.c b/native/codec/libraries/opus/silk/decode_pitch.c new file mode 100644 index 0000000..fd1b6bf --- /dev/null +++ b/native/codec/libraries/opus/silk/decode_pitch.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +) +{ + opus_int lag, k, min_lag, max_lag, cbk_size; + const opus_int8 *Lag_CB_ptr; + + if( Fs_kHz == 8 ) { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_EXT; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_10MS; + } + } else { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + } + + min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz ); + max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz ); + lag = min_lag + lagIndex; + + for( k = 0; k < nb_subfr; k++ ) { + pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size ); + pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag ); + } +} diff --git a/native/codec/libraries/opus/silk/decode_pulses.c b/native/codec/libraries/opus/silk/decode_pulses.c new file mode 100644 index 0000000..a56d2d3 --- /dev/null +++ b/native/codec/libraries/opus/silk/decode_pulses.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*********************************************/ +/* Decode quantization indices of excitation */ +/*********************************************/ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, j, k, iter, abs_q, nLS, RateLevelIndex; + opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ]; + opus_int16 *pulses_ptr; + const opus_uint8 *cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + } + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + nLshifts[ i ] = 0; + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 ); + + /* LSB indication */ + while( sum_pulses[ i ] == SILK_MAX_PULSES + 1 ) { + nLshifts[ i ]++; + /* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */ + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, + silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 ); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] ); + } else { + silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( pulses[0] ) ); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( nLshifts[ i ] > 0 ) { + nLS = nLshifts[ i ]; + pulses_ptr = &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ]; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = pulses_ptr[ k ]; + for( j = 0; j < nLS; j++ ) { + abs_q = silk_LSHIFT( abs_q, 1 ); + abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 ); + } + pulses_ptr[ k ] = abs_q; + } + /* Mark the number of pulses non-zero for sign decoding. */ + sum_pulses[ i ] |= nLS << 5; + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); +} diff --git a/native/codec/libraries/opus/silk/decoder_set_fs.c b/native/codec/libraries/opus/silk/decoder_set_fs.c new file mode 100644 index 0000000..d9a13d0 --- /dev/null +++ b/native/codec/libraries/opus/silk/decoder_set_fs.c @@ -0,0 +1,108 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +) +{ + opus_int frame_length, ret = 0; + + celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + celt_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 ); + + /* New (sub)frame length */ + psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz ); + frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length ); + + /* Initialize resampler when switching internal or external sampling frequency */ + if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) { + /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */ + ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 ); + + psDec->fs_API_hz = fs_API_Hz; + } + + if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) { + if( fs_kHz == 8 ) { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psDec->fs_kHz != fs_kHz ) { + psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + if( fs_kHz == 8 || fs_kHz == 12 ) { + psDec->LPC_order = MIN_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psDec->LPC_order = MAX_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_WB; + } + if( fs_kHz == 16 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( fs_kHz == 12 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else if( fs_kHz == 8 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } else { + /* unsupported sampling rate */ + celt_assert( 0 ); + } + psDec->first_frame_after_reset = 1; + psDec->lagPrev = 100; + psDec->LastGainIndex = 10; + psDec->prevSignalType = TYPE_NO_VOICE_ACTIVITY; + silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf)); + silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) ); + } + + psDec->fs_kHz = fs_kHz; + psDec->frame_length = frame_length; + } + + /* Check that settings are valid */ + celt_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); + + return ret; +} + diff --git a/native/codec/libraries/opus/silk/define.h b/native/codec/libraries/opus/silk/define.h new file mode 100644 index 0000000..247cb0b --- /dev/null +++ b/native/codec/libraries/opus/silk/define.h @@ -0,0 +1,234 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_DEFINE_H +#define SILK_DEFINE_H + +#include "errors.h" +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Max number of encoder channels (1/2) */ +#define ENCODER_NUM_CHANNELS 2 +/* Number of decoder channels (1/2) */ +#define DECODER_NUM_CHANNELS 2 + +#define MAX_FRAMES_PER_PACKET 3 + +/* Limits on bitrate */ +#define MIN_TARGET_RATE_BPS 5000 +#define MAX_TARGET_RATE_BPS 80000 + +/* LBRR thresholds */ +#define LBRR_NB_MIN_RATE_BPS 12000 +#define LBRR_MB_MIN_RATE_BPS 14000 +#define LBRR_WB_MIN_RATE_BPS 16000 + +/* DTX settings */ +#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */ +#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ +#define DTX_ACTIVITY_THRESHOLD 0.1f + +/* VAD decision */ +#define VAD_NO_DECISION -1 +#define VAD_NO_ACTIVITY 0 +#define VAD_ACTIVITY 1 + +/* Maximum sampling frequency */ +#define MAX_FS_KHZ 16 +#define MAX_API_FS_KHZ 48 + +/* Signal types */ +#define TYPE_NO_VOICE_ACTIVITY 0 +#define TYPE_UNVOICED 1 +#define TYPE_VOICED 2 + +/* Conditional coding types */ +#define CODE_INDEPENDENTLY 0 +#define CODE_INDEPENDENTLY_NO_LTP_SCALING 1 +#define CODE_CONDITIONALLY 2 + +/* Settings for stereo processing */ +#define STEREO_QUANT_TAB_SIZE 16 +#define STEREO_QUANT_SUB_STEPS 5 +#define STEREO_INTERP_LEN_MS 8 /* must be even */ +#define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */ + +/* Range of pitch lag estimates */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ + +/* Maximum number of subframes */ +#define MAX_NB_SUBFR 4 + +/* Number of samples per frame */ +#define LTP_MEM_LENGTH_MS 20 +#define SUB_FRAME_LENGTH_MS 5 +#define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ ) +#define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR ) +#define MAX_FRAME_LENGTH ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for pitch analysis */ +#define LA_PITCH_MS 2 +#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ ) + +/* Order of LPC used in find pitch */ +#define MAX_FIND_PITCH_LPC_ORDER 16 + +/* Length of LPC window used in find pitch */ +#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for noise shape analysis */ +#define LA_SHAPE_MS 5 +#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + +/* Maximum length of LPC window used in noise shape analysis */ +#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ ) + +/* dB level of lowest gain quantization level */ +#define MIN_QGAIN_DB 2 +/* dB level of highest gain quantization level */ +#define MAX_QGAIN_DB 88 +/* Number of gain quantization levels */ +#define N_LEVELS_QGAIN 64 +/* Max increase in gain quantization index */ +#define MAX_DELTA_GAIN_QUANT 36 +/* Max decrease in gain quantization index */ +#define MIN_DELTA_GAIN_QUANT -4 + +/* Quantization offsets (multiples of 4) */ +#define OFFSET_VL_Q10 32 +#define OFFSET_VH_Q10 100 +#define OFFSET_UVL_Q10 100 +#define OFFSET_UVH_Q10 240 + +#define QUANT_LEVEL_ADJUST_Q10 80 + +/* Maximum numbers of iterations used to stabilize an LPC vector */ +#define MAX_LPC_STABILIZE_ITERATIONS 16 +#define MAX_PREDICTION_POWER_GAIN 1e4f +#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f + +#define MAX_LPC_ORDER 16 +#define MIN_LPC_ORDER 10 + +/* Find Pred Coef defines */ +#define LTP_ORDER 5 + +/* LTP quantization settings */ +#define NB_LTP_CBKS 3 + +/* Flag to use harmonic noise shaping */ +#define USE_HARM_SHAPING 1 + +/* Max LPC order of noise shaping filters */ +#define MAX_SHAPE_LPC_ORDER 24 + +#define HARM_SHAPE_FIR_TAPS 3 + +/* Maximum number of delayed decision states */ +#define MAX_DEL_DEC_STATES 4 + +#define LTP_BUF_LENGTH 512 +#define LTP_MASK ( LTP_BUF_LENGTH - 1 ) + +#define DECISION_DELAY 40 + +/* Number of subframes for excitation entropy coding */ +#define SHELL_CODEC_FRAME_LENGTH 16 +#define LOG2_SHELL_CODEC_FRAME_LENGTH 4 +#define MAX_NB_SHELL_BLOCKS ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH ) + +/* Number of rate levels, for entropy coding of excitation */ +#define N_RATE_LEVELS 10 + +/* Maximum sum of pulses per shell coding frame */ +#define SILK_MAX_PULSES 16 + +#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ + +# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER + +/***************************/ +/* Voice activity detector */ +/***************************/ +#define VAD_N_BANDS 4 + +#define VAD_INTERNAL_SUBFRAMES_LOG2 2 +#define VAD_INTERNAL_SUBFRAMES ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 ) + +#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */ +#define VAD_NOISE_LEVELS_BIAS 50 + +/* Sigmoid settings */ +#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */ +#define VAD_SNR_FACTOR_Q16 45000 + +/* smoothing for SNR measurement */ +#define VAD_SNR_SMOOTH_COEF_Q18 4096 + +/* Size of the piecewise linear cosine approximation table for the LSFs */ +#define LSF_COS_TAB_SZ_FIX 128 + +/******************/ +/* NLSF quantizer */ +/******************/ +#define NLSF_W_Q 2 +#define NLSF_VQ_MAX_VECTORS 32 +#define NLSF_QUANT_MAX_AMPLITUDE 4 +#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10 +#define NLSF_QUANT_LEVEL_ADJ 0.1 +#define NLSF_QUANT_DEL_DEC_STATES_LOG2 2 +#define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 ) + +/* Transition filtering for mode switching */ +#define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/ +#define TRANSITION_NB 3 /* Hardcoded in tables */ +#define TRANSITION_NA 2 /* Hardcoded in tables */ +#define TRANSITION_INT_NUM 5 /* Hardcoded in tables */ +#define TRANSITION_FRAMES ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS ) +#define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) ) + +/* BWE factors to apply after packet loss */ +#define BWE_AFTER_LOSS_Q16 63570 + +/* Defines for CN generation */ +#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ +#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ +#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/enc_API.c b/native/codec/libraries/opus/silk/enc_API.c new file mode 100644 index 0000000..55a33f3 --- /dev/null +++ b/native/codec/libraries/opus/silk/enc_API.c @@ -0,0 +1,576 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "define.h" +#include "API.h" +#include "control.h" +#include "typedef.h" +#include "stack_alloc.h" +#include "structs.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *encSizeBytes = sizeof( silk_encoder ); + + return ret; +} + +/*************************/ +/* Init or Reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + int arch, /* I Run-time architecture */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + silk_encoder *psEnc; + opus_int n, ret = SILK_NO_ERROR; + + psEnc = (silk_encoder *)encState; + + /* Reset encoder */ + silk_memset( psEnc, 0, sizeof( silk_encoder ) ); + for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) { + if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) { + celt_assert( 0 ); + } + } + + psEnc->nChannelsAPI = 1; + psEnc->nChannelsInternal = 1; + + /* Read control structure */ + if( ret += silk_QueryEncoder( encState, encStatus ) ) { + celt_assert( 0 ); + } + + return ret; +} + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + opus_int ret = SILK_NO_ERROR; + silk_encoder_state_Fxx *state_Fxx; + silk_encoder *psEnc = (silk_encoder *)encState; + + state_Fxx = psEnc->state_Fxx; + + encStatus->nChannelsAPI = psEnc->nChannelsAPI; + encStatus->nChannelsInternal = psEnc->nChannelsInternal; + encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz; + encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz; + encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz; + encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz; + encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms; + encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps; + encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc; + encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity; + encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC; + encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX; + encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR; + encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch; + encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0; + + return ret; +} + + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0; + opus_int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms; + opus_int nSamplesFromInput = 0, nSamplesFromInputMax; + opus_int speech_act_thr_for_switch_Q8; + opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum; + silk_encoder *psEnc = ( silk_encoder * )encState; + VARDECL( opus_int16, buf ); + opus_int transition, curr_block, tot_blocks; + SAVE_STACK; + + if (encControl->reducedDependency) + { + psEnc->state_Fxx[0].sCmn.first_frame_after_reset = 1; + psEnc->state_Fxx[1].sCmn.first_frame_after_reset = 1; + } + psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0; + + /* Check values in encoder control structure */ + if( ( ret = check_control_input( encControl ) ) != 0 ) { + celt_assert( 0 ); + RESTORE_STACK; + return ret; + } + + encControl->switchReady = 0; + + if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) { + /* Mono -> Stereo transition: init state of second channel and stereo state */ + ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch ); + silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) ); + silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) ); + psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1; + psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1; + psEnc->sStereo.width_prev_Q14 = 0; + psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 ); + if( psEnc->nChannelsAPI == 2 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) ); + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) ); + } + } + + transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal); + + psEnc->nChannelsAPI = encControl->nChannelsAPI; + psEnc->nChannelsInternal = encControl->nChannelsInternal; + + nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate ); + tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1; + curr_block = 0; + if( prefillFlag ) { + silk_LP_state save_LP; + /* Only accept input length of 10 ms */ + if( nBlocksOf10ms != 1 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + if ( prefillFlag == 2 ) { + save_LP = psEnc->state_Fxx[ 0 ].sCmn.sLP; + /* Save the sampling rate so the bandwidth switching code can keep handling transitions. */ + save_LP.saved_fs_kHz = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz; + } + /* Reset Encoder */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch ); + /* Restore the variable LP state. */ + if ( prefillFlag == 2 ) { + psEnc->state_Fxx[ n ].sCmn.sLP = save_LP; + } + celt_assert( !ret ); + } + tmp_payloadSize_ms = encControl->payloadSize_ms; + encControl->payloadSize_ms = 10; + tmp_complexity = encControl->complexity; + encControl->complexity = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1; + } + } else { + /* Only accept input lengths that are a multiple of 10 ms */ + if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + /* Make sure no more than one packet can be produced */ + if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + } + + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + /* Force the side channel to the same rate as the mid */ + opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0; + if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) { + silk_assert( 0 ); + RESTORE_STACK; + return ret; + } + if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) { + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0; + } + } + psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX; + } + celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + + /* Input buffering/resampling and encoding */ + nSamplesToBufferMax = + 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz; + nSamplesFromInputMax = + silk_DIV32_16( nSamplesToBufferMax * + psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + ALLOC( buf, nSamplesFromInputMax, opus_int16 ); + while( 1 ) { + nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, nSamplesToBufferMax ); + nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + /* Resample and write to buffer */ + if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) { + opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n ]; + } + /* Making sure to start both resamplers from the same state when switching from mono to stereo */ + if( psEnc->nPrevChannelsInternal == 1 && id==0 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state)); + } + + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + + nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n + 1 ]; + } + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + + psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer; + } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) { + /* Combine left and right channels before resampling */ + for( n = 0; n < nSamplesFromInput; n++ ) { + sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ]; + buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + } + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + /* On the first mono frame, average the results for the two resampler states */ + if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) { + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) { + psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] = + silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] + + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1); + } + } + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } else { + celt_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 ); + silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16)); + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } + + samplesIn += nSamplesFromInput * encControl->nChannelsAPI; + nSamplesIn -= nSamplesFromInput; + + /* Default */ + psEnc->allowBandwidthSwitch = 0; + + /* Silk encoder */ + if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) { + /* Enough data in input buffer, so encode */ + celt_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length ); + + /* Deal with LBRR data */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) { + /* Create space at start of payload for VAD and FEC flags */ + opus_uint8 iCDF[ 2 ] = { 0, 0 }; + iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + ec_enc_icdf( psRangeEnc, 0, iCDF, 8 ); + + /* Encode any LBRR data from previous packet */ + /* Encode LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + LBRR_symbol = 0; + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i ); + } + psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0; + if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) { + ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 ); + } + } + + /* Code LBRR indices and excitation signals */ + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) { + opus_int condCoding; + + if( encControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] ); + /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */ + if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding ); + silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType, + psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length ); + } + } + } + + /* Reset LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) ); + } + + psEnc->nBitsUsedLBRR = ec_tell( psRangeEnc ); + } + + silk_HP_variable_cutoff( psEnc->state_Fxx ); + + /* Total target bits for packet */ + nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + /* Subtract bits used for LBRR */ + if( !prefillFlag ) { + nBits -= psEnc->nBitsUsedLBRR; + } + /* Divide by number of uncoded frames left in packet */ + nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket ); + /* Convert to bits/second */ + if( encControl->payloadSize_ms == 10 ) { + TargetRate_bps = silk_SMULBB( nBits, 100 ); + } else { + TargetRate_bps = silk_SMULBB( nBits, 50 ); + } + /* Subtract fraction of bits in excess of target in previous frames and packets */ + TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + if( !prefillFlag && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded > 0 ) { + /* Compare actual vs target bits so far in this packet */ + opus_int32 bitsBalance = ec_tell( psRangeEnc ) - psEnc->nBitsUsedLBRR - nBits * psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + TargetRate_bps -= silk_DIV32_16( silk_MUL( bitsBalance, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + } + /* Never exceed input bitrate */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 ); + + /* Convert Left/Right to Mid/Side */ + if( encControl->nChannelsInternal == 2 ) { + silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ], + psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], + MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + /* Reset side channel encoder memory for first frame with side coding */ + if( psEnc->prev_decode_only_middle == 1 ) { + silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) ); + silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) ); + psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100; + psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10; + psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1; + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity ); + } else { + psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0; + } + if( !prefillFlag ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + } + } + } else { + /* Buffering */ + silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) ); + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity ); + + /* Encode */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + opus_int maxBits, useCBR; + + /* Handling rate constraints */ + maxBits = encControl->maxBits; + if( tot_blocks == 2 && curr_block == 0 ) { + maxBits = maxBits * 3 / 5; + } else if( tot_blocks == 3 ) { + if( curr_block == 0 ) { + maxBits = maxBits * 2 / 5; + } else if( curr_block == 1 ) { + maxBits = maxBits * 3 / 4; + } + } + useCBR = encControl->useCBR && curr_block == tot_blocks - 1; + + if( encControl->nChannelsInternal == 1 ) { + channelRate_bps = TargetRate_bps; + } else { + channelRate_bps = MStargetRates_bps[ n ]; + if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) { + useCBR = 0; + /* Give mid up to 1/2 of the max bits for that frame */ + maxBits -= encControl->maxBits / ( tot_blocks * 2 ); + } + } + + if( channelRate_bps > 0 ) { + opus_int condCoding; + + silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps ); + + /* Use independent coding if no previous frame available */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( n > 0 && psEnc->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) { + silk_assert( 0 ); + } + } + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0; + psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++; + } + psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ]; + + /* Insert VAD and FEC flags at beginning of bitstream */ + if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) { + flags = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ]; + } + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag; + } + if( !prefillFlag ) { + ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + } + + /* Return zero bytes if all channels DTXed */ + if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) { + *nBytesOut = 0; + } + + psEnc->nBitsExceeded += *nBytesOut * 8; + psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 ); + + /* Update flag indicating if bandwidth switching is allowed */ + speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ), + SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms ); + if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) { + psEnc->allowBandwidthSwitch = 1; + psEnc->timeSinceSwitchAllowed_ms = 0; + } else { + psEnc->allowBandwidthSwitch = 0; + psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms; + } + } + + if( nSamplesIn == 0 ) { + break; + } + } else { + break; + } + curr_block++; + } + + psEnc->nPrevChannelsInternal = encControl->nChannelsInternal; + + encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch; + encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0; + encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14; + if( prefillFlag ) { + encControl->payloadSize_ms = tmp_payloadSize_ms; + encControl->complexity = tmp_complexity; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0; + } + } + + encControl->signalType = psEnc->state_Fxx[0].sCmn.indices.signalType; + encControl->offset = silk_Quantization_Offsets_Q10 + [ psEnc->state_Fxx[0].sCmn.indices.signalType >> 1 ] + [ psEnc->state_Fxx[0].sCmn.indices.quantOffsetType ]; + RESTORE_STACK; + return ret; +} + diff --git a/native/codec/libraries/opus/silk/encode_indices.c b/native/codec/libraries/opus/silk/encode_indices.c new file mode 100644 index 0000000..4bcbc33 --- /dev/null +++ b/native/codec/libraries/opus/silk/encode_indices.c @@ -0,0 +1,181 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Encode side-information parameters to payload */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, typeOffset; + opus_int encode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + const SideInfoIndices *psIndices; + + if( encode_LBRR ) { + psIndices = &psEncC->indices_LBRR[ FrameIndex ]; + } else { + psIndices = &psEncC->indices; + } + + /*******************************************/ + /* Encode signal type and quantizer offset */ + /*******************************************/ + typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType; + celt_assert( typeOffset >= 0 && typeOffset < 6 ); + celt_assert( encode_LBRR == 0 || typeOffset >= 2 ); + if( encode_LBRR || typeOffset >= 2 ) { + ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 ); + } + + /****************/ + /* Encode gains */ + /****************/ + /* first subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* conditional coding */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 ); + } else { + /* independent coding, in two stages: MSB bits followed by 3 LSBs */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN ); + ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 ); + } + + /* remaining subframes */ + for( i = 1; i < psEncC->nb_subfr; i++ ) { + silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 ); + } + + /****************/ + /* Encode NLSFs */ + /****************/ + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] ); + celt_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder ); + for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) { + if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + } + } + + /* Encode NLSF interpolation factor */ + if( psEncC->nb_subfr == MAX_NB_SUBFR ) { + silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 ); + } + + if( psIndices->signalType == TYPE_VOICED ) + { + /*********************/ + /* Encode pitch lags */ + /*********************/ + /* lag index */ + encode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) { + /* Delta Encoding */ + delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex; + if( delta_lagIndex < -8 || delta_lagIndex > 11 ) { + delta_lagIndex = 0; + } else { + delta_lagIndex = delta_lagIndex + 9; + encode_absolute_lagIndex = 0; /* Only use delta */ + } + silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 ); + ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 ); + } + if( encode_absolute_lagIndex ) { + /* Absolute encoding */ + opus_int32 pitch_high_bits, pitch_low_bits; + pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 ); + silk_assert( pitch_high_bits < 32 ); + ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 ); + } + psEncC->ec_prevLagIndex = psIndices->lagIndex; + + /* Countour index */ + silk_assert( psIndices->contourIndex >= 0 ); + silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) || + ( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) ); + ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 ); + + /********************/ + /* Encode LTP gains */ + /********************/ + /* PERIndex value */ + silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 ); + + /* Codebook Indices */ + for( k = 0; k < psEncC->nb_subfr; k++ ) { + silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) ); + ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 ); + } + + /**********************/ + /* Encode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 ); + } + silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 ); + } + + psEncC->ec_prevSignalType = psIndices->signalType; + + /***************/ + /* Encode seed */ + /***************/ + silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 ); + ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 ); +} diff --git a/native/codec/libraries/opus/silk/encode_pulses.c b/native/codec/libraries/opus/silk/encode_pulses.c new file mode 100644 index 0000000..8a19991 --- /dev/null +++ b/native/codec/libraries/opus/silk/encode_pulses.c @@ -0,0 +1,206 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/*********************************************/ +/* Encode quantization indices of excitation */ +/*********************************************/ + +static OPUS_INLINE opus_int combine_and_check( /* return ok */ + opus_int *pulses_comb, /* O */ + const opus_int *pulses_in, /* I */ + opus_int max_pulses, /* I max value for sum of pulses */ + opus_int len /* I number of output values */ +) +{ + opus_int k, sum; + + for( k = 0; k < len; k++ ) { + sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ]; + if( sum > max_pulses ) { + return 1; + } + pulses_comb[ k ] = sum; + } + + return 0; +} + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; + opus_int32 abs_q, minSumBits_Q5, sumBits_Q5; + VARDECL( opus_int, abs_pulses ); + VARDECL( opus_int, sum_pulses ); + VARDECL( opus_int, nRshifts ); + opus_int pulses_comb[ 8 ]; + opus_int *abs_pulses_ptr; + const opus_int8 *pulses_ptr; + const opus_uint8 *cdf_ptr; + const opus_uint8 *nBits_ptr; + SAVE_STACK; + + silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/ + + /****************************/ + /* Prepare for shell coding */ + /****************************/ + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8)); + } + + /* Take the absolute value of the pulses */ + ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int ); + silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) ); + for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) { + abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] ); + abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] ); + abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] ); + abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] ); + } + + /* Calc sum pulses per shell code frame */ + ALLOC( sum_pulses, iter, opus_int ); + ALLOC( nRshifts, iter, opus_int ); + abs_pulses_ptr = abs_pulses; + for( i = 0; i < iter; i++ ) { + nRshifts[ i ] = 0; + + while( 1 ) { + /* 1+1 -> 2 */ + scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 ); + /* 2+2 -> 4 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 ); + /* 4+4 -> 8 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 ); + /* 8+8 -> 16 */ + scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 ); + + if( scale_down ) { + /* We need to downscale the quantization signal */ + nRshifts[ i ]++; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 ); + } + } else { + /* Jump out of while(1) loop and go to next shell coding frame */ + break; + } + } + abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH; + } + + /**************/ + /* Rate level */ + /**************/ + /* find rate level that leads to fewest bits for coding of pulses per block info */ + minSumBits_Q5 = silk_int32_MAX; + for( k = 0; k < N_RATE_LEVELS - 1; k++ ) { + nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ]; + sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + sumBits_Q5 += nBits_ptr[ SILK_MAX_PULSES + 1 ]; + } else { + sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ]; + } + } + if( sumBits_Q5 < minSumBits_Q5 ) { + minSumBits_Q5 = sumBits_Q5; + RateLevelIndex = k; + } + } + ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /***************************************************/ + /* Sum-Weighted-Pulses Encoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] == 0 ) { + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 ); + } else { + ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, cdf_ptr, 8 ); + for( k = 0; k < nRshifts[ i ] - 1; k++ ) { + ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + } + + /******************/ + /* Shell Encoding */ + /******************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] ); + } + } + + /****************/ + /* LSB Encoding */ + /****************/ + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ]; + nLS = nRshifts[ i ] - 1; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] ); + for( j = nLS; j > 0; j-- ) { + bit = silk_RSHIFT( abs_q, j ) & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + bit = abs_q & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + } + } + + /****************/ + /* Encode signs */ + /****************/ + silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/errors.h b/native/codec/libraries/opus/silk/errors.h new file mode 100644 index 0000000..4507080 --- /dev/null +++ b/native/codec/libraries/opus/silk/errors.h @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_ERRORS_H +#define SILK_ERRORS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************/ +/* Error messages */ +/******************/ +#define SILK_NO_ERROR 0 + +/**************************/ +/* Encoder error messages */ +/**************************/ + +/* Input length is not a multiple of 10 ms, or length is longer than the packet length */ +#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -101 + +/* Sampling frequency not 8000, 12000 or 16000 Hertz */ +#define SILK_ENC_FS_NOT_SUPPORTED -102 + +/* Packet size not 10, 20, 40, or 60 ms */ +#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -103 + +/* Allocated payload buffer too short */ +#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT -104 + +/* Loss rate not between 0 and 100 percent */ +#define SILK_ENC_INVALID_LOSS_RATE -105 + +/* Complexity setting not valid, use 0...10 */ +#define SILK_ENC_INVALID_COMPLEXITY_SETTING -106 + +/* Inband FEC setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_INBAND_FEC_SETTING -107 + +/* DTX setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_DTX_SETTING -108 + +/* CBR setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_CBR_SETTING -109 + +/* Internal encoder error */ +#define SILK_ENC_INTERNAL_ERROR -110 + +/* Internal encoder error */ +#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR -111 + +/**************************/ +/* Decoder error messages */ +/**************************/ + +/* Output sampling frequency lower than internal decoded sampling frequency */ +#define SILK_DEC_INVALID_SAMPLING_FREQUENCY -200 + +/* Payload size exceeded the maximum allowed 1024 bytes */ +#define SILK_DEC_PAYLOAD_TOO_LARGE -201 + +/* Payload has bit errors */ +#define SILK_DEC_PAYLOAD_ERROR -202 + +/* Payload has bit errors */ +#define SILK_DEC_INVALID_FRAME_SIZE -203 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/fixed/LTP_analysis_filter_FIX.c b/native/codec/libraries/opus/silk/fixed/LTP_analysis_filter_FIX.c new file mode 100644 index 0000000..5574e70 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/LTP_analysis_filter_FIX.c @@ -0,0 +1,90 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +) +{ + const opus_int16 *x_ptr, *x_lag_ptr; + opus_int16 Btmp_Q14[ LTP_ORDER ]; + opus_int16 *LTP_res_ptr; + opus_int k, i; + opus_int32 LTP_est; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + + x_lag_ptr = x_ptr - pitchL[ k ]; + + Btmp_Q14[ 0 ] = LTPCoef_Q14[ k * LTP_ORDER ]; + Btmp_Q14[ 1 ] = LTPCoef_Q14[ k * LTP_ORDER + 1 ]; + Btmp_Q14[ 2 ] = LTPCoef_Q14[ k * LTP_ORDER + 2 ]; + Btmp_Q14[ 3 ] = LTPCoef_Q14[ k * LTP_ORDER + 3 ]; + Btmp_Q14[ 4 ] = LTPCoef_Q14[ k * LTP_ORDER + 4 ]; + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + + /* Long-term prediction */ + LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 1 ], Btmp_Q14[ 1 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 0 ], Btmp_Q14[ 2 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -1 ], Btmp_Q14[ 3 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -2 ], Btmp_Q14[ 4 ] ); + + LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/ + + /* Subtract long-term prediction */ + LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est ); + + /* Scale residual */ + LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] ); + + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} + diff --git a/native/codec/libraries/opus/silk/fixed/LTP_scale_ctrl_FIX.c b/native/codec/libraries/opus/silk/fixed/LTP_scale_ctrl_FIX.c new file mode 100644 index 0000000..3dcedef --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/LTP_scale_ctrl_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( + silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ]; +} diff --git a/native/codec/libraries/opus/silk/fixed/apply_sine_window_FIX.c b/native/codec/libraries/opus/silk/fixed/apply_sine_window_FIX.c new file mode 100644 index 0000000..03e088a --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/apply_sine_window_FIX.c @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* Every other sample is linearly interpolated, for speed. */ +/* Window length must be between 16 and 120 (incl) and a multiple of 4. */ + +/* Matlab code for table: + for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end +*/ +static const opus_int16 freq_table_Q16[ 27 ] = { + 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, + 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, + 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702, +}; + +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k, f_Q16, c_Q16; + opus_int32 S0_Q16, S1_Q16; + + celt_assert( win_type == 1 || win_type == 2 ); + + /* Length must be in a range from 16 to 120 and a multiple of 4 */ + celt_assert( length >= 16 && length <= 120 ); + celt_assert( ( length & 3 ) == 0 ); + + /* Frequency */ + k = ( length >> 2 ) - 4; + celt_assert( k >= 0 && k <= 26 ); + f_Q16 = (opus_int)freq_table_Q16[ k ]; + + /* Factor used for cosine approximation */ + c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 ); + silk_assert( c_Q16 >= -32768 ); + + /* initialize state */ + if( win_type == 1 ) { + /* start from 0 */ + S0_Q16 = 0; + /* approximation of sin(f) */ + S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 ); + } else { + /* start from 1 */ + S0_Q16 = ( (opus_int32)1 << 16 ); + /* approximation of cos(f) */ + S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 ); + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] ); + px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] ); + S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) ); + + px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] ); + px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] ); + S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) ); + } +} diff --git a/native/codec/libraries/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h b/native/codec/libraries/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h new file mode 100644 index 0000000..1992e43 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_WARPED_AUTOCORRELATION_FIX_ARM_H +# define SILK_WARPED_AUTOCORRELATION_FIX_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(FIXED_POINT) + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_warped_autocorrelation_FIX_neon( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), PRESUME_NEON(silk_warped_autocorrelation_FIX)(corr, scale, input, warping_Q16, length, order)) +# endif +# endif + +# if !defined(OVERRIDE_silk_warped_autocorrelation_FIX) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_WARPED_AUTOCORRELATION_FIX_IMPL[OPUS_ARCHMASK+1])(opus_int32*, opus_int*, const opus_int16*, const opus_int, const opus_int, const opus_int); +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((*SILK_WARPED_AUTOCORRELATION_FIX_IMPL[(arch)&OPUS_ARCHMASK])(corr, scale, input, warping_Q16, length, order)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), silk_warped_autocorrelation_FIX_neon(corr, scale, input, warping_Q16, length, order)) +# endif +# endif + +# endif /* end FIXED_POINT */ + +#endif /* end SILK_WARPED_AUTOCORRELATION_FIX_ARM_H */ diff --git a/native/codec/libraries/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c b/native/codec/libraries/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c new file mode 100644 index 0000000..00a70cb --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c @@ -0,0 +1,260 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc., Jean-Marc Valin +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +#endif +#include "stack_alloc.h" +#include "main_FIX.h" + +static OPUS_INLINE void calc_corr( const opus_int32 *const input_QS, opus_int64 *const corr_QC, const opus_int offset, const int32x4_t state_QS_s32x4 ) +{ + int64x2_t corr_QC_s64x2[ 2 ], t_s64x2[ 2 ]; + const int32x4_t input_QS_s32x4 = vld1q_s32( input_QS + offset ); + corr_QC_s64x2[ 0 ] = vld1q_s64( corr_QC + offset + 0 ); + corr_QC_s64x2[ 1 ] = vld1q_s64( corr_QC + offset + 2 ); + t_s64x2[ 0 ] = vmull_s32( vget_low_s32( state_QS_s32x4 ), vget_low_s32( input_QS_s32x4 ) ); + t_s64x2[ 1 ] = vmull_s32( vget_high_s32( state_QS_s32x4 ), vget_high_s32( input_QS_s32x4 ) ); + corr_QC_s64x2[ 0 ] = vsraq_n_s64( corr_QC_s64x2[ 0 ], t_s64x2[ 0 ], 2 * QS - QC ); + corr_QC_s64x2[ 1 ] = vsraq_n_s64( corr_QC_s64x2[ 1 ], t_s64x2[ 1 ], 2 * QS - QC ); + vst1q_s64( corr_QC + offset + 0, corr_QC_s64x2[ 0 ] ); + vst1q_s64( corr_QC + offset + 2, corr_QC_s64x2[ 1 ] ); +} + +static OPUS_INLINE int32x4_t calc_state( const int32x4_t state_QS0_s32x4, const int32x4_t state_QS0_1_s32x4, const int32x4_t state_QS1_1_s32x4, const int32x4_t warping_Q16_s32x4 ) +{ + int32x4_t t_s32x4 = vsubq_s32( state_QS0_s32x4, state_QS0_1_s32x4 ); + t_s32x4 = vqdmulhq_s32( t_s32x4, warping_Q16_s32x4 ); + return vaddq_s32( state_QS1_1_s32x4, t_s32x4 ); +} + +void silk_warped_autocorrelation_FIX_neon( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + if( ( MAX_SHAPE_LPC_ORDER > 24 ) || ( order < 6 ) ) { + silk_warped_autocorrelation_FIX_c( corr, scale, input, warping_Q16, length, order ); + } else { + opus_int n, i, lsh; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; /* In reverse order */ + opus_int64 corr_QC_orderT; + int64x2_t lsh_s64x2; + const opus_int orderT = ( order + 3 ) & ~3; + opus_int64 *corr_QCT; + opus_int32 *input_QS; + VARDECL( opus_int32, input_QST ); + VARDECL( opus_int32, state ); + SAVE_STACK; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + ALLOC( input_QST, length + 2 * MAX_SHAPE_LPC_ORDER, opus_int32 ); + + input_QS = input_QST; + /* input_QS has zero paddings in the beginning and end. */ + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + + /* Loop over samples */ + for( n = 0; n < length - 7; n += 8, input_QS += 8 ) { + const int16x8_t t0_s16x4 = vld1q_s16( input + n ); + vst1q_s32( input_QS + 0, vshll_n_s16( vget_low_s16( t0_s16x4 ), QS ) ); + vst1q_s32( input_QS + 4, vshll_n_s16( vget_high_s16( t0_s16x4 ), QS ) ); + } + for( ; n < length; n++, input_QS++ ) { + input_QS[ 0 ] = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + } + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS = input_QST + MAX_SHAPE_LPC_ORDER - orderT; + + /* The following loop runs ( length + order ) times, with ( order ) extra epilogues. */ + /* The zero paddings in input_QS guarantee corr_QC's correctness even with the extra epilogues. */ + /* The values of state_QS will be polluted by the extra epilogues, however they are temporary values. */ + + /* Keep the C code here to help understand the intrinsics optimization. */ + /* + { + opus_int32 state_QS[ 2 ][ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int32 *state_QST[ 3 ]; + state_QST[ 0 ] = state_QS[ 0 ]; + state_QST[ 1 ] = state_QS[ 1 ]; + for( n = 0; n < length + order; n++, input_QS++ ) { + state_QST[ 0 ][ orderT ] = input_QS[ orderT ]; + for( i = 0; i < orderT; i++ ) { + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( state_QST[ 0 ][ i ], input_QS[ i ] ), 2 * QS - QC ); + state_QST[ 1 ][ i ] = silk_SMLAWB( state_QST[ 1 ][ i + 1 ], state_QST[ 0 ][ i ] - state_QST[ 0 ][ i + 1 ], warping_Q16 ); + } + state_QST[ 2 ] = state_QST[ 0 ]; + state_QST[ 0 ] = state_QST[ 1 ]; + state_QST[ 1 ] = state_QST[ 2 ]; + } + } + */ + + { + const int32x4_t warping_Q16_s32x4 = vdupq_n_s32( warping_Q16 << 15 ); + const opus_int32 *in = input_QS + orderT; + opus_int o = orderT; + int32x4_t state_QS_s32x4[ 3 ][ 2 ]; + + ALLOC( state, length + orderT, opus_int32 ); + state_QS_s32x4[ 2 ][ 1 ] = vdupq_n_s32( 0 ); + + /* Calculate 8 taps of all inputs in each loop. */ + do { + state_QS_s32x4[ 0 ][ 0 ] = state_QS_s32x4[ 0 ][ 1 ] = + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 1 ][ 1 ] = vdupq_n_s32( 0 ); + n = 0; + do { + calc_corr( input_QS + n, corr_QC, o - 8, state_QS_s32x4[ 0 ][ 0 ] ); + calc_corr( input_QS + n, corr_QC, o - 4, state_QS_s32x4[ 0 ][ 1 ] ); + state_QS_s32x4[ 2 ][ 1 ] = vld1q_s32( in + n ); + vst1q_lane_s32( state + n, state_QS_s32x4[ 0 ][ 0 ], 0 ); + state_QS_s32x4[ 2 ][ 0 ] = vextq_s32( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 0 ][ 1 ], 1 ); + state_QS_s32x4[ 2 ][ 1 ] = vextq_s32( state_QS_s32x4[ 0 ][ 1 ], state_QS_s32x4[ 2 ][ 1 ], 1 ); + state_QS_s32x4[ 0 ][ 0 ] = calc_state( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], state_QS_s32x4[ 1 ][ 0 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 0 ][ 1 ] = calc_state( state_QS_s32x4[ 0 ][ 1 ], state_QS_s32x4[ 2 ][ 1 ], state_QS_s32x4[ 1 ][ 1 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 2 ][ 0 ]; + state_QS_s32x4[ 1 ][ 1 ] = state_QS_s32x4[ 2 ][ 1 ]; + } while( ++n < ( length + order ) ); + in = state; + o -= 8; + } while( o > 4 ); + + if( o ) { + /* Calculate the last 4 taps of all inputs. */ + opus_int32 *stateT = state; + silk_assert( o == 4 ); + state_QS_s32x4[ 0 ][ 0 ] = state_QS_s32x4[ 1 ][ 0 ] = vdupq_n_s32( 0 ); + n = length + order; + do { + calc_corr( input_QS, corr_QC, 0, state_QS_s32x4[ 0 ][ 0 ] ); + state_QS_s32x4[ 2 ][ 0 ] = vld1q_s32( stateT ); + vst1q_lane_s32( stateT, state_QS_s32x4[ 0 ][ 0 ], 0 ); + state_QS_s32x4[ 2 ][ 0 ] = vextq_s32( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], 1 ); + state_QS_s32x4[ 0 ][ 0 ] = calc_state( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], state_QS_s32x4[ 1 ][ 0 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 2 ][ 0 ]; + input_QS++; + stateT++; + } while( --n ); + } + } + + { + const opus_int16 *inputT = input; + int32x4_t t_s32x4; + int64x1_t t_s64x1; + int64x2_t t_s64x2 = vdupq_n_s64( 0 ); + for( n = 0; n <= length - 8; n += 8 ) { + int16x8_t input_s16x8 = vld1q_s16( inputT ); + t_s32x4 = vmull_s16( vget_low_s16( input_s16x8 ), vget_low_s16( input_s16x8 ) ); + t_s32x4 = vmlal_s16( t_s32x4, vget_high_s16( input_s16x8 ), vget_high_s16( input_s16x8 ) ); + t_s64x2 = vaddw_s32( t_s64x2, vget_low_s32( t_s32x4 ) ); + t_s64x2 = vaddw_s32( t_s64x2, vget_high_s32( t_s32x4 ) ); + inputT += 8; + } + t_s64x1 = vadd_s64( vget_low_s64( t_s64x2 ), vget_high_s64( t_s64x2 ) ); + corr_QC_orderT = vget_lane_s64( t_s64x1, 0 ); + for( ; n < length; n++ ) { + corr_QC_orderT += silk_SMULL( input[ n ], input[ n ] ); + } + corr_QC_orderT = silk_LSHIFT64( corr_QC_orderT, QC ); + corr_QC[ orderT ] = corr_QC_orderT; + } + + corr_QCT = corr_QC + orderT - order; + lsh = silk_CLZ64( corr_QC_orderT ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + lsh_s64x2 = vdupq_n_s64( lsh ); + for( i = 0; i <= order - 3; i += 4 ) { + int32x4_t corr_s32x4; + int64x2_t corr_QC0_s64x2, corr_QC1_s64x2; + corr_QC0_s64x2 = vld1q_s64( corr_QCT + i ); + corr_QC1_s64x2 = vld1q_s64( corr_QCT + i + 2 ); + corr_QC0_s64x2 = vshlq_s64( corr_QC0_s64x2, lsh_s64x2 ); + corr_QC1_s64x2 = vshlq_s64( corr_QC1_s64x2, lsh_s64x2 ); + corr_s32x4 = vcombine_s32( vmovn_s64( corr_QC1_s64x2 ), vmovn_s64( corr_QC0_s64x2 ) ); + corr_s32x4 = vrev64q_s32( corr_s32x4 ); + vst1q_s32( corr + order - i - 3, corr_s32x4 ); + } + if( lsh >= 0 ) { + for( ; i < order + 1; i++ ) { + corr[ order - i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QCT[ i ], lsh ) ); + } + } else { + for( ; i < order + 1; i++ ) { + corr[ order - i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QCT[ i ], -lsh ) ); + } + } + silk_assert( corr_QCT[ order ] >= 0 ); /* If breaking, decrease QC*/ + RESTORE_STACK; + } + +#ifdef OPUS_CHECK_ASM + { + opus_int32 corr_c[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int scale_c; + silk_warped_autocorrelation_FIX_c( corr_c, &scale_c, input, warping_Q16, length, order ); + silk_assert( !memcmp( corr_c, corr, sizeof( corr_c[ 0 ] ) * ( order + 1 ) ) ); + silk_assert( scale_c == *scale ); + } +#endif +} diff --git a/native/codec/libraries/opus/silk/fixed/autocorr_FIX.c b/native/codec/libraries/opus/silk/fixed/autocorr_FIX.c new file mode 100644 index 0000000..de95c98 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/autocorr_FIX.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "celt_lpc.h" + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount, /* I Number of correlation taps to compute */ + int arch /* I Run-time architecture */ +) +{ + opus_int corrCount; + corrCount = silk_min_int( inputDataSize, correlationCount ); + *scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch); +} diff --git a/native/codec/libraries/opus/silk/fixed/burg_modified_FIX.c b/native/codec/libraries/opus/silk/fixed/burg_modified_FIX.c new file mode 100644 index 0000000..274d4b2 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/burg_modified_FIX.c @@ -0,0 +1,280 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "define.h" +#include "tuning_parameters.h" +#include "pitch.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#define QA 25 +#define N_BITS_HEAD_ROOM 3 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_c( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) +{ + opus_int k, n, s, lz, rshifts, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + opus_int64 C0_64; + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0_64 = silk_inner_prod16_aligned_64( x, x, subfr_length*nb_subfr, arch ); + lz = silk_CLZ64(C0_64); + rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz; + if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS; + if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS; + + if (rshifts > 0) { + C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts ); + } else { + C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts ); + } + + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64( + silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts ); + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + int i; + opus_int32 d; + x_ptr = x + s * subfr_length; + celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch ); + for( n = 1; n < D + 1; n++ ) { + for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ ) + d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] ); + xcorr[ n - 1 ] += d; + } + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = (opus_int32)1 << 30; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */ + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + /* We sometimes have get overflows in the multiplications (even beyond +/- 2^32), + but they cancel each other and the real result seems to always fit in a 32-bit + signed integer. This was determined experimentally, not theoretically (unfortunately). */ + tmp1 = silk_MLA_ovflw( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA_ovflw( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */ + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */ + tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */ + num = 0; /* Q( -rshifts ) */ + nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */ + } + CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */ + CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */ + num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + if( rc_Q31 > 0 ) { + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; /* QA */ + tmp2 = Af_QA[ n - k - 1 ]; /* QA */ + Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; /* Q( -rshifts ) */ + tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */ + CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch), -rshifts); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = (opus_int32)1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/native/codec/libraries/opus/silk/fixed/corrMatrix_FIX.c b/native/codec/libraries/opus/silk/fixed/corrMatrix_FIX.c new file mode 100644 index 0000000..1b4a29c --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/corrMatrix_FIX.c @@ -0,0 +1,150 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation Matrix Computations for LS estimate. + **********************************************************************/ + +#include "main_FIX.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts, /* I Right shifts of correlations */ + int arch /* I Run-time architecture */ +) +{ + opus_int lag, i; + const opus_int16 *ptr1, *ptr2; + opus_int32 inner_prod; + + ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + ptr2 = t; + /* Calculate X'*t */ + if( rshifts > 0 ) { + /* Right shifting used */ + for( lag = 0; lag < order; lag++ ) { + inner_prod = 0; + for( i = 0; i < L; i++ ) { + inner_prod = silk_ADD_RSHIFT32( inner_prod, silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); + } + Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } else { + silk_assert( rshifts == 0 ); + for( lag = 0; lag < order; lag++ ) { + Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int32 *nrg, /* O Energy of x vector */ + opus_int *rshifts, /* O Right shifts of correlations and energy */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, j, lag; + opus_int32 energy; + const opus_int16 *ptr1, *ptr2; + + /* Calculate energy to find shift used to fit in 32 bits */ + silk_sum_sqr_shift( nrg, rshifts, x, L + order - 1 ); + energy = *nrg; + + /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */ + /* Remove contribution of first order - 1 samples */ + for( i = 0; i < order - 1; i++ ) { + energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), *rshifts ); + } + + /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */ + /* Fill out the diagonal of the correlation matrix */ + matrix_ptr( XX, 0, 0, order ) = energy; + silk_assert( energy >= 0 ); + ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */ + for( j = 1; j < order; j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), *rshifts ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), *rshifts ) ); + matrix_ptr( XX, j, j, order ) = energy; + silk_assert( energy >= 0 ); + } + + ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */ + /* Calculate the remaining elements of the correlation matrix */ + if( *rshifts > 0 ) { + /* Right shifting used */ + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = 0; + for( i = 0; i < L; i++ ) { + energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), *rshifts ); + } + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), *rshifts ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), *rshifts ) ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--; /* Update pointer to first sample of next column (lag) in X */ + } + } else { + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) ); + energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--;/* Update pointer to first sample of next column (lag) in X */ + } + } +} + diff --git a/native/codec/libraries/opus/silk/fixed/encode_frame_FIX.c b/native/codec/libraries/opus/silk/fixed/encode_frame_FIX.c new file mode 100644 index 0000000..a02bf87 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/encode_frame_FIX.c @@ -0,0 +1,448 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int16 x16[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FIX sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + opus_int16 *x_frame; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; + opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; + opus_int best_sum[ MAX_NB_SUBFR ]; + SAVE_STACK; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + /* start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) ); + + if( !psEnc->sCmn.prefillFlag ) { + VARDECL( opus_int16, res_pitch ); + VARDECL( opus_uint8, ec_buf_copy ); + opus_int16 *res_pitch_frame; + + ALLOC( res_pitch, + psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + + psEnc->sCmn.ltp_mem_length, opus_int16 ); + /* start of pitch LPC residual frame */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; + + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame - psEnc->sCmn.ltp_mem_length, psEnc->sCmn.arch ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FIX( psEnc, &sEncCtrl, x_frame, condCoding ); + + /* Loop over quantizer and entropy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + ALLOC( ec_buf_copy, 1275, opus_uint8 ); + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, + psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, + psEnc->sCmn.arch); + } + + if ( iter == maxIter && !found_lower ) { + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + /* If we still bust after the last iteration, do some damage control. */ + if ( iter == maxIter && !found_lower && nBits > maxBits ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + + /* Keep gains the same as the last frame. */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + psEnc->sCmn.indices.GainsIndices[ i ] = 4; + } + if (condCoding != CODE_CONDITIONALLY) { + psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev; + } + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + /* Clear all pulses. */ + for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + psEnc->sCmn.pulses[ i ] = 0; + } + + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + } + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + celt_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 ); + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + celt_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if ( !found_lower && nBits > maxBits ) { + int j; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + int sum=0; + for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) { + sum += abs( psEnc->sCmn.pulses[j] ); + } + if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) { + best_sum[i] = sum; + best_gain_mult[i] = gainMult_Q8; + } else { + gain_lock[i] = 1; + } + } + } + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + if( nBits > maxBits ) { + if (gainMult_Q8 < 16384) { + gainMult_Q8 *= 2; + } else { + gainMult_Q8 = 32767; + } + } else { + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } + + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + opus_int16 tmp; + if ( gain_lock[i] ) { + tmp = best_gain_mult[i]; + } else { + tmp = gainMult_Q8; + } + sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) ); + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + RESTORE_STACK; + return ret; + } + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + RESTORE_STACK; + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int16 x16[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int32 TempGains_Q16[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + /* Overwrite unquantized gains with quantized gains */ + silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch ); + } + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + } +} diff --git a/native/codec/libraries/opus/silk/fixed/find_LPC_FIX.c b/native/codec/libraries/opus/silk/fixed/find_LPC_FIX.c new file mode 100644 index 0000000..c762a0f --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/find_LPC_FIX.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Finds LPC vector from correlations, and converts to NLSF */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + opus_int32 a_Q16[ MAX_LPC_ORDER ]; + opus_int isInterpLower, shift; + opus_int32 res_nrg0, res_nrg1; + opus_int rshift0, rshift1; + + /* Used only for LSF interpolation */ + opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; + opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; + opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + SAVE_STACK; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: no interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + VARDECL( opus_int16, LPC_res ); + + /* Optimal solution for last 10 ms */ + silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch ); + + /* subtract residual energy here, as that's easier than adding it to the */ + /* residual energy of the first 10 ms in each iteration of the search below */ + shift = res_tmp_nrg_Q - res_nrg_Q; + if( shift >= 0 ) { + if( shift < 32 ) { + res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift ); + } + } else { + silk_assert( shift > -32 ); + res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; + res_nrg_Q = res_tmp_nrg_Q; + } + + /* Convert to NLSFs */ + silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder ); + + ALLOC( LPC_res, 2 * subfr_length, opus_int16 ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + /* Calculate residual energy with NLSF interpolation */ + silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder, psEncC->arch ); + + silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ); + silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ); + + /* Add subframe energies from first half frame */ + shift = rshift0 - rshift1; + if( shift >= 0 ) { + res_nrg1 = silk_RSHIFT( res_nrg1, shift ); + res_nrg_interp_Q = -rshift0; + } else { + res_nrg0 = silk_RSHIFT( res_nrg0, -shift ); + res_nrg_interp_Q = -rshift1; + } + res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 ); + + /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ + shift = res_nrg_interp_Q - res_nrg_Q; + if( shift >= 0 ) { + if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + if( -shift < 32 ) { + if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + isInterpLower = silk_FALSE; + } + } + + /* Determine whether current interpolated NLSFs are best so far */ + if( isInterpLower == silk_TRUE ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + res_nrg_Q = res_nrg_interp_Q; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder ); + } + + celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/fixed/find_LTP_FIX.c b/native/codec/libraries/opus/silk/fixed/find_LTP_FIX.c new file mode 100644 index 0000000..62d4afb --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/find_LTP_FIX.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +void silk_find_LTP_FIX( + opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */ + opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */ + const opus_int16 r_ptr[], /* I Residual signal after LPC */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, extra_shifts; + opus_int xx_shifts, xX_shifts, XX_shifts; + const opus_int16 *lag_ptr; + opus_int32 *XXLTP_Q17_ptr, *xXLTP_Q17_ptr; + opus_int32 xx, nrg, temp; + + xXLTP_Q17_ptr = xXLTP_Q17; + XXLTP_Q17_ptr = XXLTP_Q17; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + silk_sum_sqr_shift( &xx, &xx_shifts, r_ptr, subfr_length + LTP_ORDER ); /* xx in Q( -xx_shifts ) */ + silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, XXLTP_Q17_ptr, &nrg, &XX_shifts, arch ); /* XXLTP_Q17_ptr and nrg in Q( -XX_shifts ) */ + extra_shifts = xx_shifts - XX_shifts; + if( extra_shifts > 0 ) { + /* Shift XX */ + xX_shifts = xx_shifts; + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = silk_RSHIFT32( XXLTP_Q17_ptr[ i ], extra_shifts ); /* Q( -xX_shifts ) */ + } + nrg = silk_RSHIFT32( nrg, extra_shifts ); /* Q( -xX_shifts ) */ + } else if( extra_shifts < 0 ) { + /* Shift xx */ + xX_shifts = XX_shifts; + xx = silk_RSHIFT32( xx, -extra_shifts ); /* Q( -xX_shifts ) */ + } else { + xX_shifts = xx_shifts; + } + silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xXLTP_Q17_ptr, xX_shifts, arch ); /* xXLTP_Q17_ptr in Q( -xX_shifts ) */ + + /* At this point all correlations are in Q(-xX_shifts) */ + temp = silk_SMLAWB( 1, nrg, SILK_FIX_CONST( LTP_CORR_INV_MAX, 16 ) ); + temp = silk_max( temp, xx ); +TIC(div) +#if 0 + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( XXLTP_Q17_ptr[ i ], temp, 17 ); + } + for( i = 0; i < LTP_ORDER; i++ ) { + xXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( xXLTP_Q17_ptr[ i ], temp, 17 ); + } +#else + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)XXLTP_Q17_ptr[ i ], 17 ) / temp ); + } + for( i = 0; i < LTP_ORDER; i++ ) { + xXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)xXLTP_Q17_ptr[ i ], 17 ) / temp ); + } +#endif +TOC(div) + r_ptr += subfr_length; + XXLTP_Q17_ptr += LTP_ORDER * LTP_ORDER; + xXLTP_Q17_ptr += LTP_ORDER; + } +} diff --git a/native/codec/libraries/opus/silk/fixed/find_pitch_lags_FIX.c b/native/codec/libraries/opus/silk/fixed/find_pitch_lags_FIX.c new file mode 100644 index 0000000..6c3379f --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/find_pitch_lags_FIX.c @@ -0,0 +1,143 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int buf_len, i, scale; + opus_int32 thrhld_Q13, res_nrg; + const opus_int16 *x_ptr; + VARDECL( opus_int16, Wsig ); + opus_int16 *Wsig_ptr; + opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ]; + SAVE_STACK; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + /*************************************/ + /* Estimate LPC AR coefficients */ + /*************************************/ + + /* Calculate windowed signal */ + + ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 ); + + /* First LA_LTP samples */ + x_ptr = x + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window( Wsig_ptr, x_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle un - windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + x_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + silk_apply_sine_window( Wsig_ptr, x_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch ); + + /* Add white noise, as fraction of energy */ + auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1; + + /* Calculate the reflection coefficients using schur */ + res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Convert From 32 bit Q24 to 16 bit Q12 coefs */ + for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) { + A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) ); + } + + /* Do BWE */ + silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter( res, x, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder, psEnc->sCmn.arch ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 ); + thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder ); + thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 21 ), psEnc->sCmn.speech_activity_Q8 ); + thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15, 13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) ); + thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 14 ), psEnc->sCmn.input_tilt_Q15 ); + thrhld_Q13 = silk_SAT16( thrhld_Q13 ); + + /*****************************************/ + /* Call pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex, + &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16, + (opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, + psEnc->sCmn.arch) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr_Q15 = 0; + } + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/fixed/find_pred_coefs_FIX.c b/native/codec/libraries/opus/silk/fixed/find_pred_coefs_FIX.c new file mode 100644 index 0000000..606d863 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/find_pred_coefs_FIX.c @@ -0,0 +1,145 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" + +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const opus_int16 *x_ptr; + opus_int16 *x_pre_ptr; + VARDECL( opus_int16, LPC_in_pre ); + opus_int32 min_gain_Q16, minInvGain_Q30; + SAVE_STACK; + + /* weighting for weighted least squares */ + min_gain_Q16 = silk_int32_MAX >> 6; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); + } + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + /* Divide to Q16 */ + silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 ); + /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */ + invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); + + /* Limit inverse */ + invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 100 ); + + /* Square the inverted gains */ + silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) ); + + /* Invert the inverted and normalized gains */ + local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] ); + } + + ALLOC( LPC_in_pre, + psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder + + psEnc->sCmn.frame_length, opus_int16 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + VARDECL( opus_int32, xXLTP_Q17 ); + VARDECL( opus_int32, XXLTP_Q17 ); + + /**********/ + /* VOICED */ + /**********/ + celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + ALLOC( xXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER, opus_int32 ); + ALLOC( XXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 ); + + /* LTP analysis */ + silk_find_LTP_FIX( XXLTP_Q17, xXLTP_Q17, res_pitch, + psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + &psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain_Q7, XXLTP_Q17, xXLTP_Q17, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14, + psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + + silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) ); + psEncCtrl->LTPredCodGain_Q7 = 0; + psEnc->sCmn.sum_log_gain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 ); + } else { + minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */ + minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30, + silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ), + silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 ); + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 ); + + /* Quantize LSFs */ + silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.arch ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/fixed/k2a_FIX.c b/native/codec/libraries/opus/silk/fixed/k2a_FIX.c new file mode 100644 index 0000000..549f6ea --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/k2a_FIX.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 rc, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rc = rc_Q15[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A_Q24[ n ]; + tmp2 = A_Q24[ k - n - 1 ]; + A_Q24[ n ] = silk_SMLAWB( tmp1, silk_LSHIFT( tmp2, 1 ), rc ); + A_Q24[ k - n - 1 ] = silk_SMLAWB( tmp2, silk_LSHIFT( tmp1, 1 ), rc ); + } + A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 ); + } +} diff --git a/native/codec/libraries/opus/silk/fixed/k2a_Q16_FIX.c b/native/codec/libraries/opus/silk/fixed/k2a_Q16_FIX.c new file mode 100644 index 0000000..1595aa6 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/k2a_Q16_FIX.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 rc, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rc = rc_Q16[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A_Q24[ n ]; + tmp2 = A_Q24[ k - n - 1 ]; + A_Q24[ n ] = silk_SMLAWW( tmp1, tmp2, rc ); + A_Q24[ k - n - 1 ] = silk_SMLAWW( tmp2, tmp1, rc ); + } + A_Q24[ k ] = -silk_LSHIFT( rc, 8 ); + } +} diff --git a/native/codec/libraries/opus/silk/fixed/main_FIX.h b/native/codec/libraries/opus/silk/fixed/main_FIX.h new file mode 100644 index 0000000..6d2112e --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/main_FIX.h @@ -0,0 +1,244 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MAIN_FIX_H +#define SILK_MAIN_FIX_H + +#include "SigProc_FIX.h" +#include "structs_FIX.h" +#include "control.h" +#include "main.h" +#include "PLC.h" +#include "debug.h" +#include "entenc.h" + +#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \ + || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "fixed/arm/warped_autocorrelation_FIX_arm.h" +#endif + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +extern "C" +{ +#endif +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX +#define silk_encode_frame_Fxx silk_encode_frame_FIX + +#define QC 10 +#define QS 13 + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */ + int arch /* I Run-time architecture */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +#if !defined(OVERRIDE_silk_warped_autocorrelation_FIX) +#define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), silk_warped_autocorrelation_FIX_c(corr, scale, input, warping_Q16, length, order)) +#endif + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +); + +/* LTP analysis */ +void silk_find_LTP_FIX( + opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */ + opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */ + const opus_int16 r_lpc[], /* I Residual signal after LPC */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +); + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int32 *nrg, /* O Energy of x vector */ + opus_int *rshifts, /* O Right shifts of correlations */ + int arch /* I Run-time architecture */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts, /* I Right shifts of correlations */ + int arch /* I Run-time architecture */ +); + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* FORCE_CPP_BUILD */ +#endif /* SILK_MAIN_FIX_H */ diff --git a/native/codec/libraries/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h b/native/codec/libraries/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h new file mode 100644 index 0000000..3999b5b --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h @@ -0,0 +1,336 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +#define OVERRIDE_silk_noise_shape_analysis_FIX + +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; + VARDECL( opus_int16, x_windowed ); + const opus_int16 *x_ptr, *pitch_res_ptr; + SAVE_STACK; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + psEncCtrl->sparseness_Q8 = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 - + SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + delta_Q16 = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), + SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) ); + BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 ); + BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 ); + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch ); + } else { + /* Calculate regular auto correlation */ + silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = (silk_LSHIFT32( silk_LIMIT( (tmp32), silk_RSHIFT32( silk_int32_MIN, (16 - Qnrg) ), \ + silk_RSHIFT32( silk_int32_MAX, (16 - Qnrg) ) ), (16 - Qnrg) )); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } else { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + } + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); + + /* Compute noise shaping filter coefficients */ + silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) ); + + /* Bandwidth expansion for analysis filter shaping */ + silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) ); + silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); + + /* Ratio of prediction gains, in energy domain */ + pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder, arch ); + nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder, arch ); + + /*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/ + pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 ); + psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) ); + psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ), + psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] ); + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ), + psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) ); + + /* More harmonic boost for noisy input signals */ + HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16, + SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) ); + + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmBoost_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmBoost_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 ); + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h b/native/codec/libraries/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h new file mode 100644 index 0000000..21b2568 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h @@ -0,0 +1,184 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ +#ifndef __PREFILTER_FIX_MIPSR1_H__ +#define __PREFILTER_FIX_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +#define OVERRIDE_silk_warped_LPC_analysis_filter_FIX +void silk_warped_LPC_analysis_filter_FIX( + opus_int32 state[], /* I/O State [order + 1] */ + opus_int32 res_Q2[], /* O Residual signal [length] */ + const opus_int16 coef_Q13[], /* I Coefficients [order] */ + const opus_int16 input[], /* I Input signal [length] */ + const opus_int16 lambda_Q16, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order, /* I Filter order (even) */ + int arch +) +{ + opus_int n, i; + opus_int32 acc_Q11, acc_Q22, tmp1, tmp2, tmp3, tmp4; + opus_int32 state_cur, state_next; + + (void)arch; + + /* Order must be even */ + /* Length must be even */ + + silk_assert( ( order & 1 ) == 0 ); + silk_assert( ( length & 1 ) == 0 ); + + for( n = 0; n < length; n+=2 ) { + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state_cur = silk_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state_next = tmp2; + acc_Q11 = silk_RSHIFT( order, 1 ); + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] ); + + + /* Output of lowpass section */ + tmp4 = silk_SMLAWB( state_cur, state_next, lambda_Q16 ); + state[ 0 ] = silk_LSHIFT( input[ n+1 ], 14 ); + /* Output of allpass section */ + tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 ); + state[ 1 ] = tmp4; + acc_Q22 = silk_RSHIFT( order, 1 ); + acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ 0 ] ); + + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state_cur = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state_next = tmp2; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + + + /* Output of allpass section */ + tmp4 = silk_SMLAWB( state_cur, state_next - tmp3, lambda_Q16 ); + state[ i ] = tmp3; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 ); + state[ i + 1 ] = tmp4; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ i ] ); + } + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 ); + + state[ order ] = tmp3; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ order - 1 ] ); + res_Q2[ n+1 ] = silk_LSHIFT( (opus_int32)input[ n+1 ], 2 ) - silk_RSHIFT_ROUND( acc_Q22, 9 ); + } +} + + + +/* Prefilter for finding Quantizer input signal */ +#define OVERRIDE_silk_prefilt_FIX +static inline void silk_prefilt_FIX( + silk_prefilter_state_FIX *P, /* I/O state */ + opus_int32 st_res_Q12[], /* I short term residual signal */ + opus_int32 xw_Q3[], /* O prefiltered signal */ + opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + opus_int Tilt_Q14, /* I Tilt shaping coeficient */ + opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */ + opus_int lag, /* I Lag for harmonic shaping */ + opus_int length /* I Length of signals */ +) +{ + opus_int i, idx, LTP_shp_buf_idx; + opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10; + opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12; + opus_int16 *LTP_shp_buf; + + /* To speed up use temp variables instead of using the struct */ + LTP_shp_buf = P->sLTP_shp; + LTP_shp_buf_idx = P->sLTP_shp_buf_idx; + sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12; + sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12; + + if( lag > 0 ) { + for( i = 0; i < length; i++ ) { + /* unrolled loop */ + silk_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP_Q12 = silk_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + + n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 ); + } + } + else + { + for( i = 0; i < length; i++ ) { + + n_LTP_Q12 = 0; + + n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw_Q3[i] = silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 9 ); + } + } + + /* Copy temp variable back to state */ + P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12; + P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} + +#endif /* __PREFILTER_FIX_MIPSR1_H__ */ diff --git a/native/codec/libraries/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h b/native/codec/libraries/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h new file mode 100644 index 0000000..66eb2ed --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h @@ -0,0 +1,165 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ +#define __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +#undef QC +#define QC 10 + +#undef QS +#define QS 14 + +/* Autocorrelations for a warped frequency axis */ +#define OVERRIDE_silk_warped_autocorrelation_FIX_c +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS=0, tmp2_QS=0, tmp3_QS=0, tmp4_QS=0, tmp5_QS=0, tmp6_QS=0, tmp7_QS=0, tmp8_QS=0, start_1=0, start_2=0, start_3=0; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 temp64; + + opus_int32 val; + val = 2 * QS - QC; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n=n+4 ) { + + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + start_1 = tmp1_QS; + tmp3_QS = silk_LSHIFT32( (opus_int32)input[ n+1], QS ); + start_2 = tmp3_QS; + tmp5_QS = silk_LSHIFT32( (opus_int32)input[ n+2], QS ); + start_3 = tmp5_QS; + tmp7_QS = silk_LSHIFT32( (opus_int32)input[ n+3], QS ); + + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp1_QS, start_1); + + tmp4_QS = silk_SMLAWB( tmp1_QS, tmp2_QS - tmp3_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp3_QS, start_2); + + tmp6_QS = silk_SMLAWB( tmp3_QS, tmp4_QS - tmp5_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp5_QS, start_3); + + tmp8_QS = silk_SMLAWB( tmp5_QS, tmp6_QS - tmp7_QS, warping_Q16 ); + state_QS[ i ] = tmp7_QS; + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp7_QS, state_QS[0]); + + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp2_QS, start_1); + + tmp3_QS = silk_SMLAWB( tmp2_QS, tmp1_QS - tmp4_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp4_QS, start_2); + + tmp5_QS = silk_SMLAWB( tmp4_QS, tmp3_QS - tmp6_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp6_QS, start_3); + + tmp7_QS = silk_SMLAWB( tmp6_QS, tmp5_QS - tmp8_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp8_QS; + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp8_QS, state_QS[ 0 ]); + + } + state_QS[ order ] = tmp7_QS; + + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp1_QS, start_1); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp3_QS, start_2); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp5_QS, start_3); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp7_QS, state_QS[ 0 ]); + } + + for(;n< length; n++ ) { + + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp1_QS, state_QS[ 0 ]); + + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp2_QS, state_QS[ 0 ]); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp1_QS, state_QS[ 0 ]); + } + + temp64 = corr_QC[ 0 ]; + temp64 = __builtin_mips_shilo(temp64, val); + + lsh = silk_CLZ64( temp64 ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + temp64 = corr_QC[ i ]; + //temp64 = __builtin_mips_shilo(temp64, val); + temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val); + corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + temp64 = corr_QC[ i ]; + //temp64 = __builtin_mips_shilo(temp64, val); + temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val); + corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) ); + } + } + + corr_QC[ 0 ] = __builtin_mips_shilo(corr_QC[ 0 ], val); + + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} +#endif /* __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ */ diff --git a/native/codec/libraries/opus/silk/fixed/noise_shape_analysis_FIX.c b/native/codec/libraries/opus/silk/fixed/noise_shape_analysis_FIX.c new file mode 100644 index 0000000..85fea0b --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/noise_shape_analysis_FIX.c @@ -0,0 +1,407 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/ + const opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int order +) { + opus_int i; + opus_int32 gain_Q24; + + lambda_Q16 = -lambda_Q16; + gain_Q24 = coefs_Q24[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 ); + } + gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 ); + return silk_INVERSE32_varQ( gain_Q24, 40 ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static OPUS_INLINE void limit_warped_coefs( + opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int32 limit_Q24, + opus_int order +) { + opus_int i, iter, ind = 0; + opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_Q16; + opus_int32 nom_Q16, den_Q24; + opus_int32 limit_Q20, maxabs_Q20; + + /* Convert to monic coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 ); + gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + limit_Q20 = silk_RSHIFT(limit_Q24, 4); + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs_Q24 = -1; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_int32( coefs_Q24[ i ] ); + if( tmp > maxabs_Q24 ) { + maxabs_Q24 = tmp; + ind = i; + } + } + /* Use Q20 to avoid any overflow when multiplying by (ind + 1) later. */ + maxabs_Q20 = silk_RSHIFT(maxabs_Q24, 4); + if( maxabs_Q20 <= limit_Q20 ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + gain_Q16 = silk_INVERSE32_varQ( gain_Q16, 32 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + + /* Apply bandwidth expansion */ + chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ( + silk_SMULWB( maxabs_Q20 - limit_Q20, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ), + silk_MUL( maxabs_Q20, ind + 1 ), 22 ); + silk_bwexpander_32( coefs_Q24, order, chirp_Q16 ); + + /* Convert to monic warped coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 ); + gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + } + silk_assert( 0 ); +} + +/* Disable MIPS version until it's updated. */ +#if 0 && defined(MIPSr1_ASM) +#include "mips/noise_shape_analysis_FIX_mipsr1.h" +#endif + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +#ifndef OVERRIDE_silk_noise_shape_analysis_FIX +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, nSegs, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 BWExp_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR_Q24[ MAX_SHAPE_LPC_ORDER ]; + VARDECL( opus_int16, x_windowed ); + const opus_int16 *x_ptr, *pitch_res_ptr; + SAVE_STACK; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; + for( k = 0; k < nSegs; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + /* Set quantization offset depending on sparseness measure */ + if( energy_variation_Q7 > SILK_FIX_CONST( ENERGY_VARIATION_THRESHOLD_QNT_OFFSET, 7 ) * (nSegs-1) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch ); + } else { + /* Calculate regular auto correlation */ + silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); + if( psEncCtrl->Gains_Q16[ k ] < SILK_FIX_CONST( 0.25, 16 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + } else { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ); + if ( psEncCtrl->Gains_Q16[ k ] >= ( silk_int32_MAX >> 1 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } else { + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT32( psEncCtrl->Gains_Q16[ k ], 1 ); + } + } + silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); + } + + /* Bandwidth expansion */ + silk_bwexpander_32( AR_Q24, psEnc->sCmn.shapingLPCOrder, BWExp_Q16 ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR_Q24[ i ], 11 ) ); + } + } else { + silk_LPC_fit( &psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER ], AR_Q24, 13, 24, psEnc->sCmn.shapingLPCOrder ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } + RESTORE_STACK; +} +#endif /* OVERRIDE_silk_noise_shape_analysis_FIX */ diff --git a/native/codec/libraries/opus/silk/fixed/pitch_analysis_core_FIX.c b/native/codec/libraries/opus/silk/fixed/pitch_analysis_core_FIX.c new file mode 100644 index 0000000..1472904 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/pitch_analysis_core_FIX.c @@ -0,0 +1,721 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" +#include "stack_alloc.h" +#include "debug.h" +#include "pitch.h" + +#define SCRATCH_SIZE 22 +#define SF_LENGTH_4KHZ ( PE_SUBFR_LENGTH_MS * 4 ) +#define SF_LENGTH_8KHZ ( PE_SUBFR_LENGTH_MS * 8 ) +#define MIN_LAG_4KHZ ( PE_MIN_LAG_MS * 4 ) +#define MIN_LAG_8KHZ ( PE_MIN_LAG_MS * 8 ) +#define MAX_LAG_4KHZ ( PE_MAX_LAG_MS * 4 ) +#define MAX_LAG_8KHZ ( PE_MAX_LAG_MS * 8 - 1 ) +#define CSTRIDE_4KHZ ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ ) +#define CSTRIDE_8KHZ ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) ) +#define D_COMP_MIN ( MIN_LAG_8KHZ - 3 ) +#define D_COMP_MAX ( MAX_LAG_8KHZ + 4 ) +#define D_COMP_STRIDE ( D_COMP_MAX - D_COMP_MIN ) + +typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ]; + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +/*************************************************************/ +/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ +/*************************************************************/ +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame_unscaled, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I number of 5 ms subframes */ + int arch /* I Run-time architecture */ +) +{ + VARDECL( opus_int16, frame_8kHz_buf ); + VARDECL( opus_int16, frame_4kHz ); + VARDECL( opus_int16, frame_scaled ); + opus_int32 filt_state[ 6 ]; + const opus_int16 *frame, *frame_8kHz; + opus_int i, k, d, j; + VARDECL( opus_int16, C ); + VARDECL( opus_int32, xcorr32 ); + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 cross_corr, normalizer, energy, energy_basis, energy_target; + opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp, shift; + VARDECL( opus_int16, d_comp ); + opus_int32 sum, threshold, lag_counter; + opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; + opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new; + VARDECL( silk_pe_stage3_vals, energies_st3 ); + VARDECL( silk_pe_stage3_vals, cross_corr_st3 ); + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length; + opus_int min_lag; + opus_int max_lag; + opus_int32 contour_bias_Q15, diff; + opus_int nb_cbk_search, cbk_size; + opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13; + const opus_int8 *Lag_CB_ptr; + SAVE_STACK; + + /* Check for valid sampling frequency */ + celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) ); + silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + + /* Downscale input if necessary */ + silk_sum_sqr_shift( &energy, &shift, frame_unscaled, frame_length ); + shift += 3 - silk_CLZ32( energy ); /* at least two bits headroom */ + ALLOC( frame_scaled, frame_length, opus_int16 ); + if( shift > 0 ) { + shift = silk_RSHIFT( shift + 1, 1 ); + for( i = 0; i < frame_length; i++ ) { + frame_scaled[ i ] = silk_RSHIFT( frame_unscaled[ i ], shift ); + } + frame = frame_scaled; + } else { + frame = frame_unscaled; + } + + ALLOC( frame_8kHz_buf, ( Fs_kHz == 8 ) ? 1 : frame_length_8kHz, opus_int16 ); + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8kHz_buf, frame, frame_length ); + frame_8kHz = frame_8kHz_buf; + } else if( Fs_kHz == 12 ) { + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8kHz_buf, frame, frame_length ); + frame_8kHz = frame_8kHz_buf; + } else { + celt_assert( Fs_kHz == 8 ); + frame_8kHz = frame; + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */ + ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 ); + silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); + } + + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 ); + ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 ); + silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) ); + target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_4kHz ); + celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - MIN_LAG_4KHZ; + + /* Check that we are within range of the array */ + celt_assert( basis_ptr >= frame_4kHz ); + celt_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch ); + + /* Calculate first vector products before loop */ + cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ]; + normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ); + normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ) ); + normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) ); + + matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) = + (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */ + + /* From now on normalizer is computed recursively */ + for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + cross_corr = xcorr32[ MAX_LAG_4KHZ - d ]; + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer = silk_ADD32( normalizer, + silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) - + silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) ); + + matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) = + (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */ + } + /* Update target pointer */ + target_ptr += SF_LENGTH_8KHZ; + } + + /* Combine two subframes into single correlation measure and apply short-lag bias */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) { + sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ) + + (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ); /* Q14 */ + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */ + C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */ + } + } else { + /* Only short-lag bias */ + for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) { + sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 ); /* Q14 */ + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */ + C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */ + } + } + + /* Sort */ + length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 ); + celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ, + length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = (opus_int)C[ 0 ]; /* Q14 */ + if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + RESTORE_STACK; + return 1; + } + + threshold = silk_SMULWB( search_thres1_Q16, Cmax ); + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 ); + } else { + length_d_srch = i; + break; + } + } + celt_assert( length_d_srch > 0 ); + + ALLOC( d_comp, D_COMP_STRIDE, opus_int16 ); + for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) { + d_comp[ i - D_COMP_MIN ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1; + } + + /* Convolution */ + for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) { + d_comp[ i - D_COMP_MIN ] += + d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ]; + } + + length_d_srch = 0; + for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) { + if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) { + d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ] + + d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ]; + } + + length_d_comp = 0; + for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) { + if( d_comp[ i - D_COMP_MIN ] > 0 ) { + d_comp[ length_d_comp ] = i - 2; + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) ); + + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + for( k = 0; k < nb_subfr; k++ ) { + + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_8kHz ); + celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz ); + + energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ), 1 ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_8kHz ); + silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz ); + + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ); + if( cross_corr > 0 ) { + energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ); + matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = + (opus_int16)silk_DIV32_varQ( cross_corr, + silk_ADD32( energy_target, + energy_basis ), + 13 + 1 ); /* Q13 */ + } else { + matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0; + } + } + target_ptr += SF_LENGTH_8KHZ; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = silk_int32_MIN; + CCmax_b = silk_int32_MIN; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 ); + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag ); + } else { + prevLag_log2_Q7 = 0; + } + silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) ); + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[ j ] = 0; + for( i = 0; i < nb_subfr; i++ ) { + opus_int d_subfr; + /* Try all codebooks */ + d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size ); + CC[ j ] = CC[ j ] + + (opus_int32)matrix_ptr( C, i, + d_subfr - ( MIN_LAG_8KHZ - 2 ), + CSTRIDE_8KHZ ); + } + } + /* Find best codebook */ + CCmax_new = silk_int32_MIN; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2_Q7 = silk_lin2log( d ); /* Q7 */ + silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) ); + silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) ); + CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */ + + /* Bias towards previous lag */ + silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) ); + if( prevLag > 0 ) { + delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; + silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) ); + delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 ); + prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */ + prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) ); + CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */ + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 ) && /* Correlation needs to be high enough to be voiced */ + silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ /* Lag must be in range */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + RESTORE_STACK; + return 1; + } + + /* Output normalized correlation */ + *LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 ); + silk_assert( *LTPCorr_Q15 >= 0 ); + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + CBimax_old = CBimax; + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 ); + } else if( Fs_kHz == 16 ) { + lag = silk_LSHIFT( lag, 1 ); + } else { + lag = silk_SMULBB( lag, 3 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + + CCmax = silk_int32_MIN; + /* pitch lags according to second stage */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ]; + } + + /* Set up codebook parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + /* Calculate the correlations and energies needed in stage 3 */ + ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals ); + ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals ); + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag ); + + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ]; + energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length, arch ), 1 ); + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0; + energy = energy_target; + for( k = 0; k < nb_subfr; k++ ) { + cross_corr = silk_ADD32( cross_corr, + matrix_ptr( cross_corr_st3, k, j, + nb_cbk_search )[ lag_counter ] ); + energy = silk_ADD32( energy, + matrix_ptr( energies_st3, k, j, + nb_cbk_search )[ lag_counter ] ); + silk_assert( energy >= 0 ); + } + if( cross_corr > 0 ) { + CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 ); /* Q13 */ + /* Reduce depending on flatness of contour */ + diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j ); /* Q15 */ + silk_assert( diff == silk_SAT16( diff ) ); + CCmax_new = silk_SMULWB( CCmax_new, diff ); /* Q14 */ + } else { + CCmax_new = 0; + } + + if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 ); + } + *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ ); + *contourIndex = (opus_int8)CBimax; + } + celt_assert( *lagIndex >= 0 ); + /* return as voiced */ + RESTORE_STACK; + return 0; +} + +/*********************************************************************** + * Calculates the correlations used in stage 3 search. In order to cover + * the whole lag codebook for all the searched offset lags (lag +- 2), + * the following correlations are needed in each sub frame: + * + * sf1: lag range [-8,...,7] total 16 correlations + * sf2: lag range [-4,...,4] total 9 correlations + * sf3: lag range [-3,....4] total 8 correltions + * sf4: lag range [-6,....8] total 15 correlations + * + * In total 48 correlations. The direct implementation computed in worst + * case 4*12*5 = 240 correlations, but more likely around 120. + ***********************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const opus_int16 *target_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + VARDECL( opus_int32, scratch_mem ); + VARDECL( opus_int32, xcorr32 ); + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + SAVE_STACK; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 ); + ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 ); + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + celt_assert(lag_high-lag_low+1 <= SCRATCH_SIZE); + celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch ); + for( j = lag_low; j <= lag_high; j++ ) { + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ]; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] = + scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } + RESTORE_STACK; +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +static void silk_P_Ana_calc_energy_st3( + silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + VARDECL( opus_int32, scratch_mem ); + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + SAVE_STACK; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 ); + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length, arch ); + silk_assert( energy >= 0 ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] ); + silk_assert( energy >= 0 ); + + /* add part that comes into window */ + energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) ); + silk_assert( energy >= 0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] = + scratch_mem[ idx + j ]; + silk_assert( + matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 ); + } + } + target_ptr += sf_length; + } + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/fixed/process_gains_FIX.c b/native/codec/libraries/opus/silk/fixed/process_gains_FIX.c new file mode 100644 index 0000000..05aba31 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/process_gains_FIX.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ + s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); + } + } + + /* Limit the quantized signal */ + /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */ + InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin( + silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + ResNrg = psEncCtrl->ResNrg[ k ]; + ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); + if( psEncCtrl->ResNrgQ[ k ] > 0 ) { + ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); + } else { + if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { + ResNrgPart = silk_int32_MAX; + } else { + ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); + } + } + gain = psEncCtrl->Gains_Q16[ k ]; + gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) ); + if( gain_squared < silk_int16_MAX ) { + /* recalculate with higher precision */ + gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain ); + silk_assert( gain_squared > 0 ); + gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */ + gain = silk_min( gain, silk_int32_MAX >> 8 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */ + } else { + gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */ + gain = silk_min( gain, silk_int32_MAX >> 16 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */ + } + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ]; + psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 ) + + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 ); + + silk_assert( psEncCtrl->Lambda_Q10 > 0 ); + silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) ); +} diff --git a/native/codec/libraries/opus/silk/fixed/regularize_correlations_FIX.c b/native/codec/libraries/opus/silk/fixed/regularize_correlations_FIX.c new file mode 100644 index 0000000..a2836b0 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/regularize_correlations_FIX.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FIX( + opus_int32 *XX, /* I/O Correlation matrices */ + opus_int32 *xx, /* I/O Correlation values */ + opus_int32 noise, /* I Noise to add */ + opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise ); + } + xx[ 0 ] += noise; +} diff --git a/native/codec/libraries/opus/silk/fixed/residual_energy16_FIX.c b/native/codec/libraries/opus/silk/fixed/residual_energy16_FIX.c new file mode 100644 index 0000000..7f130f3 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/residual_energy16_FIX.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +) +{ + opus_int i, j, lshifts, Qxtra; + opus_int32 c_max, w_max, tmp, tmp2, nrg; + opus_int cn[ MAX_MATRIX_SIZE ]; + const opus_int32 *pRow; + + /* Safety checks */ + celt_assert( D >= 0 ); + celt_assert( D <= 16 ); + celt_assert( cQ > 0 ); + celt_assert( cQ < 16 ); + + lshifts = 16 - cQ; + Qxtra = lshifts; + + c_max = 0; + for( i = 0; i < D; i++ ) { + c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) ); + } + Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 ); + + w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); + Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); + Qxtra = silk_max_int( Qxtra, 0 ); + for( i = 0; i < D; i++ ) { + cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra ); + silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */ + } + lshifts -= Qxtra; + + /* Compute wxx - 2 * wXx * c */ + tmp = 0; + for( i = 0; i < D; i++ ) { + tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] ); + } + nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */ + + /* Add c' * wXX * c, assuming wXX is symmetric */ + tmp2 = 0; + for( i = 0; i < D; i++ ) { + tmp = 0; + pRow = &wXX[ i * D ]; + for( j = i + 1; j < D; j++ ) { + tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] ); + } + tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); + tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] ); + } + nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */ + + /* Keep one bit free always, because we add them for LSF interpolation */ + if( nrg < 1 ) { + nrg = 1; + } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) { + nrg = silk_int32_MAX >> 1; + } else { + nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */ + } + return nrg; + +} diff --git a/native/codec/libraries/opus/silk/fixed/residual_energy_FIX.c b/native/codec/libraries/opus/silk/fixed/residual_energy_FIX.c new file mode 100644 index 0000000..6c7cade --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/residual_energy_FIX.c @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +) +{ + opus_int offset, i, j, rshift, lz1, lz2; + opus_int16 *LPC_res_ptr; + VARDECL( opus_int16, LPC_res ); + const opus_int16 *x_ptr; + opus_int32 tmp32; + SAVE_STACK; + + x_ptr = x; + offset = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 ); + celt_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr ); + for( i = 0; i < nb_subfr >> 1; i++ ) { + /* Calculate half frame LPC residual signal including preceding samples */ + silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order, arch ); + + /* Point to first subframe of the just calculated LPC residual signal */ + LPC_res_ptr = LPC_res + LPC_order; + for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) { + /* Measure subframe energy */ + silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length ); + + /* Set Q values for the measured energy */ + nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift; + + /* Move to next subframe */ + LPC_res_ptr += offset; + } + /* Move to next frame half */ + x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset; + } + + /* Apply the squared subframe gains */ + for( i = 0; i < nb_subfr; i++ ) { + /* Fully upscale gains and energies */ + lz1 = silk_CLZ32( nrgs[ i ] ) - 1; + lz2 = silk_CLZ32( gains[ i ] ) - 1; + + tmp32 = silk_LSHIFT32( gains[ i ], lz2 ); + + /* Find squared gains */ + tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/ + + /* Scale energies */ + nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/ + nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32; + } + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/fixed/schur64_FIX.c b/native/codec/libraries/opus/silk/fixed/schur64_FIX.c new file mode 100644 index 0000000..4b7e19e --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/schur64_FIX.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Check for invalid input */ + if( c[ 0 ] <= 0 ) { + silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) ); + return 0; + } + + k = 0; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } while( ++k <= order ); + + for( k = 0; k < order; k++ ) { + /* Check that we won't be getting an unstable rc, otherwise stop here. */ + if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) { + if ( C[ k + 1 ][ 0 ] > 0 ) { + rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 ); + } else { + rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 ); + } + k++; + break; + } + + /* Get reflection coefficient: divide two Q30 values and get result in Q31 */ + rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 ); + + /* Save the output */ + rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 ); + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1_Q30 = C[ n + k + 1 ][ 0 ]; + Ctmp2_Q30 = C[ n ][ 1 ]; + + /* Multiply and add the highest int32 */ + C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 ); + C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 ); + } + } + + for(; k < order; k++ ) { + rc_Q16[ k ] = 0; + } + + return silk_max_32( 1, C[ 0 ][ 1 ] ); +} diff --git a/native/codec/libraries/opus/silk/fixed/schur_FIX.c b/native/codec/libraries/opus/silk/fixed/schur_FIX.c new file mode 100644 index 0000000..2840f6b --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/schur_FIX.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +) +{ + opus_int k, n, lz; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Get number of leading zeros */ + lz = silk_CLZ32( c[ 0 ] ); + + /* Copy correlations and adjust level to Q30 */ + k = 0; + if( lz < 2 ) { + /* lz must be 1, so shift one to the right */ + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 ); + } while( ++k <= order ); + } else if( lz > 2 ) { + /* Shift to the left */ + lz -= 2; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz ); + } while( ++k <= order ); + } else { + /* No need to shift */ + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } while( ++k <= order ); + } + + for( k = 0; k < order; k++ ) { + /* Check that we won't be getting an unstable rc, otherwise stop here. */ + if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) { + if ( C[ k + 1 ][ 0 ] > 0 ) { + rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 ); + } else { + rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 ); + } + k++; + break; + } + + /* Get reflection coefficient */ + rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) ); + + /* Clip (shouldn't happen for properly conditioned inputs) */ + rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 ); + + /* Store */ + rc_Q15[ k ] = (opus_int16)rc_tmp_Q15; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 ); + C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 ); + } + } + + for(; k < order; k++ ) { + rc_Q15[ k ] = 0; + } + + /* return residual energy */ + return silk_max_32( 1, C[ 0 ][ 1 ] ); +} diff --git a/native/codec/libraries/opus/silk/fixed/structs_FIX.h b/native/codec/libraries/opus/silk/fixed/structs_FIX.h new file mode 100644 index 0000000..2774a97 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/structs_FIX.h @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FIX_H +#define SILK_STRUCTS_FIX_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + opus_int32 HarmBoost_smth_Q16; + opus_int32 HarmShapeGain_smth_Q16; + opus_int32 Tilt_smth_Q16; +} silk_shape_state_FIX; + +/********************************/ +/* Encoder state FIX */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with floating-point code */ + silk_shape_state_FIX sShape; /* Shape state */ + + /* Buffer for find pitch and noise shape analysis */ + silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */ + opus_int32 resNrgSmth; +} silk_encoder_state_FIX; + +/************************/ +/* Encoder control FIX */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + /* Testing */ + silk_DWORD_ALIGN opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + opus_int Lambda_Q10; + opus_int input_quality_Q14; + opus_int coding_quality_Q14; + + /* measures */ + opus_int32 predGain_Q16; + opus_int LTPredCodGain_Q7; + opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FIX; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsUsedLBRR; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/fixed/vector_ops_FIX.c b/native/codec/libraries/opus/silk/fixed/vector_ops_FIX.c new file mode 100644 index 0000000..d949800 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/vector_ops_FIX.c @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "pitch.h" + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +) +{ + opus_int i; + opus_int32 tmp32; + + for( i = 0; i < dataSize; i++ ) { + tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] ); + data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 ); + } +} + +/* Multiply a vector by a constant */ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +) +{ + opus_int i; + + for( i = 0; i < dataSize; i++ ) { + data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */ + } +} + +/* sum = for(i=0;i6, memory access can be reduced by half. */ +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len, /* I vector lengths */ + int arch /* I Run-time architecture */ +) +{ +#ifdef FIXED_POINT + return celt_inner_prod(inVec1, inVec2, len, arch); +#else + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +#endif +} + +opus_int64 silk_inner_prod16_aligned_64_c( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int64 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} diff --git a/native/codec/libraries/opus/silk/fixed/warped_autocorrelation_FIX.c b/native/codec/libraries/opus/silk/fixed/warped_autocorrelation_FIX.c new file mode 100644 index 0000000..5c79553 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/warped_autocorrelation_FIX.c @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +#if defined(MIPSr1_ASM) +#include "mips/warped_autocorrelation_FIX_mipsr1.h" +#endif + + +/* Autocorrelations for a warped frequency axis */ +#ifndef OVERRIDE_silk_warped_autocorrelation_FIX_c +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS, tmp2_QS; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + + lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) ); + } + } + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} +#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */ diff --git a/native/codec/libraries/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c b/native/codec/libraries/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c new file mode 100644 index 0000000..bbb1ce0 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c @@ -0,0 +1,377 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "SigProc_FIX.h" +#include "define.h" +#include "tuning_parameters.h" +#include "pitch.h" +#include "celt/x86/x86cpu.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#define QA 25 +#define N_BITS_HEAD_ROOM 2 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_sse4_1( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) +{ + opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + + __m128i FIRST_3210, LAST_3210, ATMP_3210, TMP1_3210, TMP2_3210, T1_3210, T2_3210, PTR_3210, SUBFR_3210, X1_3210, X2_3210; + __m128i CONST1 = _mm_set1_epi32(1); + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); + if( rshifts > MAX_RSHIFTS ) { + C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); + silk_assert( C0 > 0 ); + rshifts = MAX_RSHIFTS; + } else { + lz = silk_CLZ32( C0 ) - 1; + rshifts_extra = N_BITS_HEAD_ROOM - lz; + if( rshifts_extra > 0 ) { + rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts ); + C0 = silk_RSHIFT32( C0, rshifts_extra ); + } else { + rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts ); + C0 = silk_LSHIFT32( C0, -rshifts_extra ); + } + rshifts += rshifts_extra; + } + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64( + silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts ); + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + int i; + opus_int32 d; + x_ptr = x + s * subfr_length; + celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch ); + for( n = 1; n < D + 1; n++ ) { + for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ ) + d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] ); + xcorr[ n - 1 ] += d; + } + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = (opus_int32)1 << 30; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */ + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + + X1_3210 = _mm_set1_epi32( x1 ); + X2_3210 = _mm_set1_epi32( x2 ); + TMP1_3210 = _mm_setzero_si128(); + TMP2_3210 = _mm_setzero_si128(); + for( k = 0; k < n - 3; k += 4 ) { + PTR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 1 - 3 ] ); + SUBFR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k ] ); + FIRST_3210 = _mm_loadu_si128( (__m128i *)&C_first_row[ k ] ); + PTR_3210 = _mm_shuffle_epi32( PTR_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + LAST_3210 = _mm_loadu_si128( (__m128i *)&C_last_row[ k ] ); + ATMP_3210 = _mm_loadu_si128( (__m128i *)&Af_QA[ k ] ); + + T1_3210 = _mm_mullo_epi32( PTR_3210, X1_3210 ); + T2_3210 = _mm_mullo_epi32( SUBFR_3210, X2_3210 ); + + ATMP_3210 = _mm_srai_epi32( ATMP_3210, 7 ); + ATMP_3210 = _mm_add_epi32( ATMP_3210, CONST1 ); + ATMP_3210 = _mm_srai_epi32( ATMP_3210, 1 ); + + FIRST_3210 = _mm_add_epi32( FIRST_3210, T1_3210 ); + LAST_3210 = _mm_add_epi32( LAST_3210, T2_3210 ); + + PTR_3210 = _mm_mullo_epi32( ATMP_3210, PTR_3210 ); + SUBFR_3210 = _mm_mullo_epi32( ATMP_3210, SUBFR_3210 ); + + _mm_storeu_si128( (__m128i *)&C_first_row[ k ], FIRST_3210 ); + _mm_storeu_si128( (__m128i *)&C_last_row[ k ], LAST_3210 ); + + TMP1_3210 = _mm_add_epi32( TMP1_3210, PTR_3210 ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, SUBFR_3210 ); + } + + TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_unpackhi_epi64(TMP1_3210, TMP1_3210 ) ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_unpackhi_epi64(TMP2_3210, TMP2_3210 ) ); + TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_shufflelo_epi16(TMP1_3210, 0x0E ) ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_shufflelo_epi16(TMP2_3210, 0x0E ) ); + + tmp1 += _mm_cvtsi128_si32( TMP1_3210 ); + tmp2 += _mm_cvtsi128_si32( TMP2_3210 ); + + for( ; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + + { + __m128i xmm_tmp1, xmm_tmp2; + __m128i xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1; + __m128i xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1; + + xmm_tmp1 = _mm_set1_epi32( tmp1 ); + xmm_tmp2 = _mm_set1_epi32( tmp2 ); + + for( k = 0; k <= n - 3; k += 4 ) { + xmm_x_ptr_n_k_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 3 ] ); + xmm_x_ptr_sub_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k - 1 ] ); + + xmm_x_ptr_n_k_x2x0 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + xmm_x_ptr_n_k_x2x0 = _mm_slli_epi32( xmm_x_ptr_n_k_x2x0, -rshifts - 1 ); + xmm_x_ptr_sub_x2x0 = _mm_slli_epi32( xmm_x_ptr_sub_x2x0, -rshifts - 1 ); + + /* equal shift right 4 bytes, xmm_x_ptr_n_k_x3x1 = _mm_srli_si128(xmm_x_ptr_n_k_x2x0, 4)*/ + xmm_x_ptr_n_k_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + xmm_x_ptr_sub_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_sub_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_ptr_n_k_x2x0 = _mm_mul_epi32( xmm_x_ptr_n_k_x2x0, xmm_tmp1 ); + xmm_x_ptr_n_k_x3x1 = _mm_mul_epi32( xmm_x_ptr_n_k_x3x1, xmm_tmp1 ); + xmm_x_ptr_sub_x2x0 = _mm_mul_epi32( xmm_x_ptr_sub_x2x0, xmm_tmp2 ); + xmm_x_ptr_sub_x3x1 = _mm_mul_epi32( xmm_x_ptr_sub_x3x1, xmm_tmp2 ); + + xmm_x_ptr_n_k_x2x0 = _mm_srli_epi64( xmm_x_ptr_n_k_x2x0, 16 ); + xmm_x_ptr_n_k_x3x1 = _mm_slli_epi64( xmm_x_ptr_n_k_x3x1, 16 ); + xmm_x_ptr_sub_x2x0 = _mm_srli_epi64( xmm_x_ptr_sub_x2x0, 16 ); + xmm_x_ptr_sub_x3x1 = _mm_slli_epi64( xmm_x_ptr_sub_x3x1, 16 ); + + xmm_x_ptr_n_k_x2x0 = _mm_blend_epi16( xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1, 0xCC ); + xmm_x_ptr_sub_x2x0 = _mm_blend_epi16( xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1, 0xCC ); + + X1_3210 = _mm_loadu_si128( (__m128i *)&CAf[ k ] ); + PTR_3210 = _mm_loadu_si128( (__m128i *)&CAb[ k ] ); + + X1_3210 = _mm_add_epi32( X1_3210, xmm_x_ptr_n_k_x2x0 ); + PTR_3210 = _mm_add_epi32( PTR_3210, xmm_x_ptr_sub_x2x0 ); + + _mm_storeu_si128( (__m128i *)&CAf[ k ], X1_3210 ); + _mm_storeu_si128( (__m128i *)&CAb[ k ], PTR_3210 ); + } + + for( ; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */ + } + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */ + tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */ + num = 0; /* Q( -rshifts ) */ + nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */ + } + CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */ + CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */ + num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + if( rc_Q31 > 0 ) { + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; /* QA */ + tmp2 = Af_QA[ n - k - 1 ]; /* QA */ + Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; /* Q( -rshifts ) */ + tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */ + CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch ), -rshifts ); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = (opus_int32)1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/native/codec/libraries/opus/silk/fixed/x86/prefilter_FIX_sse.c b/native/codec/libraries/opus/silk/fixed/x86/prefilter_FIX_sse.c new file mode 100644 index 0000000..555432c --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/x86/prefilter_FIX_sse.c @@ -0,0 +1,160 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +void silk_warped_LPC_analysis_filter_FIX_sse4_1( + opus_int32 state[], /* I/O State [order + 1] */ + opus_int32 res_Q2[], /* O Residual signal [length] */ + const opus_int16 coef_Q13[], /* I Coefficients [order] */ + const opus_int16 input[], /* I Input signal [length] */ + const opus_int16 lambda_Q16, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order /* I Filter order (even) */ +) +{ + opus_int n, i; + opus_int32 acc_Q11, tmp1, tmp2; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + + if (order == 10) + { + if (0 == lambda_Q16) + { + __m128i coef_Q13_3210, coef_Q13_7654; + __m128i coef_Q13_0123, coef_Q13_4567; + __m128i state_0123, state_4567; + __m128i xmm_product1, xmm_product2; + __m128i xmm_tempa, xmm_tempb; + + register opus_int32 sum; + register opus_int32 state_8, state_9, state_a; + register opus_int64 coef_Q13_8, coef_Q13_9; + + celt_assert( length > 0 ); + + coef_Q13_3210 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 0 ] ); + coef_Q13_7654 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 4 ] ); + + coef_Q13_0123 = _mm_shuffle_epi32( coef_Q13_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + coef_Q13_4567 = _mm_shuffle_epi32( coef_Q13_7654, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + coef_Q13_8 = (opus_int64) coef_Q13[ 8 ]; + coef_Q13_9 = (opus_int64) coef_Q13[ 9 ]; + + state_0123 = _mm_loadu_si128( (__m128i *)(&state[ 0 ] ) ); + state_4567 = _mm_loadu_si128( (__m128i *)(&state[ 4 ] ) ); + + state_0123 = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + state_4567 = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + state_8 = state[ 8 ]; + state_9 = state[ 9 ]; + state_a = 0; + + for( n = 0; n < length; n++ ) + { + xmm_product1 = _mm_mul_epi32( coef_Q13_0123, state_0123 ); /* 64-bit multiply, only 2 pairs */ + xmm_product2 = _mm_mul_epi32( coef_Q13_4567, state_4567 ); + + xmm_tempa = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + xmm_tempb = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + xmm_product1 = _mm_srli_epi64( xmm_product1, 16 ); /* >> 16, zero extending works */ + xmm_product2 = _mm_srli_epi64( xmm_product2, 16 ); + + xmm_tempa = _mm_mul_epi32( coef_Q13_3210, xmm_tempa ); + xmm_tempb = _mm_mul_epi32( coef_Q13_7654, xmm_tempb ); + + xmm_tempa = _mm_srli_epi64( xmm_tempa, 16 ); + xmm_tempb = _mm_srli_epi64( xmm_tempb, 16 ); + + xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_product1 ); + xmm_tempb = _mm_add_epi32( xmm_tempb, xmm_product2 ); + xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_tempb ); + + sum = (opus_int32)((coef_Q13_8 * state_8) >> 16); + sum += (opus_int32)((coef_Q13_9 * state_9) >> 16); + + xmm_tempa = _mm_add_epi32( xmm_tempa, _mm_shuffle_epi32( xmm_tempa, _MM_SHUFFLE( 0, 0, 0, 2 ) ) ); + sum += _mm_cvtsi128_si32( xmm_tempa); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( ( 5 + sum ), 9); + + /* move right */ + state_a = state_9; + state_9 = state_8; + state_8 = _mm_cvtsi128_si32( state_4567 ); + state_4567 = _mm_alignr_epi8( state_0123, state_4567, 4 ); + + state_0123 = _mm_alignr_epi8( _mm_cvtsi32_si128( silk_LSHIFT( input[ n ], 14 ) ), state_0123, 4 ); + } + + _mm_storeu_si128( (__m128i *)( &state[ 0 ] ), _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ) ); + _mm_storeu_si128( (__m128i *)( &state[ 4 ] ), _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ) ); + state[ 8 ] = state_8; + state[ 9 ] = state_9; + state[ 10 ] = state_a; + + return; + } + } + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state[ 0 ] = silk_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state[ 1 ] = tmp2; + acc_Q11 = silk_RSHIFT( order, 1 ); + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state[ i ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state[ i + 1 ] = tmp2; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + } + state[ order ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 ); + } +} diff --git a/native/codec/libraries/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c b/native/codec/libraries/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c new file mode 100644 index 0000000..c1e9056 --- /dev/null +++ b/native/codec/libraries/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" + +#include "SigProc_FIX.h" +#include "pitch.h" + +opus_int64 silk_inner_prod16_aligned_64_sse4_1( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i, dataSize8; + opus_int64 sum; + + __m128i xmm_tempa; + __m128i inVec1_76543210, acc1; + __m128i inVec2_76543210, acc2; + + sum = 0; + dataSize8 = len & ~7; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for( i = 0; i < dataSize8; i += 8 ) { + inVec1_76543210 = _mm_loadu_si128( (__m128i *)(&inVec1[i + 0] ) ); + inVec2_76543210 = _mm_loadu_si128( (__m128i *)(&inVec2[i + 0] ) ); + + /* only when all 4 operands are -32768 (0x8000), this results in wrap around */ + inVec1_76543210 = _mm_madd_epi16( inVec1_76543210, inVec2_76543210 ); + + xmm_tempa = _mm_cvtepi32_epi64( inVec1_76543210 ); + /* equal shift right 8 bytes */ + inVec1_76543210 = _mm_shuffle_epi32( inVec1_76543210, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + inVec1_76543210 = _mm_cvtepi32_epi64( inVec1_76543210 ); + + acc1 = _mm_add_epi64( acc1, xmm_tempa ); + acc2 = _mm_add_epi64( acc2, inVec1_76543210 ); + } + + acc1 = _mm_add_epi64( acc1, acc2 ); + + /* equal shift right 8 bytes */ + acc2 = _mm_shuffle_epi32( acc1, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + acc1 = _mm_add_epi64( acc1, acc2 ); + + _mm_storel_epi64( (__m128i *)&sum, acc1 ); + + for( ; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + + return sum; +} diff --git a/native/codec/libraries/opus/silk/float/LPC_analysis_filter_FLP.c b/native/codec/libraries/opus/silk/float/LPC_analysis_filter_FLP.c new file mode 100644 index 0000000..0e1a1fe --- /dev/null +++ b/native/codec/libraries/opus/silk/float/LPC_analysis_filter_FLP.c @@ -0,0 +1,249 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ + +/* 16th order LPC analysis filter, does not write first 16 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter16_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 16; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ] + + s_ptr[ -12 ] * PredCoef[ 12 ] + + s_ptr[ -13 ] * PredCoef[ 13 ] + + s_ptr[ -14 ] * PredCoef[ 14 ] + + s_ptr[ -15 ] * PredCoef[ 15 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 12th order LPC analysis filter, does not write first 12 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter12_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 12; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 10th order LPC analysis filter, does not write first 10 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter10_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 10; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 8th order LPC analysis filter, does not write first 8 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter8_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 8; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 6th order LPC analysis filter, does not write first 6 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter6_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 6; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +) +{ + celt_assert( Order <= length ); + + switch( Order ) { + case 6: + silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length ); + break; + + case 8: + silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length ); + break; + + case 10: + silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length ); + break; + + case 12: + silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length ); + break; + + case 16: + silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length ); + break; + + default: + celt_assert( 0 ); + break; + } + + /* Set first Order output samples to zero */ + silk_memset( r_LPC, 0, Order * sizeof( silk_float ) ); +} + diff --git a/native/codec/libraries/opus/silk/float/LPC_inv_pred_gain_FLP.c b/native/codec/libraries/opus/silk/float/LPC_inv_pred_gain_FLP.c new file mode 100644 index 0000000..2be2122 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/LPC_inv_pred_gain_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "SigProc_FLP.h" +#include "define.h" + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_a2k_FLP() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + double invGain, rc, rc_mult1, rc_mult2, tmp1, tmp2; + silk_float Atmp[ SILK_MAX_ORDER_LPC ]; + + silk_memcpy( Atmp, A, order * sizeof(silk_float) ); + + invGain = 1.0; + for( k = order - 1; k > 0; k-- ) { + rc = -Atmp[ k ]; + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; + if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) { + return 0.0f; + } + rc_mult2 = 1.0f / rc_mult1; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = Atmp[ n ]; + tmp2 = Atmp[ k - n - 1 ]; + Atmp[ n ] = (silk_float)( ( tmp1 - tmp2 * rc ) * rc_mult2 ); + Atmp[ k - n - 1 ] = (silk_float)( ( tmp2 - tmp1 * rc ) * rc_mult2 ); + } + } + rc = -Atmp[ 0 ]; + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; + if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) { + return 0.0f; + } + return (silk_float)invGain; +} diff --git a/native/codec/libraries/opus/silk/float/LTP_analysis_filter_FLP.c b/native/codec/libraries/opus/silk/float/LTP_analysis_filter_FLP.c new file mode 100644 index 0000000..849b7c1 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/LTP_analysis_filter_FLP.c @@ -0,0 +1,75 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceding samples for each subframe */ +) +{ + const silk_float *x_ptr, *x_lag_ptr; + silk_float Btmp[ LTP_ORDER ]; + silk_float *LTP_res_ptr; + silk_float inv_gain; + opus_int k, i, j; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + x_lag_ptr = x_ptr - pitchL[ k ]; + inv_gain = invGains[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp[ i ] = B[ k * LTP_ORDER + i ]; + } + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + /* Subtract long-term prediction */ + for( j = 0; j < LTP_ORDER; j++ ) { + LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ]; + } + LTP_res_ptr[ i ] *= inv_gain; + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} diff --git a/native/codec/libraries/opus/silk/float/LTP_scale_ctrl_FLP.c b/native/codec/libraries/opus/silk/float/LTP_scale_ctrl_FLP.c new file mode 100644 index 0000000..8dbe29d --- /dev/null +++ b/native/codec/libraries/opus/silk/float/LTP_scale_ctrl_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + + psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f; +} diff --git a/native/codec/libraries/opus/silk/float/SigProc_FLP.h b/native/codec/libraries/opus/silk/float/SigProc_FLP.h new file mode 100644 index 0000000..953de8b --- /dev/null +++ b/native/codec/libraries/opus/silk/float/SigProc_FLP.h @@ -0,0 +1,197 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FLP_H +#define SILK_SIGPROC_FLP_H + +#include "SigProc_FIX.h" +#include "float_cast.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +); + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_FLP_a2k() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +); + +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +); + +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I Number of 5 ms subframes */ + int arch /* I Run-time architecture */ +); + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +); + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +); + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +); + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +); + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +#define PI (3.1415926536f) + +#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b)) +#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b)) +#define silk_abs_float( a ) ((silk_float)fabs(a)) + +/* sigmoid function */ +static OPUS_INLINE silk_float silk_sigmoid( silk_float x ) +{ + return (silk_float)(1.0 / (1.0 + exp(-x))); +} + +/* floating-point to integer conversion (rounding) */ +static OPUS_INLINE opus_int32 silk_float2int( silk_float x ) +{ + return (opus_int32)float2int( x ); +} + +/* floating-point to integer conversion (rounding) */ +static OPUS_INLINE void silk_float2short_array( + opus_int16 *out, + const silk_float *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) ); + } +} + +/* integer to floating-point conversion */ +static OPUS_INLINE void silk_short2float_array( + silk_float *out, + const opus_int16 *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = (silk_float)in[k]; + } +} + +/* using log2() helps the fixed-point conversion */ +static OPUS_INLINE silk_float silk_log2( double x ) +{ + return ( silk_float )( 3.32192809488736 * log10( x ) ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FLP_H */ diff --git a/native/codec/libraries/opus/silk/float/apply_sine_window_FLP.c b/native/codec/libraries/opus/silk/float/apply_sine_window_FLP.c new file mode 100644 index 0000000..e49e717 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/apply_sine_window_FLP.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Apply sine window to signal vector */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k; + silk_float freq, c, S0, S1; + + celt_assert( win_type == 1 || win_type == 2 ); + + /* Length must be multiple of 4 */ + celt_assert( ( length & 3 ) == 0 ); + + freq = PI / ( length + 1 ); + + /* Approximation of 2 * cos(f) */ + c = 2.0f - freq * freq; + + /* Initialize state */ + if( win_type < 2 ) { + /* Start from 0 */ + S0 = 0.0f; + /* Approximation of sin(f) */ + S1 = freq; + } else { + /* Start from 1 */ + S0 = 1.0f; + /* Approximation of cos(f) */ + S1 = 0.5f * c; + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 ); + px_win[ k + 1 ] = px[ k + 1 ] * S1; + S0 = c * S1 - S0; + px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 ); + px_win[ k + 3 ] = px[ k + 3 ] * S0; + S1 = c * S0 - S1; + } +} diff --git a/native/codec/libraries/opus/silk/float/autocorrelation_FLP.c b/native/codec/libraries/opus/silk/float/autocorrelation_FLP.c new file mode 100644 index 0000000..8b8a9e6 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/autocorrelation_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "SigProc_FLP.h" + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +) +{ + opus_int i; + + if( correlationCount > inputDataSize ) { + correlationCount = inputDataSize; + } + + for( i = 0; i < correlationCount; i++ ) { + results[ i ] = (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i ); + } +} diff --git a/native/codec/libraries/opus/silk/float/burg_modified_FLP.c b/native/codec/libraries/opus/silk/float/burg_modified_FLP.c new file mode 100644 index 0000000..756b76a --- /dev/null +++ b/native/codec/libraries/opus/silk/float/burg_modified_FLP.c @@ -0,0 +1,186 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" +#include "tuning_parameters.h" +#include "define.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/ + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +) +{ + opus_int k, n, s, reached_max_gain; + double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; + const silk_float *x_ptr; + double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ]; + double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ]; + double Af[ SILK_MAX_ORDER_LPC ]; + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0 = silk_energy_FLP( x, nb_subfr * subfr_length ); + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) ); + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f; + invGain = 1.0f; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + tmp1 = x_ptr[ n ]; + tmp2 = x_ptr[ subfr_length - n - 1 ]; + for( k = 0; k < n; k++ ) { + C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ]; + C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ]; + Atmp = Af[ k ]; + tmp1 += x_ptr[ n - k - 1 ] * Atmp; + tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; + } + for( k = 0; k <= n; k++ ) { + CAf[ k ] -= tmp1 * x_ptr[ n - k ]; + CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ]; + } + } + tmp1 = C_first_row[ n ]; + tmp2 = C_last_row[ n ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + tmp1 += C_last_row[ n - k - 1 ] * Atmp; + tmp2 += C_first_row[ n - k - 1 ] * Atmp; + } + CAf[ n + 1 ] = tmp1; + CAb[ n + 1 ] = tmp2; + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + num = CAb[ n + 1 ]; + nrg_b = CAb[ 0 ]; + nrg_f = CAf[ 0 ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + num += CAb[ n - k ] * Atmp; + nrg_b += CAb[ k + 1 ] * Atmp; + nrg_f += CAf[ k + 1 ] * Atmp; + } + silk_assert( nrg_f > 0.0 ); + silk_assert( nrg_b > 0.0 ); + + /* Calculate the next order reflection (parcor) coefficient */ + rc = -2.0 * num / ( nrg_f + nrg_b ); + silk_assert( rc > -1.0 && rc < 1.0 ); + + /* Update inverse prediction gain */ + tmp1 = invGain * ( 1.0 - rc * rc ); + if( tmp1 <= minInvGain ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + rc = sqrt( 1.0 - minInvGain / invGain ); + if( num > 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc = -rc; + } + invGain = minInvGain; + reached_max_gain = 1; + } else { + invGain = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af[ k ]; + tmp2 = Af[ n - k - 1 ]; + Af[ k ] = tmp1 + rc * tmp2; + Af[ n - k - 1 ] = tmp2 + rc * tmp1; + } + Af[ n ] = rc; + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af[ k ] = 0.0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; + CAf[ k ] += rc * CAb[ n - k + 1 ]; + CAb[ n - k + 1 ] += rc * tmp1; + } + } + + if( reached_max_gain ) { + /* Convert to silk_float */ + for( k = 0; k < D; k++ ) { + A[ k ] = (silk_float)( -Af[ k ] ); + } + /* Subtract energy of preceding samples from C0 */ + for( s = 0; s < nb_subfr; s++ ) { + C0 -= silk_energy_FLP( x + s * subfr_length, D ); + } + /* Approximate residual energy */ + nrg_f = C0 * invGain; + } else { + /* Compute residual energy and store coefficients as silk_float */ + nrg_f = CAf[ 0 ]; + tmp1 = 1.0; + for( k = 0; k < D; k++ ) { + Atmp = Af[ k ]; + nrg_f += CAf[ k + 1 ] * Atmp; + tmp1 += Atmp * Atmp; + A[ k ] = (silk_float)(-Atmp); + } + nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1; + } + + /* Return residual energy */ + return (silk_float)nrg_f; +} diff --git a/native/codec/libraries/opus/silk/float/bwexpander_FLP.c b/native/codec/libraries/opus/silk/float/bwexpander_FLP.c new file mode 100644 index 0000000..d55a4d7 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/bwexpander_FLP.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +) +{ + opus_int i; + silk_float cfac = chirp; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] *= cfac; + cfac *= chirp; + } + ar[ d - 1 ] *= cfac; +} diff --git a/native/codec/libraries/opus/silk/float/corrMatrix_FLP.c b/native/codec/libraries/opus/silk/float/corrMatrix_FLP.c new file mode 100644 index 0000000..eae6a1c --- /dev/null +++ b/native/codec/libraries/opus/silk/float/corrMatrix_FLP.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation matrix computations for LS estimate. + **********************************************************************/ + +#include "main_FLP.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +) +{ + opus_int lag; + const silk_float *ptr1; + + ptr1 = &x[ Order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + for( lag = 0; lag < Order; lag++ ) { + /* Calculate X[:,lag]'*t */ + Xt[ lag ] = (silk_float)silk_inner_product_FLP( ptr1, t, L ); + ptr1--; /* Next column of X */ + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +) +{ + opus_int j, lag; + double energy; + const silk_float *ptr1, *ptr2; + + ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */ + energy = silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */ + matrix_ptr( XX, 0, 0, Order ) = ( silk_float )energy; + for( j = 1; j < Order; j++ ) { + /* Calculate X[:,j]'*X[:,j] */ + energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ]; + matrix_ptr( XX, j, j, Order ) = ( silk_float )energy; + } + + ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */ + for( lag = 1; lag < Order; lag++ ) { + /* Calculate X[:,0]'*X[:,lag] */ + energy = silk_inner_product_FLP( ptr1, ptr2, L ); + matrix_ptr( XX, lag, 0, Order ) = ( silk_float )energy; + matrix_ptr( XX, 0, lag, Order ) = ( silk_float )energy; + /* Calculate X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( Order - lag ); j++ ) { + energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ]; + matrix_ptr( XX, lag + j, j, Order ) = ( silk_float )energy; + matrix_ptr( XX, j, lag + j, Order ) = ( silk_float )energy; + } + ptr2--; /* Next column of X */ + } +} diff --git a/native/codec/libraries/opus/silk/float/encode_frame_FLP.c b/native/codec/libraries/opus/silk/float/encode_frame_FLP.c new file mode 100644 index 0000000..b029c3f --- /dev/null +++ b/native/codec/libraries/opus/silk/float/encode_frame_FLP.c @@ -0,0 +1,435 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FLP sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + silk_float *x_frame, *res_pitch_frame; + silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + opus_uint8 ec_buf_copy[ 1275 ]; + opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; + opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; + opus_int best_sum[ MAX_NB_SUBFR ]; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /**************************************************************/ + /* pointers aligned with start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */ + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */ + for( i = 0; i < 8; i++ ) { + x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f; + } + + if( !psEnc->sCmn.prefillFlag ) { + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FLP( psEnc, &sEncCtrl, x_frame, condCoding ); + + /* Loop over quantizer and entroy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, x_frame ); + + if ( iter == maxIter && !found_lower ) { + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + /* If we still bust after the last iteration, do some damage control. */ + if ( iter == maxIter && !found_lower && nBits > maxBits ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + + /* Keep gains the same as the last frame. */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + psEnc->sCmn.indices.GainsIndices[ i ] = 4; + } + if (condCoding != CODE_CONDITIONALLY) { + psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev; + } + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + /* Clear all pulses. */ + for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + psEnc->sCmn.pulses[ i ] = 0; + } + + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + } + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + celt_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda = silk_max_float(sEncCtrl.Lambda*1.5f, 1.5f); + /* Reducing dithering can help us hit the target. */ + psEnc->sCmn.indices.quantOffsetType = 0; + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + celt_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if ( !found_lower && nBits > maxBits ) { + int j; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + int sum=0; + for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) { + sum += abs( psEnc->sCmn.pulses[j] ); + } + if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) { + best_sum[i] = sum; + best_gain_mult[i] = gainMult_Q8; + } else { + gain_lock[i] = 1; + } + } + } + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + if( nBits > maxBits ) { + if (gainMult_Q8 < 16384) { + gainMult_Q8 *= 2; + } else { + gainMult_Q8 = 32767; + } + } else { + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + opus_int16 tmp; + if ( gain_lock[i] ) { + tmp = best_gain_mult[i]; + } else { + tmp = gainMult_Q8; + } + pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f; + } + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) ); + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + return ret; + } + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int k; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_float TempGains[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f ); + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw ); + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + } +} diff --git a/native/codec/libraries/opus/silk/float/energy_FLP.c b/native/codec/libraries/opus/silk/float/energy_FLP.c new file mode 100644 index 0000000..7bc7173 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/energy_FLP.c @@ -0,0 +1,59 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +) +{ + opus_int i; + double result; + + /* 4x unrolled loop */ + result = 0.0; + for( i = 0; i < dataSize - 3; i += 4 ) { + result += data[ i + 0 ] * (double)data[ i + 0 ] + + data[ i + 1 ] * (double)data[ i + 1 ] + + data[ i + 2 ] * (double)data[ i + 2 ] + + data[ i + 3 ] * (double)data[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data[ i ] * (double)data[ i ]; + } + + silk_assert( result >= 0.0 ); + return result; +} diff --git a/native/codec/libraries/opus/silk/float/find_LPC_FLP.c b/native/codec/libraries/opus/silk/float/find_LPC_FLP.c new file mode 100644 index 0000000..fa3ffe7 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/find_LPC_FLP.c @@ -0,0 +1,104 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + silk_float a[ MAX_LPC_ORDER ]; + + /* Used only for NLSF interpolation */ + silk_float res_nrg, res_nrg_2nd, res_nrg_interp; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + silk_float a_tmp[ MAX_LPC_ORDER ]; + silk_float LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ]; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: No interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than */ + /* adding it to the residual energy of the first 10 ms in each iteration of the search below */ + res_nrg -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder ); + + /* Convert to NLSFs */ + silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + res_nrg_2nd = silk_float_MAX; + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + /* Calculate residual energy with LSF interpolation */ + silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder ); + res_nrg_interp = (silk_float)( + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ) + + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) ); + + /* Determine whether current interpolated NLSFs are best so far */ + if( res_nrg_interp < res_nrg ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } else if( res_nrg_interp > res_nrg_2nd ) { + /* No reason to continue iterating - residual energies will continue to climb */ + break; + } + res_nrg_2nd = res_nrg_interp; + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder ); + } + + celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || + ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); +} diff --git a/native/codec/libraries/opus/silk/float/find_LTP_FLP.c b/native/codec/libraries/opus/silk/float/find_LTP_FLP.c new file mode 100644 index 0000000..f970649 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/find_LTP_FLP.c @@ -0,0 +1,64 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_LTP_FLP( + silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* O Weight for LTP quantization */ + const silk_float r_ptr[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + silk_float *xX_ptr, *XX_ptr; + const silk_float *lag_ptr; + silk_float xx, temp; + + xX_ptr = xX; + XX_ptr = XX; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, XX_ptr ); + silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xX_ptr ); + xx = ( silk_float )silk_energy_FLP( r_ptr, subfr_length + LTP_ORDER ); + temp = 1.0f / silk_max( xx, LTP_CORR_INV_MAX * 0.5f * ( XX_ptr[ 0 ] + XX_ptr[ 24 ] ) + 1.0f ); + silk_scale_vector_FLP( XX_ptr, temp, LTP_ORDER * LTP_ORDER ); + silk_scale_vector_FLP( xX_ptr, temp, LTP_ORDER ); + + r_ptr += subfr_length; + XX_ptr += LTP_ORDER * LTP_ORDER; + xX_ptr += LTP_ORDER; + } +} diff --git a/native/codec/libraries/opus/silk/float/find_pitch_lags_FLP.c b/native/codec/libraries/opus/silk/float/find_pitch_lags_FLP.c new file mode 100644 index 0000000..dedbcd2 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/find_pitch_lags_FLP.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int buf_len; + silk_float thrhld, res_nrg; + const silk_float *x_buf_ptr, *x_buf; + silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + silk_float A[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float Wsig[ FIND_PITCH_LPC_WIN_MAX ]; + silk_float *Wsig_ptr; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.ltp_mem_length; + + /******************************************/ + /* Estimate LPC AR coeficients */ + /******************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle non-windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_buf_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as a fraction of the energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1; + + /* Calculate the reflection coefficients using Schur */ + res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Bandwidth expansion */ + silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWIDTH_EXPANSION ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld = 0.6f; + thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder; + thrhld -= 0.1f * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + thrhld -= 0.15f * (psEnc->sCmn.prevSignalType >> 1); + thrhld -= 0.1f * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ); + + /*****************************************/ + /* Call Pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, + &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f, + thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, arch ) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr = 0; + } +} diff --git a/native/codec/libraries/opus/silk/float/find_pred_coefs_FLP.c b/native/codec/libraries/opus/silk/float/find_pred_coefs_FLP.c new file mode 100644 index 0000000..dcf7c52 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/find_pred_coefs_FLP.c @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + silk_float XXLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + silk_float xXLTP[ MAX_NB_SUBFR * LTP_ORDER ]; + silk_float invGains[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const silk_float *x_ptr; + silk_float *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + silk_float minInvGain; + + /* Weighting for weighted least squares */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_assert( psEncCtrl->Gains[ i ] > 0.0f ); + invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ]; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + silk_find_LTP_FLP( XXLTP, xXLTP, res_pitch, psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + &psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain, XXLTP, xXLTP, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FLP( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef, + psEncCtrl->pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + silk_memset( psEncCtrl->LTPCoef, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) ); + psEncCtrl->LTPredCodGain = 0.0f; + psEnc->sCmn.sum_log_gain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain = 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET; + } else { + minInvGain = (silk_float)pow( 2, psEncCtrl->LTPredCodGain / 3 ) / MAX_PREDICTION_POWER_GAIN; + minInvGain /= 0.25f + 0.75f * psEncCtrl->coding_quality; + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FLP( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain ); + + /* Quantize LSFs */ + silk_process_NLSFs_FLP( &psEnc->sCmn, psEncCtrl->PredCoef, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); +} + diff --git a/native/codec/libraries/opus/silk/float/inner_product_FLP.c b/native/codec/libraries/opus/silk/float/inner_product_FLP.c new file mode 100644 index 0000000..cdd39d2 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/inner_product_FLP.c @@ -0,0 +1,59 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +) +{ + opus_int i; + double result; + + /* 4x unrolled loop */ + result = 0.0; + for( i = 0; i < dataSize - 3; i += 4 ) { + result += data1[ i + 0 ] * (double)data2[ i + 0 ] + + data1[ i + 1 ] * (double)data2[ i + 1 ] + + data1[ i + 2 ] * (double)data2[ i + 2 ] + + data1[ i + 3 ] * (double)data2[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data1[ i ] * (double)data2[ i ]; + } + + return result; +} diff --git a/native/codec/libraries/opus/silk/float/k2a_FLP.c b/native/codec/libraries/opus/silk/float/k2a_FLP.c new file mode 100644 index 0000000..1448008 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/k2a_FLP.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + silk_float rck, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rck = rc[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A[ n ]; + tmp2 = A[ k - n - 1 ]; + A[ n ] = tmp1 + tmp2 * rck; + A[ k - n - 1 ] = tmp2 + tmp1 * rck; + } + A[ k ] = -rck; + } +} diff --git a/native/codec/libraries/opus/silk/float/main_FLP.h b/native/codec/libraries/opus/silk/float/main_FLP.h new file mode 100644 index 0000000..5dc0ccf --- /dev/null +++ b/native/codec/libraries/opus/silk/float/main_FLP.h @@ -0,0 +1,286 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MAIN_FLP_H +#define SILK_MAIN_FLP_H + +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "structs_FLP.h" +#include "main.h" +#include "define.h" +#include "debug.h" +#include "entenc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FLP +#define silk_encode_frame_Fxx silk_encode_frame_FLP + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int activity /* I Decision of Opus voice activity detector */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + int arch /* I Run-tim architecture */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Prediction gain from LTP (dB) */ +); + +/* LTP analysis */ +void silk_find_LTP_FLP( + silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* O Weight for LTP quantization */ + const silk_float r_ptr[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr /* I number of subframes */ +); + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceding samples for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +); + +/* 16th order LPC analysis filter */ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + silk_float *pred_gain_dB, /* O LTP prediction gain */ + const silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Correlation matrix */ + const silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* I Correlation vector */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +); + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Wrapper functions. Call flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +); + +/* Convert NLSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +); + +/* Limit, stabilize, and quantize NLSFs */ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +/* Floating-point Silk NSQ wrapper */ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/float/noise_shape_analysis_FLP.c b/native/codec/libraries/opus/silk/float/noise_shape_analysis_FLP.c new file mode 100644 index 0000000..cb3d8a5 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/noise_shape_analysis_FLP.c @@ -0,0 +1,350 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static OPUS_INLINE silk_float warped_gain( + const silk_float *coefs, + silk_float lambda, + opus_int order +) { + opus_int i; + silk_float gain; + + lambda = -lambda; + gain = coefs[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain = lambda * gain + coefs[ i ]; + } + return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static OPUS_INLINE void warped_true2monic_coefs( + silk_float *coefs, + silk_float lambda, + silk_float limit, + opus_int order +) { + opus_int i, iter, ind = 0; + silk_float tmp, maxabs, chirp, gain; + + /* Convert to monic coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs[ i - 1 ] -= lambda * coefs[ i ]; + } + gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + + /* Limit */ + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_float( coefs[ i ] ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs[ i - 1 ] += lambda * coefs[ i ]; + } + gain = 1.0f / gain; + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + silk_bwexpander_FLP( coefs, order, chirp ); + + /* Convert to monic warped coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs[ i - 1 ] -= lambda * coefs[ i ]; + } + gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + } + silk_assert( 0 ); +} + +static OPUS_INLINE void limit_coefs( + silk_float *coefs, + silk_float limit, + opus_int order +) { + opus_int i, iter, ind = 0; + silk_float tmp, maxabs, chirp; + + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_float( coefs[ i ] ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + silk_bwexpander_FLP( coefs, order, chirp ); + } + silk_assert( 0 ); +} + +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k, nSamples, nSegs; + silk_float SNR_adj_dB, HarmShapeGain, Tilt; + silk_float nrg, log_energy, log_energy_prev, energy_variation; + silk_float BWExp, gain_mult, gain_add, strength, b, warping; + silk_float x_windowed[ SHAPE_LPC_WIN_MAX ]; + silk_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + silk_float rc[ MAX_SHAPE_LPC_ORDER + 1 ]; + const silk_float *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ); + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f ); + + /* Coding quality level, between 0.0 and 1.0 */ + psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) ); + + if( psEnc->sCmn.useCBR == 0 ) { + /* Reduce coding SNR during low speech activity */ + b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr; + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = 2 * psEnc->sCmn.fs_kHz; + energy_variation = 0.0f; + log_energy_prev = 0.0f; + pitch_res_ptr = pitch_res; + nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; + for( k = 0; k < nSegs; k++ ) { + nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples ); + log_energy = silk_log2( nrg ); + if( k > 0 ) { + energy_variation += silk_abs_float( log_energy - log_energy_prev ); + } + log_energy_prev = log_energy; + pitch_res_ptr += nSamples; + } + + /* Set quantization offset depending on sparseness measure */ + if( energy_variation > ENERGY_VARIATION_THRESHOLD_QNT_OFFSET * (nSegs-1) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */ + BWExp = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength ); + + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality; + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2; + + silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) ); + shift += flat_part; + silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping, + psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION + 1.0f; + + /* Convert correlations to prediction coefficients, and compute residual energy */ + nrg = silk_schur_FLP( rc, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_k2a_FLP( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], rc, psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder ); + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_FLP( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Convert to monic warped prediction coefficients and limit absolute values */ + warped_true2monic_coefs( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], warping, 3.999f, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Limit absolute values */ + limit_coefs( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], 3.999f, psEnc->sCmn.shapingLPCOrder ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity */ + gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB ); + gain_add = (silk_float)pow( 2.0f, 0.16f * MIN_QGAIN_DB ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= gain_mult; + psEncCtrl->Gains[ k ] += gain_add; + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) ); + strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ]; + psEncCtrl->LF_MA_shp[ k ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength; + } + Tilt = - HP_NOISE_COEF - + (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + } else { + b = 1.3f / psEnc->sCmn.fs_kHz; + psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f; + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ]; + psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ]; + } + Tilt = -HP_NOISE_COEF; + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Harmonic noise shaping */ + HarmShapeGain = HARMONIC_SHAPING; + + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING * + ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr ); + } else { + HarmShapeGain = 0.0f; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth ); + psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth; + psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth ); + psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth; + } +} diff --git a/native/codec/libraries/opus/silk/float/pitch_analysis_core_FLP.c b/native/codec/libraries/opus/silk/float/pitch_analysis_core_FLP.c new file mode 100644 index 0000000..f351bc3 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/pitch_analysis_core_FLP.c @@ -0,0 +1,630 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/***************************************************************************** +* Pitch analyser function +******************************************************************************/ +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" +#include "pitch.h" + +#define SCRATCH_SIZE 22 + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +/************************************************************/ +/* CORE PITCH ANALYSIS FUNCTION */ +/************************************************************/ +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I Number of 5 ms subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, d, j; + silk_float frame_8kHz[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + silk_float frame_4kHz[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int32 filt_state[ 6 ]; + silk_float threshold, contour_bias; + silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ]; + opus_val32 xcorr[ PE_MAX_LAG_MS * 4 - PE_MIN_LAG_MS * 4 + 1 ]; + silk_float CC[ PE_NB_CBKS_STAGE2_EXT ]; + const silk_float *target_ptr, *basis_ptr; + double cross_corr, normalizer, energy, energy_tmp; + opus_int d_srch[ PE_D_SRCH_LENGTH ]; + opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ]; + opus_int length_d_srch, length_d_comp; + silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new; + opus_int CBimax, CBimax_new, lag, start_lag, end_lag, lag_new; + opus_int cbk_size; + silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr; + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int lag_counter; + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length, sf_length_8kHz, sf_length_4kHz; + opus_int min_lag, min_lag_8kHz, min_lag_4kHz; + opus_int max_lag, max_lag_8kHz, max_lag_4kHz; + opus_int nb_cbk_search; + const opus_int8 *Lag_CB_ptr; + + /* Check for valid sampling frequency */ + celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f ); + silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4; + sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PE_MIN_LAG_MS * 4; + min_lag_8kHz = PE_MIN_LAG_MS * 8; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + max_lag_4kHz = PE_MAX_LAG_MS * 4; + max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1; + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + /* Resample to 16 -> 8 khz */ + opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_16_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else if( Fs_kHz == 12 ) { + /* Resample to 12 -> 8 khz */ + opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_12_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else { + celt_assert( Fs_kHz == 8 ); + silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz ); + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz ); + silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5)); + target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_4kHz ); + celt_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + celt_assert( basis_ptr >= frame_4kHz ); + celt_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + celt_pitch_xcorr( target_ptr, target_ptr-max_lag_4kHz, xcorr, sf_length_8kHz, max_lag_4kHz - min_lag_4kHz + 1, arch ); + + /* Calculate first vector products before loop */ + cross_corr = xcorr[ max_lag_4kHz - min_lag_4kHz ]; + normalizer = silk_energy_FLP( target_ptr, sf_length_8kHz ) + + silk_energy_FLP( basis_ptr, sf_length_8kHz ) + + sf_length_8kHz * 4000.0f; + + C[ 0 ][ min_lag_4kHz ] += (silk_float)( 2 * cross_corr / normalizer ); + + /* From now on normalizer is computed recursively */ + for( d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++ ) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + cross_corr = xcorr[ max_lag_4kHz - d ]; + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] - + basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ]; + C[ 0 ][ d ] += (silk_float)( 2 * cross_corr / normalizer ); + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Apply short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f; + } + + /* Sort */ + length_d_srch = 4 + 2 * complexity; + celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = C[ 0 ][ min_lag_4kHz ]; + if( Cmax < 0.2f ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = search_thres1 * Cmax; + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 ); + } else { + length_d_srch = i; + break; + } + } + celt_assert( length_d_srch > 0 ); + + for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) { + d_comp[ i ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] ] = 1; + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ]; + } + + length_d_srch = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) { + if( d_comp[ i + 1 ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ]; + } + + length_d_comp = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) { + if( d_comp[ i ] > 0 ) { + d_comp[ length_d_comp ] = (opus_int16)( i - 2 ); + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float)); + + if( Fs_kHz == 8 ) { + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } else { + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } + for( k = 0; k < nb_subfr; k++ ) { + energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ) + 1.0; + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz ); + if( cross_corr > 0.0f ) { + energy = silk_energy_FLP( basis_ptr, sf_length_8kHz ); + C[ k ][ d ] = (silk_float)( 2 * cross_corr / ( energy + energy_tmp ) ); + } else { + C[ k ][ d ] = 0.0f; + } + } + target_ptr += sf_length_8kHz; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = 0.0f; /* This value doesn't matter */ + CCmax_b = -1000.0f; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_LSHIFT( prevLag, 1 ) / 3; + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2 = silk_log2( (silk_float)prevLag ); + } else { + prevLag_log2 = 0; + } + + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[j] = 0.0f; + for( i = 0; i < nb_subfr; i++ ) { + /* Try all codebooks */ + CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )]; + } + } + /* Find best codebook */ + CCmax_new = -1000.0f; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2 = silk_log2( (silk_float)d ); + CCmax_new_b = CCmax_new - PE_SHORTLAG_BIAS * nb_subfr * lag_log2; + + /* Bias towards previous lag */ + if( prevLag > 0 ) { + delta_lag_log2_sqr = lag_log2 - prevLag_log2; + delta_lag_log2_sqr *= delta_lag_log2_sqr; + CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / ( delta_lag_log2_sqr + 0.5f ); + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > nb_subfr * search_thres2 /* Correlation needs to be high enough to be voiced */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + /* Output normalized correlation */ + *LTPCorr = (silk_float)( CCmax / nb_subfr ); + silk_assert( *LTPCorr >= 0.0f ); + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 ); + } else { /* Fs_kHz == 16 */ + lag = silk_LSHIFT( lag, 1 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + + CCmax = -1000.0f; + + /* Calculate the correlations and energies needed in stage 3 */ + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias = PE_FLATCONTOUR_BIAS / lag; + + /* Set up cbk parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ]; + energy_tmp = silk_energy_FLP( target_ptr, nb_subfr * sf_length ) + 1.0; + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0.0; + energy = energy_tmp; + for( k = 0; k < nb_subfr; k++ ) { + cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ]; + energy += energies_st3[ k ][ j ][ lag_counter ]; + } + if( cross_corr > 0.0 ) { + CCmax_new = (silk_float)( 2 * cross_corr / energy ); + /* Reduce depending on flatness of contour */ + CCmax_new *= 1.0f - contour_bias * j; + } else { + CCmax_new = 0.0f; + } + + if( CCmax_new > CCmax && ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag ); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * 8 ); + } + *lagIndex = (opus_int16)( lag - min_lag_8kHz ); + *contourIndex = (opus_int8)CBimax; + } + celt_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +/*********************************************************************** + * Calculates the correlations used in stage 3 search. In order to cover + * the whole lag codebook for all the searched offset lags (lag +- 2), + * the following correlations are needed in each sub frame: + * + * sf1: lag range [-8,...,7] total 16 correlations + * sf2: lag range [-4,...,4] total 9 correlations + * sf3: lag range [-3,....4] total 8 correltions + * sf4: lag range [-6,....8] total 15 correlations + * + * In total 48 correlations. The direct implementation computed in worst + * case 4*12*5 = 240 correlations, but more likely around 120. + ***********************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const silk_float *target_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + silk_float scratch_mem[ SCRATCH_SIZE ]; + opus_val32 xcorr[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE); + celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr, sf_length, lag_high - lag_low + 1, arch ); + for( j = lag_low; j <= lag_high; j++ ) { + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = xcorr[ lag_high - j ]; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +{ + const silk_float *target_ptr, *basis_ptr; + double energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + silk_float scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3; + silk_assert( energy >= 0.0 ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i]; + silk_assert( energy >= 0.0 ); + + /* add part that comes into window */ + energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ]; + silk_assert( energy >= 0.0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f ); + } + } + target_ptr += sf_length; + } +} diff --git a/native/codec/libraries/opus/silk/float/process_gains_FLP.c b/native/codec/libraries/opus/silk/float/process_gains_FLP.c new file mode 100644 index 0000000..c0da0da --- /dev/null +++ b/native/codec/libraries/opus/silk/float/process_gains_FLP.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + silk_float s, InvMaxSqrVal, gain, quant_offset; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + s = 1.0f - 0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= s; + } + } + + /* Limit the quantized signal */ + InvMaxSqrVal = ( silk_float )( pow( 2.0f, 0.33f * ( 21.0f - psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) ) ) / psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + gain = psEncCtrl->Gains[ k ]; + gain = ( silk_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal ); + psEncCtrl->Gains[ k ] = silk_min_float( gain, 32767.0f ); + } + + /* Prepare gains for noise shaping quantization */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + pGains_Q16[ k ] = (opus_int32)( psEncCtrl->Gains[ k ] * 65536.0f ); + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f; + } + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain + psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ) > 1.0f ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ] / 1024.0f; + psEncCtrl->Lambda = LAMBDA_OFFSET + + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision + + LAMBDA_SPEECH_ACT * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ) + + LAMBDA_INPUT_QUALITY * psEncCtrl->input_quality + + LAMBDA_CODING_QUALITY * psEncCtrl->coding_quality + + LAMBDA_QUANT_OFFSET * quant_offset; + + silk_assert( psEncCtrl->Lambda > 0.0f ); + silk_assert( psEncCtrl->Lambda < 2.0f ); +} diff --git a/native/codec/libraries/opus/silk/float/regularize_correlations_FLP.c b/native/codec/libraries/opus/silk/float/regularize_correlations_FLP.c new file mode 100644 index 0000000..df46126 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/regularize_correlations_FLP.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FLP( + silk_float *XX, /* I/O Correlation matrices */ + silk_float *xx, /* I/O Correlation values */ + const silk_float noise, /* I Noise energy to add */ + const opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) += noise; + } + xx[ 0 ] += noise; +} diff --git a/native/codec/libraries/opus/silk/float/residual_energy_FLP.c b/native/codec/libraries/opus/silk/float/residual_energy_FLP.c new file mode 100644 index 0000000..1bd07b3 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/residual_energy_FLP.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +#define MAX_ITERATIONS_RESIDUAL_NRG 10 +#define REGULARIZATION_FACTOR 1e-8f + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +) +{ + opus_int i, j, k; + silk_float tmp, nrg = 0.0f, regularization; + + /* Safety checks */ + celt_assert( D >= 0 ); + + regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] ); + for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) { + nrg = wxx; + + tmp = 0.0f; + for( i = 0; i < D; i++ ) { + tmp += wXx[ i ] * c[ i ]; + } + nrg -= 2.0f * tmp; + + /* compute c' * wXX * c, assuming wXX is symmetric */ + for( i = 0; i < D; i++ ) { + tmp = 0.0f; + for( j = i + 1; j < D; j++ ) { + tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ]; + } + nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] ); + } + if( nrg > 0 ) { + break; + } else { + /* Add white noise */ + for( i = 0; i < D; i++ ) { + matrix_c_ptr( wXX, i, i, D ) += regularization; + } + /* Increase noise for next run */ + regularization *= 2.0f; + } + } + if( k == MAX_ITERATIONS_RESIDUAL_NRG ) { + silk_assert( nrg == 0 ); + nrg = 1.0f; + } + + return nrg; +} + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int shift; + silk_float *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + LPC_res_ptr = LPC_res + LPC_order; + shift = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order ); + nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + + if( nb_subfr == MAX_NB_SUBFR ) { + silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order ); + nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + } +} diff --git a/native/codec/libraries/opus/silk/float/scale_copy_vector_FLP.c b/native/codec/libraries/opus/silk/float/scale_copy_vector_FLP.c new file mode 100644 index 0000000..20db32b --- /dev/null +++ b/native/codec/libraries/opus/silk/float/scale_copy_vector_FLP.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data_out[ i + 0 ] = gain * data_in[ i + 0 ]; + data_out[ i + 1 ] = gain * data_in[ i + 1 ]; + data_out[ i + 2 ] = gain * data_in[ i + 2 ]; + data_out[ i + 3 ] = gain * data_in[ i + 3 ]; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data_out[ i ] = gain * data_in[ i ]; + } +} diff --git a/native/codec/libraries/opus/silk/float/scale_vector_FLP.c b/native/codec/libraries/opus/silk/float/scale_vector_FLP.c new file mode 100644 index 0000000..108fdcb --- /dev/null +++ b/native/codec/libraries/opus/silk/float/scale_vector_FLP.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data1[ i + 0 ] *= gain; + data1[ i + 1 ] *= gain; + data1[ i + 2 ] *= gain; + data1[ i + 3 ] *= gain; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data1[ i ] *= gain; + } +} diff --git a/native/codec/libraries/opus/silk/float/schur_FLP.c b/native/codec/libraries/opus/silk/float/schur_FLP.c new file mode 100644 index 0000000..8526c74 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/schur_FLP.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +) +{ + opus_int k, n; + double C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + double Ctmp1, Ctmp2, rc_tmp; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Copy correlations */ + k = 0; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ]; + } while( ++k <= order ); + + for( k = 0; k < order; k++ ) { + /* Get reflection coefficient */ + rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f ); + + /* Save the output */ + refl_coef[ k ] = (silk_float)rc_tmp; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp; + C[ n ][ 1 ] = Ctmp2 + Ctmp1 * rc_tmp; + } + } + + /* Return residual energy */ + return (silk_float)C[ 0 ][ 1 ]; +} diff --git a/native/codec/libraries/opus/silk/float/sort_FLP.c b/native/codec/libraries/opus/silk/float/sort_FLP.c new file mode 100644 index 0000000..0e18f31 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/sort_FLP.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ + +#include "typedef.h" +#include "SigProc_FLP.h" + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + silk_float value; + opus_int i, j; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} diff --git a/native/codec/libraries/opus/silk/float/structs_FLP.h b/native/codec/libraries/opus/silk/float/structs_FLP.h new file mode 100644 index 0000000..3150b38 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/structs_FLP.h @@ -0,0 +1,112 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FLP_H +#define SILK_STRUCTS_FLP_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + silk_float HarmShapeGain_smth; + silk_float Tilt_smth; +} silk_shape_state_FLP; + +/********************************/ +/* Encoder state FLP */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */ + silk_shape_state_FLP sShape; /* Noise shaping state */ + + /* Buffer for find pitch and noise shape analysis */ + silk_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + silk_float LTPCorr; /* Normalized correlation from pitch lag estimator */ +} silk_encoder_state_FLP; + +/************************/ +/* Encoder control FLP */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + silk_float Gains[ MAX_NB_SUBFR ]; + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */ + silk_float LTPCoef[LTP_ORDER * MAX_NB_SUBFR]; + silk_float LTP_scale; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + silk_float AR[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float LF_MA_shp[ MAX_NB_SUBFR ]; + silk_float LF_AR_shp[ MAX_NB_SUBFR ]; + silk_float Tilt[ MAX_NB_SUBFR ]; + silk_float HarmShapeGain[ MAX_NB_SUBFR ]; + silk_float Lambda; + silk_float input_quality; + silk_float coding_quality; + + /* Measures */ + silk_float predGain; + silk_float LTPredCodGain; + silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FLP; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FLP state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsUsedLBRR; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/float/warped_autocorrelation_FLP.c b/native/codec/libraries/opus/silk/float/warped_autocorrelation_FLP.c new file mode 100644 index 0000000..09186e7 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/warped_autocorrelation_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i; + double tmp1, tmp2; + double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1 = input[ n ]; + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + C[ i ] += state[ 0 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + C[ i + 1 ] += state[ 0 ] * tmp2; + } + state[ order ] = tmp1; + C[ order ] += state[ 0 ] * tmp1; + } + + /* Copy correlations in silk_float output format */ + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( silk_float )C[ i ]; + } +} diff --git a/native/codec/libraries/opus/silk/float/wrappers_FLP.c b/native/codec/libraries/opus/silk/float/wrappers_FLP.c new file mode 100644 index 0000000..ad90b87 --- /dev/null +++ b/native/codec/libraries/opus/silk/float/wrappers_FLP.c @@ -0,0 +1,207 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Wrappers. Calls flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int i; + opus_int32 a_fix_Q16[ MAX_LPC_ORDER ]; + + for( i = 0; i < LPC_order; i++ ) { + a_fix_Q16[ i ] = silk_float2int( pAR[ i ] * 65536.0f ); + } + + silk_A2NLSF( NLSF_Q15, a_fix_Q16, LPC_order ); +} + +/* Convert LSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +) +{ + opus_int i; + opus_int16 a_fix_Q12[ MAX_LPC_ORDER ]; + + silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order, arch ); + + for( i = 0; i < LPC_order; i++ ) { + pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f ); + } +} + +/******************************************/ +/* Floating-point NLSF processing wrapper */ +/******************************************/ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, j; + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + + silk_process_NLSFs( psEncC, PredCoef_Q12, NLSF_Q15, prev_NLSF_Q15); + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + PredCoef[ j ][ i ] = ( silk_float )PredCoef_Q12[ j ][ i ] * ( 1.0f / 4096.0f ); + } + } +} + +/****************************************/ +/* Floating-point Silk NSQ wrapper */ +/****************************************/ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +) +{ + opus_int i, j; + opus_int16 x16[ MAX_FRAME_LENGTH ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + + /* Noise shaping parameters */ + opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Lambda_Q10; + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + + /* Convert control struct to fix control struct */ + /* Noise shape parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) { + AR_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + LF_shp_Q14[ i ] = silk_LSHIFT32( silk_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) | + (opus_uint16)silk_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f ); + Tilt_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->Tilt[ i ] * 16384.0f ); + HarmShapeGain_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f ); + } + Lambda_Q10 = ( opus_int )silk_float2int( psEncCtrl->Lambda * 1024.0f ); + + /* prediction and coding parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr * LTP_ORDER; i++ ) { + LTPCoef_Q14[ i ] = (opus_int16)silk_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f ); + } + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + PredCoef_Q12[ j ][ i ] = (opus_int16)silk_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + Gains_Q16[ i ] = silk_float2int( psEncCtrl->Gains[ i ] * 65536.0f ); + silk_assert( Gains_Q16[ i ] > 0 ); + } + + if( psIndices->signalType == TYPE_VOICED ) { + LTP_scale_Q14 = silk_LTPScales_table_Q14[ psIndices->LTP_scaleIndex ]; + } else { + LTP_scale_Q14 = 0; + } + + /* Convert input to fix */ + for( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + x16[ i ] = silk_float2int( x[ i ] ); + } + + /* Call NSQ */ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x16, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x16, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch ); + } +} + +/***********************************************/ +/* Floating-point Silk LTP quantiation wrapper */ +/***********************************************/ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + silk_float *pred_gain_dB, /* O LTP prediction gain */ + const silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Correlation matrix */ + const silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* I Correlation vector */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, pred_gain_dB_Q7; + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ]; + opus_int32 XX_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + opus_int32 xX_Q17[ MAX_NB_SUBFR * LTP_ORDER ]; + + for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) { + XX_Q17[ i ] = (opus_int32)silk_float2int( XX[ i ] * 131072.0f ); + } + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + xX_Q17[ i ] = (opus_int32)silk_float2int( xX[ i ] * 131072.0f ); + } + + silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, sum_log_gain_Q7, &pred_gain_dB_Q7, XX_Q17, xX_Q17, subfr_len, nb_subfr, arch ); + + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + B[ i ] = (silk_float)B_Q14[ i ] * ( 1.0f / 16384.0f ); + } + + *pred_gain_dB = (silk_float)pred_gain_dB_Q7 * ( 1.0f / 128.0f ); +} diff --git a/native/codec/libraries/opus/silk/gain_quant.c b/native/codec/libraries/opus/silk/gain_quant.c new file mode 100644 index 0000000..ee65245 --- /dev/null +++ b/native/codec/libraries/opus/silk/gain_quant.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +#define OFFSET ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 ) +#define SCALE_Q16 ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) +#define INV_SCALE_Q16 ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) ) + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + /* Convert to log scale, scale, floor() */ + ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET ); + + /* Round towards previous quantized gain (hysteresis) */ + if( ind[ k ] < *prev_ind ) { + ind[ k ]++; + } + ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 ); + + /* Compute delta indices and limit */ + if( k == 0 && conditional == 0 ) { + /* Full index */ + ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 ); + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + ind[ k ] = ind[ k ] - *prev_ind; + + /* Double the quantization step size for large gain increases, so that the max gain level can be reached */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind[ k ] > double_step_size_threshold ) { + ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 ); + } + + ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); + + /* Accumulate deltas */ + if( ind[ k ] > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold; + *prev_ind = silk_min_int( *prev_ind, N_LEVELS_QGAIN - 1 ); + } else { + *prev_ind += ind[ k ]; + } + + /* Shift to make non-negative */ + ind[ k ] -= MIN_DELTA_GAIN_QUANT; + } + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, ind_tmp, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + if( k == 0 && conditional == 0 ) { + /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */ + *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 ); + } else { + /* Delta index */ + ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT; + + /* Accumulate deltas */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind_tmp > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold; + } else { + *prev_ind += ind_tmp; + } + } + *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 ); + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + opus_int32 gainsID; + + gainsID = 0; + for( k = 0; k < nb_subfr; k++ ) { + gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 ); + } + + return gainsID; +} diff --git a/native/codec/libraries/opus/silk/init_decoder.c b/native/codec/libraries/opus/silk/init_decoder.c new file mode 100644 index 0000000..16c03dc --- /dev/null +++ b/native/codec/libraries/opus/silk/init_decoder.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/************************/ +/* Init Decoder State */ +/************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +) +{ + /* Clear the entire encoder state, except anything copied */ + silk_memset( psDec, 0, sizeof( silk_decoder_state ) ); + + /* Used to deactivate LSF interpolation */ + psDec->first_frame_after_reset = 1; + psDec->prev_gain_Q16 = 65536; + psDec->arch = opus_select_arch(); + + /* Reset CNG state */ + silk_CNG_Reset( psDec ); + + /* Reset PLC state */ + silk_PLC_Reset( psDec ); + + return(0); +} + diff --git a/native/codec/libraries/opus/silk/init_encoder.c b/native/codec/libraries/opus/silk/init_encoder.c new file mode 100644 index 0000000..65995c3 --- /dev/null +++ b/native/codec/libraries/opus/silk/init_encoder.c @@ -0,0 +1,64 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" +#include "cpu_support.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */ + int arch /* I Run-time architecture */ +) +{ + opus_int ret = 0; + + /* Clear the entire encoder state */ + silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) ); + + psEnc->sCmn.arch = arch; + + psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 ); + psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15; + + /* Used to deactivate LSF interpolation, pitch prediction */ + psEnc->sCmn.first_frame_after_reset = 1; + + /* Initialize Silk VAD */ + ret += silk_VAD_Init( &psEnc->sCmn.sVAD ); + + return ret; +} diff --git a/native/codec/libraries/opus/silk/inner_prod_aligned.c b/native/codec/libraries/opus/silk/inner_prod_aligned.c new file mode 100644 index 0000000..257ae9e --- /dev/null +++ b/native/codec/libraries/opus/silk/inner_prod_aligned.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale ); + } + return sum; +} diff --git a/native/codec/libraries/opus/silk/interpolate.c b/native/codec/libraries/opus/silk/interpolate.c new file mode 100644 index 0000000..833c28e --- /dev/null +++ b/native/codec/libraries/opus/silk/interpolate.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +) +{ + opus_int i; + + celt_assert( ifact_Q2 >= 0 ); + celt_assert( ifact_Q2 <= 4 ); + + for( i = 0; i < d; i++ ) { + xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 ); + } +} diff --git a/native/codec/libraries/opus/silk/lin2log.c b/native/codec/libraries/opus/silk/lin2log.c new file mode 100644 index 0000000..0d5155a --- /dev/null +++ b/native/codec/libraries/opus/silk/lin2log.c @@ -0,0 +1,46 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +) +{ + opus_int32 lz, frac_Q7; + + silk_CLZ_FRAC( inLin, &lz, &frac_Q7 ); + + /* Piece-wise parabolic approximation */ + return silk_ADD_LSHIFT32( silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 ), 31 - lz, 7 ); +} + diff --git a/native/codec/libraries/opus/silk/log2lin.c b/native/codec/libraries/opus/silk/log2lin.c new file mode 100644 index 0000000..b7c48e4 --- /dev/null +++ b/native/codec/libraries/opus/silk/log2lin.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Approximation of 2^() (very close inverse of silk_lin2log()) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +) +{ + opus_int32 out, frac_Q7; + + if( inLog_Q7 < 0 ) { + return 0; + } else if ( inLog_Q7 >= 3967 ) { + return silk_int32_MAX; + } + + out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) ); + frac_Q7 = inLog_Q7 & 0x7F; + if( inLog_Q7 < 2048 ) { + /* Piece-wise parabolic approximation */ + out = silk_ADD_RSHIFT32( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 ); + } else { + /* Piece-wise parabolic approximation */ + out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ); + } + return out; +} diff --git a/native/codec/libraries/opus/silk/macros.h b/native/codec/libraries/opus/silk/macros.h new file mode 100644 index 0000000..3c67b6e --- /dev/null +++ b/native/codec/libraries/opus/silk/macros.h @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MACROS_H +#define SILK_MACROS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_types.h" +#include "opus_defines.h" +#include "arch.h" + +/* This is an OPUS_INLINE header file for general platform. */ + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#if OPUS_FAST_INT64 +#define silk_SMULWB(a32, b32) ((opus_int32)(((a32) * (opus_int64)((opus_int16)(b32))) >> 16)) +#else +#define silk_SMULWB(a32, b32) ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16)) +#endif + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#if OPUS_FAST_INT64 +#define silk_SMLAWB(a32, b32, c32) ((opus_int32)((a32) + (((b32) * (opus_int64)((opus_int16)(c32))) >> 16))) +#else +#define silk_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))) +#endif + +/* (a32 * (b32 >> 16)) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMULWT(a32, b32) ((opus_int32)(((a32) * (opus_int64)((b32) >> 16)) >> 16)) +#else +#define silk_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) +#endif + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMLAWT(a32, b32, c32) ((opus_int32)((a32) + (((b32) * ((opus_int64)(c32) >> 16)) >> 16))) +#else +#define silk_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) +#endif + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#define silk_SMULBB(a32, b32) ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32))) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#define silk_SMLABB(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#define silk_SMULBT(a32, b32) ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#define silk_SMLABT(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16)) + +/* a64 + (b32 * c32) */ +#define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32)))) + +/* (a32 * b32) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMULWW(a32, b32) ((opus_int32)(((opus_int64)(a32) * (b32)) >> 16)) +#else +#define silk_SMULWW(a32, b32) silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)) +#endif + +/* a32 + ((b32 * c32) >> 16) */ +#if OPUS_FAST_INT64 +#define silk_SMLAWW(a32, b32, c32) ((opus_int32)((a32) + (((opus_int64)(b32) * (c32)) >> 16))) +#else +#define silk_SMLAWW(a32, b32, c32) silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)) +#endif + +/* add/subtract with output saturated */ +#define silk_ADD_SAT32(a, b) ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) ) + +#define silk_SUB_SAT32(a, b) ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) ) + +#if defined(MIPSr1_ASM) +#include "mips/macros_mipsr1.h" +#endif + +#include "ecintrin.h" +#ifndef OVERRIDE_silk_CLZ16 +static OPUS_INLINE opus_int32 silk_CLZ16(opus_int16 in16) +{ + return 32 - EC_ILOG(in16<<16|0x8000); +} +#endif + +#ifndef OVERRIDE_silk_CLZ32 +static OPUS_INLINE opus_int32 silk_CLZ32(opus_int32 in32) +{ + return in32 ? 32 - EC_ILOG(in32) : 32; +} +#endif + +/* Row based */ +#define matrix_ptr(Matrix_base_adr, row, column, N) \ + (*((Matrix_base_adr) + ((row)*(N)+(column)))) +#define matrix_adr(Matrix_base_adr, row, column, N) \ + ((Matrix_base_adr) + ((row)*(N)+(column))) + +/* Column based */ +#ifndef matrix_c_ptr +# define matrix_c_ptr(Matrix_base_adr, row, column, M) \ + (*((Matrix_base_adr) + ((row)+(M)*(column)))) +#endif + +#ifdef OPUS_ARM_INLINE_ASM +#include "arm/macros_armv4.h" +#endif + +#ifdef OPUS_ARM_INLINE_EDSP +#include "arm/macros_armv5e.h" +#endif + +#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR +#include "arm/macros_arm64.h" +#endif + +#endif /* SILK_MACROS_H */ + diff --git a/native/codec/libraries/opus/silk/main.h b/native/codec/libraries/opus/silk/main.h new file mode 100644 index 0000000..1a33eed --- /dev/null +++ b/native/codec/libraries/opus/silk/main.h @@ -0,0 +1,476 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MAIN_H +#define SILK_MAIN_H + +#include "SigProc_FIX.h" +#include "define.h" +#include "structs.h" +#include "tables.h" +#include "PLC.h" +#include "control.h" +#include "debug.h" +#include "entenc.h" +#include "entdec.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/main_sse.h" +#endif + +#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/NSQ_del_dec_arm.h" +#endif + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +); + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +); + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +); + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +); + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +); + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +); + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +); + +/***************/ +/* Shell coder */ +/***************/ + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +); + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +); + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +); + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + opus_int32 *sum_gain_dB_Q7, /* I/O Cumulative max prediction gain */ + opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */ + const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */ + const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +/* Entropy constrained matrix-weighted VQ, for a single input data vector */ +void silk_VQ_WMat_EC_c( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *res_nrg_Q15, /* O best residual energy */ + opus_int32 *rate_dist_Q8, /* O best total bitrate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int32 *XX_Q17, /* I correlation matrix */ + const opus_int32 *xX_Q17, /* I correlation vector */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int subfr_len, /* I number of samples per subframe */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const opus_int L /* I number of vectors in codebook */ +); + +#if !defined(OVERRIDE_silk_VQ_WMat_EC) +#define silk_VQ_WMat_EC(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L, arch) \ + ((void)(arch),silk_VQ_WMat_EC_c(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L)) +#endif + +/************************************/ +/* Noise shaping quantization (NSQ) */ +/************************************/ + +void silk_NSQ_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if !defined(OVERRIDE_silk_NSQ) +#define silk_NSQ(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) +#endif + +/* Noise shaping using delayed decision */ +void silk_NSQ_del_dec_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if !defined(OVERRIDE_silk_NSQ_del_dec) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_del_dec_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) +#endif + +/************/ +/* Silk VAD */ +/************/ +/* Initialize the Silk VAD */ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Get speech activity level in Q8 */ +opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +); + +#if !defined(OVERRIDE_silk_VAD_GetSA_Q8) +#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_c(psEnC, pIn)) +#endif + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting transition_frame_no = 1; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +); + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q26[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +); + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +); + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +); + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +); + +/****************************************************/ +/* Decoder Functions */ +/****************************************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +); + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding, /* I The type of conditional coding to use */ + int arch /* I Run-time architecture */ +); + +/* Decode indices from bitstream */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */ + int arch /* I Run-time architecture */ +); + +/* Decode quantization indices of excitation (Shell coding) */ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* CNG */ +/******************/ + +/* Reset CNG */ +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +); + +/* Encoding of various parameters */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +#endif diff --git a/native/codec/libraries/opus/silk/mips/NSQ_del_dec_mipsr1.h b/native/codec/libraries/opus/silk/mips/NSQ_del_dec_mipsr1.h new file mode 100644 index 0000000..cd70713 --- /dev/null +++ b/native/codec/libraries/opus/silk/mips/NSQ_del_dec_mipsr1.h @@ -0,0 +1,410 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef __NSQ_DEL_DEC_MIPSR1_H__ +#define __NSQ_DEL_DEC_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +#define OVERRIDE_silk_noise_shape_quantizer_del_dec +static inline void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + NSQ_sample_struct psSampleState[ MAX_DEL_DEC_STATES ][ 2 ]; + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + opus_int16 b_Q14_0, b_Q14_1, b_Q14_2, b_Q14_3, b_Q14_4; + opus_int16 a_Q12_0, a_Q12_1, a_Q12_2, a_Q12_3, a_Q12_4, a_Q12_5, a_Q12_6; + opus_int16 a_Q12_7, a_Q12_8, a_Q12_9, a_Q12_10, a_Q12_11, a_Q12_12, a_Q12_13; + opus_int16 a_Q12_14, a_Q12_15; + + opus_int32 cur, prev, next; + + /*Unused.*/ + (void)arch; + + //Intialize b_Q14 variables + b_Q14_0 = b_Q14[ 0 ]; + b_Q14_1 = b_Q14[ 1 ]; + b_Q14_2 = b_Q14[ 2 ]; + b_Q14_3 = b_Q14[ 3 ]; + b_Q14_4 = b_Q14[ 4 ]; + + //Intialize a_Q12 variables + a_Q12_0 = a_Q12[0]; + a_Q12_1 = a_Q12[1]; + a_Q12_2 = a_Q12[2]; + a_Q12_3 = a_Q12[3]; + a_Q12_4 = a_Q12[4]; + a_Q12_5 = a_Q12[5]; + a_Q12_6 = a_Q12[6]; + a_Q12_7 = a_Q12[7]; + a_Q12_8 = a_Q12[8]; + a_Q12_9 = a_Q12[9]; + a_Q12_10 = a_Q12[10]; + a_Q12_11 = a_Q12[11]; + a_Q12_12 = a_Q12[12]; + a_Q12_13 = a_Q12[13]; + a_Q12_14 = a_Q12[14]; + a_Q12_15 = a_Q12[15]; + + long long temp64; + + silk_assert( nStatesDelayedDecision > 0 ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + temp64 = __builtin_mips_mult(pred_lag_ptr[ 0 ], b_Q14_0 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -1 ], b_Q14_1 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -2 ], b_Q14_2 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -3 ], b_Q14_3 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -4 ], b_Q14_4 ); + temp64 += 32768; + LTP_pred_Q14 = __builtin_mips_extr_w(temp64, 16); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + temp64 = __builtin_mips_mult(psLPC_Q14[ 0 ], a_Q12_0 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -1 ], a_Q12_1 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -2 ], a_Q12_2 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -3 ], a_Q12_3 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -4 ], a_Q12_4 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -5 ], a_Q12_5 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -6 ], a_Q12_6 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -7 ], a_Q12_7 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -8 ], a_Q12_8 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -9 ], a_Q12_9 ); + if( predictLPCOrder == 16 ) { + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -10 ], a_Q12_10 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -11 ], a_Q12_11 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -12 ], a_Q12_12 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -13 ], a_Q12_13 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -14 ], a_Q12_14 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -15 ], a_Q12_15 ); + } + temp64 += 32768; + LPC_pred_Q14 = __builtin_mips_extr_w(temp64, 16); + + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + + temp64 = __builtin_mips_mult(tmp2, AR_shp_Q13[ 0 ] ); + + prev = psDD->sAR2_Q14[ 1 ]; + + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + cur = psDD->sAR2_Q14[ j ]; + next = psDD->sAR2_Q14[ j+1 ]; + /* Output of allpass section */ + tmp2 = silk_SMLAWB( prev, cur - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ j - 1 ] ); + temp64 = __builtin_mips_madd( temp64, tmp2, AR_shp_Q13[ j ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( cur, next - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + prev = next; + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + temp64 += 32768; + n_AR_Q14 = __builtin_mips_extr_w(temp64, 16); + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } +} + +#endif /* __NSQ_DEL_DEC_MIPSR1_H__ */ diff --git a/native/codec/libraries/opus/silk/mips/macros_mipsr1.h b/native/codec/libraries/opus/silk/mips/macros_mipsr1.h new file mode 100644 index 0000000..12ed981 --- /dev/null +++ b/native/codec/libraries/opus/silk/mips/macros_mipsr1.h @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +#ifndef __SILK_MACROS_MIPSR1_H__ +#define __SILK_MACROS_MIPSR1_H__ + +#define mips_clz(x) __builtin_clz(x) + +#undef silk_SMULWB +static inline int silk_SMULWB(int a, int b) +{ + long long ac; + int c; + + ac = __builtin_mips_mult(a, (opus_int32)(opus_int16)b); + c = __builtin_mips_extr_w(ac, 16); + + return c; +} + +#undef silk_SMLAWB +#define silk_SMLAWB(a32, b32, c32) ((a32) + silk_SMULWB(b32, c32)) + +#undef silk_SMULWW +static inline int silk_SMULWW(int a, int b) +{ + long long ac; + int c; + + ac = __builtin_mips_mult(a, b); + c = __builtin_mips_extr_w(ac, 16); + + return c; +} + +#undef silk_SMLAWW +static inline int silk_SMLAWW(int a, int b, int c) +{ + long long ac; + int res; + + ac = __builtin_mips_mult(b, c); + res = __builtin_mips_extr_w(ac, 16); + res += a; + + return res; +} + +#define OVERRIDE_silk_CLZ16 +static inline opus_int32 silk_CLZ16(opus_int16 in16) +{ + int re32; + opus_int32 in32 = (opus_int32 )in16; + re32 = mips_clz(in32); + re32-=16; + return re32; +} + +#define OVERRIDE_silk_CLZ32 +static inline opus_int32 silk_CLZ32(opus_int32 in32) +{ + int re32; + re32 = mips_clz(in32); + return re32; +} + +#endif /* __SILK_MACROS_MIPSR1_H__ */ diff --git a/native/codec/libraries/opus/silk/mips/sigproc_fix_mipsr1.h b/native/codec/libraries/opus/silk/mips/sigproc_fix_mipsr1.h new file mode 100644 index 0000000..51520c0 --- /dev/null +++ b/native/codec/libraries/opus/silk/mips/sigproc_fix_mipsr1.h @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_MIPSR1_H +#define SILK_SIGPROC_FIX_MIPSR1_H + +#undef silk_SAT16 +static inline short int silk_SAT16(int a) +{ + int c; + c = __builtin_mips_shll_s_w(a, 16); + c = c>>16; + + return c; +} + +#undef silk_LSHIFT_SAT32 +static inline int silk_LSHIFT_SAT32(int a, int shift) +{ + int r; + + r = __builtin_mips_shll_s_w(a, shift); + + return r; +} + +#undef silk_RSHIFT_ROUND +static inline int silk_RSHIFT_ROUND(int a, int shift) +{ + int r; + + r = __builtin_mips_shra_r_w(a, shift); + return r; +} + +#endif /* SILK_SIGPROC_FIX_MIPSR1_H */ diff --git a/native/codec/libraries/opus/silk/pitch_est_defines.h b/native/codec/libraries/opus/silk/pitch_est_defines.h new file mode 100644 index 0000000..e1e4b5d --- /dev/null +++ b/native/codec/libraries/opus/silk/pitch_est_defines.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_PE_DEFINES_H +#define SILK_PE_DEFINES_H + +#include "SigProc_FIX.h" + +/********************************************************/ +/* Definitions for pitch estimator */ +/********************************************************/ + +#define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */ + +#define PE_MAX_NB_SUBFR 4 +#define PE_SUBFR_LENGTH_MS 5 /* 5 ms */ + +#define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS ) + +#define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS ) +#define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ ) +#define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 ) +#define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 ) + +#define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ ) +#define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ ) + +#define PE_D_SRCH_LENGTH 24 + +#define PE_NB_STAGE3_LAGS 5 + +#define PE_NB_CBKS_STAGE2 3 +#define PE_NB_CBKS_STAGE2_EXT 11 + +#define PE_NB_CBKS_STAGE3_MAX 34 +#define PE_NB_CBKS_STAGE3_MID 24 +#define PE_NB_CBKS_STAGE3_MIN 16 + +#define PE_NB_CBKS_STAGE3_10MS 12 +#define PE_NB_CBKS_STAGE2_10MS 3 + +#define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_FLATCONTOUR_BIAS 0.05f + +#define SILK_PE_MIN_COMPLEX 0 +#define SILK_PE_MID_COMPLEX 1 +#define SILK_PE_MAX_COMPLEX 2 + +/* Tables for 20 ms frames */ +extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ]; +extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ]; +extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ]; +extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ]; + +/* Tables for 10 ms frames */ +extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ]; +extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ]; +extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ]; + +#endif + diff --git a/native/codec/libraries/opus/silk/pitch_est_tables.c b/native/codec/libraries/opus/silk/pitch_est_tables.c new file mode 100644 index 0000000..81a8bac --- /dev/null +++ b/native/codec/libraries/opus/silk/pitch_est_tables.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "pitch_est_defines.h" + +const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] = +{ + {0, 1, 0}, + {0, 0, 1} +}; + +const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] = +{ + { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3}, + { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3} +}; + +const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] = +{ + {-3, 7}, + {-2, 7} +}; + +const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ] = +{ + {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0}, + {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1} +}; + +const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] = +{ + {0, 0, 1,-1, 0, 1,-1, 0,-1, 1,-2, 2,-2,-2, 2,-3, 2, 3,-3,-4, 3,-4, 4, 4,-5, 5,-6,-5, 6,-7, 6, 5, 8,-9}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 0, 1,-1,-1, 1,-1, 2, 1,-1, 2,-2,-2, 2,-2, 2, 2, 3,-3}, + {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,-1, 1, 0, 0, 2, 1,-1, 2,-1,-1, 2,-1, 2, 2,-1, 3,-2,-2,-2, 3}, + {0, 1, 0, 0, 1, 0, 1,-1, 2,-1, 2,-1, 2, 3,-2, 3,-2,-2, 4, 4,-3, 5,-3,-4, 6,-4, 6, 5,-5, 8,-6,-5,-7, 9} +}; + +const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] = +{ + /* Lags to search for low number of stage3 cbks */ + { + {-5,8}, + {-1,6}, + {-1,6}, + {-4,10} + }, + /* Lags to search for middle number of stage3 cbks */ + { + {-6,10}, + {-2,6}, + {-1,6}, + {-5,10} + }, + /* Lags to search for max number of stage3 cbks */ + { + {-9,12}, + {-3,7}, + {-2,7}, + {-7,13} + } +}; + +const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] = +{ + PE_NB_CBKS_STAGE3_MIN, + PE_NB_CBKS_STAGE3_MID, + PE_NB_CBKS_STAGE3_MAX +}; diff --git a/native/codec/libraries/opus/silk/process_NLSFs.c b/native/codec/libraries/opus/silk/process_NLSFs.c new file mode 100644 index 0000000..d130809 --- /dev/null +++ b/native/codec/libraries/opus/silk/process_NLSFs.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, doInterpolate; + opus_int NLSF_mu_Q20; + opus_int16 i_sqr_Q15; + opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ]; + + silk_assert( psEncC->speech_activity_Q8 >= 0 ); + silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) ); + celt_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) ); + + /***********************/ + /* Calculate mu values */ + /***********************/ + /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */ + NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 ); + if( psEncC->nb_subfr == 2 ) { + /* Multiply by 1.5 for 10 ms packets */ + NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 ); + } + + celt_assert( NLSF_mu_Q20 > 0 ); + silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) ); + + /* Calculate NLSF weights */ + silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights for interpolated NLSFs */ + doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 ); + if( doInterpolate ) { + /* Calculate the interpolated NLSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights with contribution from first half */ + i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 ); + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + pNLSFW_QW[ i ] = silk_ADD16( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), silk_RSHIFT( + silk_SMULBB( pNLSFW0_temp_QW[ i ], i_sqr_Q15 ), 16) ); + silk_assert( pNLSFW_QW[ i ] >= 1 ); + } + } + + silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, + NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType ); + + /* Convert quantized NLSFs back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized LSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Convert back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + } else { + /* Copy LPC coefficients for first half from second half */ + celt_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER ); + silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) ); + } +} diff --git a/native/codec/libraries/opus/silk/quant_LTP_gains.c b/native/codec/libraries/opus/silk/quant_LTP_gains.c new file mode 100644 index 0000000..d6b8eff --- /dev/null +++ b/native/codec/libraries/opus/silk/quant_LTP_gains.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */ + const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */ + const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int j, k, cbk_size; + opus_int8 temp_idx[ MAX_NB_SUBFR ]; + const opus_uint8 *cl_ptr_Q5; + const opus_int8 *cbk_ptr_Q7; + const opus_uint8 *cbk_gain_ptr_Q7; + const opus_int32 *XX_Q17_ptr, *xX_Q17_ptr; + opus_int32 res_nrg_Q15_subfr, res_nrg_Q15, rate_dist_Q7_subfr, rate_dist_Q7, min_rate_dist_Q7; + opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7; + opus_int gain_Q7; + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist_Q7 = silk_int32_MAX; + best_sum_log_gain_Q7 = 0; + for( k = 0; k < 3; k++ ) { + /* Safety margin for pitch gain control, to take into account factors + such as state rescaling/rewhitening. */ + opus_int32 gain_safety = SILK_FIX_CONST( 0.4, 7 ); + + cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ]; + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ]; + cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ]; + cbk_size = silk_LTP_vq_sizes[ k ]; + + /* Set up pointers to first subframe */ + XX_Q17_ptr = XX_Q17; + xX_Q17_ptr = xX_Q17; + + res_nrg_Q15 = 0; + rate_dist_Q7 = 0; + sum_log_gain_tmp_Q7 = *sum_log_gain_Q7; + for( j = 0; j < nb_subfr; j++ ) { + max_gain_Q7 = silk_log2lin( ( SILK_FIX_CONST( MAX_SUM_LOG_GAIN_DB / 6.0, 7 ) - sum_log_gain_tmp_Q7 ) + + SILK_FIX_CONST( 7, 7 ) ) - gain_safety; + silk_VQ_WMat_EC( + &temp_idx[ j ], /* O index of best codebook vector */ + &res_nrg_Q15_subfr, /* O residual energy */ + &rate_dist_Q7_subfr, /* O best weighted quantization error + mu * rate */ + &gain_Q7, /* O sum of absolute LTP coefficients */ + XX_Q17_ptr, /* I correlation matrix */ + xX_Q17_ptr, /* I correlation vector */ + cbk_ptr_Q7, /* I codebook */ + cbk_gain_ptr_Q7, /* I codebook effective gains */ + cl_ptr_Q5, /* I code length for each codebook vector */ + subfr_len, /* I number of samples per subframe */ + max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + cbk_size, /* I number of vectors in codebook */ + arch /* I Run-time architecture */ + ); + + res_nrg_Q15 = silk_ADD_POS_SAT32( res_nrg_Q15, res_nrg_Q15_subfr ); + rate_dist_Q7 = silk_ADD_POS_SAT32( rate_dist_Q7, rate_dist_Q7_subfr ); + sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7 + + silk_lin2log( gain_safety + gain_Q7 ) - SILK_FIX_CONST( 7, 7 )); + + XX_Q17_ptr += LTP_ORDER * LTP_ORDER; + xX_Q17_ptr += LTP_ORDER; + } + + if( rate_dist_Q7 <= min_rate_dist_Q7 ) { + min_rate_dist_Q7 = rate_dist_Q7; + *periodicity_index = (opus_int8)k; + silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) ); + best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7; + } + } + + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ]; + for( j = 0; j < nb_subfr; j++ ) { + for( k = 0; k < LTP_ORDER; k++ ) { + B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 ); + } + } + + if( nb_subfr == 2 ) { + res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 1 ); + } else { + res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 2 ); + } + + *sum_log_gain_Q7 = best_sum_log_gain_Q7; + *pred_gain_dB_Q7 = (opus_int)silk_SMULBB( -3, silk_lin2log( res_nrg_Q15 ) - ( 15 << 7 ) ); +} diff --git a/native/codec/libraries/opus/silk/resampler.c b/native/codec/libraries/opus/silk/resampler.c new file mode 100644 index 0000000..1f11e50 --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Matrix of resampling methods used: + * Fs_out (kHz) + * 8 12 16 24 48 + * + * 8 C UF U UF UF + * 12 AF C UF U UF + * Fs_in (kHz) 16 D AF C UF UF + * 24 AF D AF C U + * 48 AF AF AF D C + * + * C -> Copy (no resampling) + * D -> Allpass-based 2x downsampling + * U -> Allpass-based 2x upsampling + * UF -> Allpass-based 2x upsampling followed by FIR interpolation + * AF -> AR2 filter followed by FIR interpolation + */ + +#include "resampler_private.h" + +/* Tables with delay compensation values to equalize total delay for different modes */ +static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = { +/* in \ out 8 12 16 */ +/* 8 */ { 6, 0, 3 }, +/* 12 */ { 0, 7, 3 }, +/* 16 */ { 0, 1, 10 }, +/* 24 */ { 0, 2, 6 }, +/* 48 */ { 18, 10, 12 } +}; + +static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = { +/* in \ out 8 12 16 24 48 */ +/* 8 */ { 4, 0, 2, 0, 0 }, +/* 12 */ { 0, 9, 4, 7, 4 }, +/* 16 */ { 0, 3, 12, 7, 7 } +}; + +/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */ +#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 ) + +#define USE_silk_resampler_copy (0) +#define USE_silk_resampler_private_up2_HQ_wrapper (1) +#define USE_silk_resampler_private_IIR_FIR (2) +#define USE_silk_resampler_private_down_FIR (3) + +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +) +{ + opus_int up2x; + + /* Clear state */ + silk_memset( S, 0, sizeof( silk_resampler_state_struct ) ); + + /* Input checking */ + if( forEnc ) { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 ) ) { + celt_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } else { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000 ) ) { + celt_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } + + S->Fs_in_kHz = silk_DIV32_16( Fs_Hz_in, 1000 ); + S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 ); + + /* Number of samples processed per batch */ + S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS; + + /* Find resampler with the right sampling ratio */ + up2x = 0; + if( Fs_Hz_out > Fs_Hz_in ) { + /* Upsample */ + if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + S->resampler_function = USE_silk_resampler_private_IIR_FIR; + up2x = 1; + } + } else if ( Fs_Hz_out < Fs_Hz_in ) { + /* Downsample */ + S->resampler_function = USE_silk_resampler_private_down_FIR; + if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */ + S->FIR_Fracs = 3; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_3_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */ + S->FIR_Fracs = 2; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_2_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1; + S->Coefs = silk_Resampler_1_2_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_6_COEFS; + } else { + /* None available */ + celt_assert( 0 ); + return -1; + } + } else { + /* Input and output sampling rates are equal: copy */ + S->resampler_function = USE_silk_resampler_copy; + } + + /* Ratio of input/output samples */ + S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 ); + /* Make sure the ratio is rounded up */ + while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) { + S->invRatio_Q16++; + } + + return 0; +} + +/* Resampler: convert from one sampling rate to another */ +/* Input and output sampling rate are at most 48000 Hz */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int nSamples; + + /* Need at least 1 ms of input data */ + celt_assert( inLen >= S->Fs_in_kHz ); + /* Delay can't exceed the 1 ms of buffering */ + celt_assert( S->inputDelay <= S->Fs_in_kHz ); + + nSamples = S->Fs_in_kHz - S->inputDelay; + + /* Copy to delay buffer */ + silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) ); + + switch( S->resampler_function ) { + case USE_silk_resampler_private_up2_HQ_wrapper: + silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_IIR_FIR: + silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_down_FIR: + silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + default: + silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) ); + silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) ); + } + + /* Copy to delay buffer */ + silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) ); + + return 0; +} diff --git a/native/codec/libraries/opus/silk/resampler_down2.c b/native/codec/libraries/opus/silk/resampler_down2.c new file mode 100644 index 0000000..971d7bf --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_down2.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_rom.h" + +/* Downsample by a factor 2 */ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ floor(len/2) ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 ); + opus_int32 in32, out32, Y, X; + + celt_assert( silk_resampler_down2_0 > 0 ); + celt_assert( silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_down2_1 ); + out32 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_down2_0 ); + out32 = silk_ADD32( out32, S[ 1 ] ); + out32 = silk_ADD32( out32, X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) ); + } +} + diff --git a/native/codec/libraries/opus/silk/resampler_down2_3.c b/native/codec/libraries/opus/silk/resampler_down2_3.c new file mode 100644 index 0000000..4342614 --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_down2_3.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +#define ORDER_FIR 4 + +/* Downsample by a factor 2/3, low quality */ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 nSamplesIn, counter, res_Q6; + VARDECL( opus_int32, buf ); + opus_int32 *buf_ptr; + SAVE_STACK; + + ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/resampler_private.h b/native/codec/libraries/opus/silk/resampler_private.h new file mode 100644 index 0000000..422a7d9 --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_private.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_PRIVATE_H +#define SILK_RESAMPLER_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SigProc_FIX.h" +#include "resampler_structs.h" +#include "resampler_rom.h" + +/* Number of input samples to process in the inner loop */ +#define RESAMPLER_MAX_BATCH_SIZE_MS 10 +#define RESAMPLER_MAX_FS_KHZ 48 +#define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ ) + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Second order AR filter */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +); + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_PRIVATE_H */ diff --git a/native/codec/libraries/opus/silk/resampler_private_AR2.c b/native/codec/libraries/opus/silk/resampler_private_AR2.c new file mode 100644 index 0000000..5fff237 --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_private_AR2.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Second order AR filter with single delay elements */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +) +{ + opus_int32 k; + opus_int32 out32; + + for( k = 0; k < len; k++ ) { + out32 = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 ); + out_Q8[ k ] = out32; + out32 = silk_LSHIFT( out32, 2 ); + S[ 0 ] = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] ); + S[ 1 ] = silk_SMULWB( out32, A_Q14[ 1 ] ); + } +} + diff --git a/native/codec/libraries/opus/silk/resampler_private_IIR_FIR.c b/native/codec/libraries/opus/silk/resampler_private_IIR_FIR.c new file mode 100644 index 0000000..6b2b3a2 --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_private_IIR_FIR.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL( + opus_int16 *out, + opus_int16 *buf, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q15; + opus_int16 *buf_ptr; + opus_int32 table_index; + + /* Interpolate upsampled signal and store in output array */ + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 ); + buf_ptr = &buf[ index_Q16 >> 16 ]; + + res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] ); + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) ); + } + return out; +} +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + VARDECL( opus_int16, buf ); + SAVE_STACK; + + ALLOC( buf, 2 * S->batchSize + RESAMPLER_ORDER_FIR_12, opus_int16 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR.i16, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 ); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL( out, buf, max_index_Q16, index_increment_Q16 ); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR.i16, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/resampler_private_down_FIR.c b/native/codec/libraries/opus/silk/resampler_private_down_FIR.c new file mode 100644 index 0000000..3e8735a --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_private_down_FIR.c @@ -0,0 +1,194 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +static OPUS_INLINE opus_int16 *silk_resampler_private_down_FIR_INTERPOL( + opus_int16 *out, + opus_int32 *buf, + const opus_int16 *FIR_Coefs, + opus_int FIR_Order, + opus_int FIR_Fracs, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q6; + opus_int32 *buf_ptr; + opus_int32 interpol_ind; + const opus_int16 *interpol_ptr; + + switch( FIR_Order ) { + case RESAMPLER_DOWN_ORDER_FIR0: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs ); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ]; + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] ); + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ]; + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 8 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR1: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 23 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 22 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 21 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 20 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 19 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 18 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 17 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 16 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 15 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 14 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR2: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 35 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 34 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 33 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 32 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 31 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 30 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 29 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 28 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 27 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 26 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + default: + celt_assert( 0 ); + } + return out; +} + +/* Resample with a 2nd order AR filter followed by FIR interpolation */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + VARDECL( opus_int32, buf ); + const opus_int16 *FIR_Coefs; + SAVE_STACK; + + ALLOC( buf, S->batchSize + S->FIR_Order, opus_int32 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR.i32, S->FIR_Order * sizeof( opus_int32 ) ); + + FIR_Coefs = &S->Coefs[ 2 ]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 ); + + /* Interpolate filtered signal */ + out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order, + S->FIR_Fracs, max_index_Q16, index_increment_Q16 ); + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 1 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR.i32, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/resampler_private_up2_HQ.c b/native/codec/libraries/opus/silk/resampler_private_up2_HQ.c new file mode 100644 index 0000000..c7ec8de --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_private_up2_HQ.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Upsample by a factor 2, high quality */ +/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + opus_int32 k; + opus_int32 in32, out32_1, out32_2, Y, X; + + silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 ); + silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 ); + + /* First all-pass section for even output sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] ); + out32_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for even output sample */ + Y = silk_SUB32( out32_1, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] ); + out32_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for even output sample */ + Y = silk_SUB32( out32_2, S[ 2 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] ); + out32_1 = silk_ADD32( S[ 2 ], X ); + S[ 2 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + + /* First all-pass section for odd output sample */ + Y = silk_SUB32( in32, S[ 3 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] ); + out32_1 = silk_ADD32( S[ 3 ], X ); + S[ 3 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for odd output sample */ + Y = silk_SUB32( out32_1, S[ 4 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] ); + out32_2 = silk_ADD32( S[ 4 ], X ); + S[ 4 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for odd output sample */ + Y = silk_SUB32( out32_2, S[ 5 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] ); + out32_1 = silk_ADD32( S[ 5 ], X ); + S[ 5 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + } +} + +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + silk_resampler_private_up2_HQ( S->sIIR, out, in, len ); +} diff --git a/native/codec/libraries/opus/silk/resampler_rom.c b/native/codec/libraries/opus/silk/resampler_rom.c new file mode 100644 index 0000000..5e6b044 --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_rom.c @@ -0,0 +1,96 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Filter coefficients for IIR/FIR polyphase resampling * + * Total size: 179 Words (358 Bytes) */ + +#include "resampler_private.h" + +/* Matlab code for the notch filter coefficients: */ +/* B = [1, 0.147, 1]; A = [1, 0.107, 0.89]; G = 0.93; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]) */ +/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */ +/* const opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634, -7012, 7209, 30474 }; */ + +/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -20694, -13867, + -49, 64, 17, -157, 353, -496, 163, 11047, 22205, + -39, 6, 91, -170, 186, 23, -896, 6336, 19928, + -19, -36, 102, -89, -24, 328, -951, 2568, 15909, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -14457, -14019, + 64, 128, -122, 36, 310, -768, 584, 9267, 17733, + 12, 128, 18, -142, 288, -117, -865, 4123, 14459, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = { + 616, -14323, + -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 16102, -15162, + -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 22500, -15099, + 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 27540, -15257, + 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = { + -2797, -6507, + 4697, 10739, + 1567, 8276, +}; + +/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = { + { 189, -600, 617, 30567 }, + { 117, -159, -1070, 29704 }, + { 52, 221, -2392, 28276 }, + { -4, 529, -3350, 26341 }, + { -48, 758, -3956, 23973 }, + { -80, 905, -4235, 21254 }, + { -99, 972, -4222, 18278 }, + { -107, 967, -3957, 15143 }, + { -103, 896, -3487, 11950 }, + { -91, 773, -2865, 8798 }, + { -71, 611, -2143, 5784 }, + { -46, 425, -1375, 2996 }, +}; diff --git a/native/codec/libraries/opus/silk/resampler_rom.h b/native/codec/libraries/opus/silk/resampler_rom.h new file mode 100644 index 0000000..490b338 --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_rom.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_FIX_RESAMPLER_ROM_H +#define SILK_FIX_RESAMPLER_ROM_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "typedef.h" +#include "resampler_structs.h" + +#define RESAMPLER_DOWN_ORDER_FIR0 18 +#define RESAMPLER_DOWN_ORDER_FIR1 24 +#define RESAMPLER_DOWN_ORDER_FIR2 36 +#define RESAMPLER_ORDER_FIR_12 8 + +/* Tables for 2x downsampler */ +static const opus_int16 silk_resampler_down2_0 = 9872; +static const opus_int16 silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, high quality */ +static const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 }; +static const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 }; + +/* Tables with IIR and FIR coefficients for fractional downsamplers */ +extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ]; +extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ]; + +/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */ +extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ]; + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_RESAMPLER_ROM_H */ diff --git a/native/codec/libraries/opus/silk/resampler_structs.h b/native/codec/libraries/opus/silk/resampler_structs.h new file mode 100644 index 0000000..9e9457d --- /dev/null +++ b/native/codec/libraries/opus/silk/resampler_structs.h @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_STRUCTS_H +#define SILK_RESAMPLER_STRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SILK_RESAMPLER_MAX_FIR_ORDER 36 +#define SILK_RESAMPLER_MAX_IIR_ORDER 6 + +typedef struct _silk_resampler_state_struct{ + opus_int32 sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */ + union{ + opus_int32 i32[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + opus_int16 i16[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + } sFIR; + opus_int16 delayBuf[ 48 ]; + opus_int resampler_function; + opus_int batchSize; + opus_int32 invRatio_Q16; + opus_int FIR_Order; + opus_int FIR_Fracs; + opus_int Fs_in_kHz; + opus_int Fs_out_kHz; + opus_int inputDelay; + const opus_int16 *Coefs; +} silk_resampler_state_struct; + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_STRUCTS_H */ + diff --git a/native/codec/libraries/opus/silk/shell_coder.c b/native/codec/libraries/opus/silk/shell_coder.c new file mode 100644 index 0000000..4af3414 --- /dev/null +++ b/native/codec/libraries/opus/silk/shell_coder.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* shell coder; pulse-subframe length is hardcoded */ + +static OPUS_INLINE void combine_pulses( + opus_int *out, /* O combined pulses vector [len] */ + const opus_int *in, /* I input vector [2 * len] */ + const opus_int len /* I number of OUTPUT samples */ +) +{ + opus_int k; + for( k = 0; k < len; k++ ) { + out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ]; + } +} + +static OPUS_INLINE void encode_split( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int p_child1, /* I pulse amplitude of first child subframe */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + } +} + +static OPUS_INLINE void decode_split( + opus_int16 *p_child1, /* O pulse amplitude of first child subframe */ + opus_int16 *p_child2, /* O pulse amplitude of second child subframe */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + p_child2[ 0 ] = p - p_child1[ 0 ]; + } else { + p_child1[ 0 ] = 0; + p_child2[ 0 ] = 0; + } +} + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +) +{ + opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + /* tree representation per pulse-subframe */ + combine_pulses( pulses1, pulses0, 8 ); + combine_pulses( pulses2, pulses1, 4 ); + combine_pulses( pulses3, pulses2, 2 ); + combine_pulses( pulses4, pulses3, 1 ); + + encode_split( psRangeEnc, pulses3[ 0 ], pulses4[ 0 ], silk_shell_code_table3 ); + + encode_split( psRangeEnc, pulses2[ 0 ], pulses3[ 0 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 0 ], pulses2[ 0 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 0 ], pulses1[ 0 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 2 ], pulses1[ 1 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 2 ], pulses2[ 1 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 4 ], pulses1[ 2 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 6 ], pulses1[ 3 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses2[ 2 ], pulses3[ 1 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 4 ], pulses2[ 2 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 8 ], pulses1[ 4 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 6 ], pulses2[ 3 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 ); +} + + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +) +{ + opus_int16 pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + decode_split( &pulses3[ 0 ], &pulses3[ 1 ], psRangeDec, pulses4, silk_shell_code_table3 ); + + decode_split( &pulses2[ 0 ], &pulses2[ 1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 0 ], &pulses1[ 1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 0 ], &pulses0[ 1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 2 ], &pulses0[ 3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 2 ], &pulses1[ 3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 4 ], &pulses0[ 5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 6 ], &pulses0[ 7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 ); + + decode_split( &pulses2[ 2 ], &pulses2[ 3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 4 ], &pulses1[ 5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 8 ], &pulses0[ 9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 6 ], &pulses1[ 7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 ); +} diff --git a/native/codec/libraries/opus/silk/sigm_Q15.c b/native/codec/libraries/opus/silk/sigm_Q15.c new file mode 100644 index 0000000..3c507d2 --- /dev/null +++ b/native/codec/libraries/opus/silk/sigm_Q15.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Approximate sigmoid function */ + +#include "SigProc_FIX.h" + +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const opus_int32 sigm_LUT_slope_Q10[ 6 ] = { + 237, 153, 73, 30, 12, 7 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const opus_int32 sigm_LUT_pos_Q15[ 6 ] = { + 16384, 23955, 28861, 31213, 32178, 32548 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const opus_int32 sigm_LUT_neg_Q15[ 6 ] = { + 16384, 8812, 3906, 1554, 589, 219 +}; + +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +) +{ + opus_int ind; + + if( in_Q5 < 0 ) { + /* Negative input */ + in_Q5 = -in_Q5; + if( in_Q5 >= 6 * 32 ) { + return 0; /* Clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_neg_Q15[ ind ] - silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } else { + /* Positive input */ + if( in_Q5 >= 6 * 32 ) { + return 32767; /* clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } +} + diff --git a/native/codec/libraries/opus/silk/sort.c b/native/codec/libraries/opus/silk/sort.c new file mode 100644 index 0000000..4fba16f --- /dev/null +++ b/native/codec/libraries/opus/silk/sort.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ +/* */ +/* Shell short: https://en.wikipedia.org/wiki/Shell_sort */ + +#include "SigProc_FIX.h" + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int32 value; + opus_int i, j; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value < a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} + +#ifdef FIXED_POINT +/* This function is only used by the fixed-point build */ +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int i, j; + opus_int value; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} +#endif + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +) +{ + opus_int value; + opus_int i, j; + + /* Safety checks */ + celt_assert( L > 0 ); + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < L; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + } + a[ j + 1 ] = value; /* Write value */ + } +} diff --git a/native/codec/libraries/opus/silk/stereo_LR_to_MS.c b/native/codec/libraries/opus/silk/stereo_LR_to_MS.c new file mode 100644 index 0000000..c822666 --- /dev/null +++ b/native/codec/libraries/opus/silk/stereo_LR_to_MS.c @@ -0,0 +1,229 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13; + opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24; + VARDECL( opus_int16, side ); + VARDECL( opus_int16, LP_mid ); + VARDECL( opus_int16, HP_mid ); + VARDECL( opus_int16, LP_side ); + VARDECL( opus_int16, HP_side ); + opus_int16 *mid = &x1[ -2 ]; + SAVE_STACK; + + ALLOC( side, frame_length + 2, opus_int16 ); + /* Convert to basic mid/side signals */ + for( n = 0; n < frame_length + 2; n++ ) { + sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ]; + diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ]; + mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) ); + } + + /* Buffering */ + silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* LP and HP filter mid signal */ + ALLOC( LP_mid, frame_length, opus_int16 ); + ALLOC( HP_mid, frame_length, opus_int16 ); + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 ); + LP_mid[ n ] = sum; + HP_mid[ n ] = mid[ n + 1 ] - sum; + } + + /* LP and HP filter side signal */ + ALLOC( LP_side, frame_length, opus_int16 ); + ALLOC( HP_side, frame_length, opus_int16 ); + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + (opus_int32)side[ n + 2 ], side[ n + 1 ], 1 ), 2 ); + LP_side[ n ] = sum; + HP_side[ n ] = side[ n + 1 ] - sum; + } + + /* Find energies and predictors */ + is10msFrame = frame_length == 10 * fs_kHz; + smooth_coef_Q16 = is10msFrame ? + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) : + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 ); + smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 ); + + pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 ); + pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 ); + /* Ratio of the norms of residual and mid signals */ + frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 ); + frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) ); + + /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */ + total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */ + if( total_rate_bps < 1 ) { + total_rate_bps = 1; + } + min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 600 ); + silk_assert( min_mid_rate_bps < 32767 ); + /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */ + frac_3_Q16 = silk_MUL( 3, frac_Q16 ); + mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 ); + /* If Mid bitrate below minimum, reduce stereo width */ + if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) { + mid_side_rates_bps[ 0 ] = min_mid_rate_bps; + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */ + width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps, + silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 ); + width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) ); + } else { + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } + + /* Smoother */ + state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 ); + + /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */ + *mid_only_flag = 0; + if( toMono ) { + /* Last frame before stereo->mono transition; collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + silk_stereo_quant_pred( pred_Q13, ix ); + } else if( state->width_prev_Q14 == 0 && + ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) ) + { + /* Code as panned-mono; previous frame already had zero width */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + mid_side_rates_bps[ 0 ] = total_rate_bps; + mid_side_rates_bps[ 1 ] = 0; + *mid_only_flag = 1; + } else if( state->width_prev_Q14 != 0 && + ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) ) + { + /* Transition to zero-width stereo */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) { + /* Full-width stereo coding */ + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } else { + /* Reduced-width stereo coding; scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = state->smth_width_Q14; + } + + /* Make sure to keep on encoding until the tapered output has been transmitted */ + if( *mid_only_flag == 1 ) { + state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz; + if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) { + *mid_only_flag = 0; + } else { + /* Limit to avoid wrapping around */ + state->silent_side_len = 10000; + } + } else { + state->silent_side_len = 0; + } + + if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) { + mid_side_rates_bps[ 1 ] = 1; + mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]); + } + + /* Interpolate predictors and subtract prediction from side channel */ + pred0_Q13 = -state->pred_prev_Q13[ 0 ]; + pred1_Q13 = -state->pred_prev_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 ); + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + w_Q24 += deltaw_Q24; + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + + pred0_Q13 = -pred_Q13[ 0 ]; + pred1_Q13 = -pred_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( width_Q14, 10 ); + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ]; + state->width_prev_Q14 = (opus_int16)width_Q14; + RESTORE_STACK; +} diff --git a/native/codec/libraries/opus/silk/stereo_MS_to_LR.c b/native/codec/libraries/opus/silk/stereo_MS_to_LR.c new file mode 100644 index 0000000..62521a4 --- /dev/null +++ b/native/codec/libraries/opus/silk/stereo_MS_to_LR.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, pred0_Q13, pred1_Q13; + + /* Buffering */ + silk_memcpy( x1, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &x1[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* Interpolate predictors and add prediction to side channel */ + pred0_Q13 = state->pred_prev_Q13[ 0 ]; + pred1_Q13 = state->pred_prev_Q13[ 1 ]; + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + pred0_Q13 = pred_Q13[ 0 ]; + pred1_Q13 = pred_Q13[ 1 ]; + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ]; + + /* Convert to left/right signals */ + for( n = 0; n < frame_length; n++ ) { + sum = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ]; + diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ]; + x1[ n + 1 ] = (opus_int16)silk_SAT16( sum ); + x2[ n + 1 ] = (opus_int16)silk_SAT16( diff ); + } +} diff --git a/native/codec/libraries/opus/silk/stereo_decode_pred.c b/native/codec/libraries/opus/silk/stereo_decode_pred.c new file mode 100644 index 0000000..56ba392 --- /dev/null +++ b/native/codec/libraries/opus/silk/stereo_decode_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +) +{ + opus_int n, ix[ 2 ][ 3 ]; + opus_int32 low_Q13, step_Q13; + + /* Entropy decoding */ + n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 ); + ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 ); + ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ]; + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 ); + ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 ); + } + + /* Dequantize */ + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ]; + low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 ); + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +) +{ + /* Decode flag that only mid channel is coded */ + *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/native/codec/libraries/opus/silk/stereo_encode_pred.c b/native/codec/libraries/opus/silk/stereo_encode_pred.c new file mode 100644 index 0000000..03becb6 --- /dev/null +++ b/native/codec/libraries/opus/silk/stereo_encode_pred.c @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +) +{ + opus_int n; + + /* Entropy coding */ + n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ]; + celt_assert( n < 25 ); + ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 ); + for( n = 0; n < 2; n++ ) { + celt_assert( ix[ n ][ 0 ] < 3 ); + celt_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 ); + } +} + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +) +{ + /* Encode flag that only mid channel is coded */ + ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/native/codec/libraries/opus/silk/stereo_find_predictor.c b/native/codec/libraries/opus/silk/stereo_find_predictor.c new file mode 100644 index 0000000..e30e90b --- /dev/null +++ b/native/codec/libraries/opus/silk/stereo_find_predictor.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +) +{ + opus_int scale, scale1, scale2; + opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10; + + /* Find predictor */ + silk_sum_sqr_shift( &nrgx, &scale1, x, length ); + silk_sum_sqr_shift( &nrgy, &scale2, y, length ); + scale = silk_max_int( scale1, scale2 ); + scale = scale + ( scale & 1 ); /* make even */ + nrgy = silk_RSHIFT32( nrgy, scale - scale2 ); + nrgx = silk_RSHIFT32( nrgx, scale - scale1 ); + nrgx = silk_max_int( nrgx, 1 ); + corr = silk_inner_prod_aligned_scale( x, y, scale, length ); + pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 ); + pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 ); + pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 ); + + /* Faster update for signals with large prediction parameters */ + smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) ); + + /* Smoothed mid and residual norms */ + silk_assert( smooth_coef_Q16 < 32768 ); + scale = silk_RSHIFT( scale, 1 ); + mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ], + smooth_coef_Q16 ); + /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */ + nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 ); + nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 ); + mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ], + smooth_coef_Q16 ); + + /* Ratio of smoothed residual and mid norms */ + *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 ); + *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 ); + + return pred_Q13; +} diff --git a/native/codec/libraries/opus/silk/stereo_quant_pred.c b/native/codec/libraries/opus/silk/stereo_quant_pred.c new file mode 100644 index 0000000..d4ced6c --- /dev/null +++ b/native/codec/libraries/opus/silk/stereo_quant_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +) +{ + opus_int i, j, n; + opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0; + + /* Quantize */ + for( n = 0; n < 2; n++ ) { + /* Brute-force search over quantization levels */ + err_min_Q13 = silk_int32_MAX; + for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) { + low_Q13 = silk_stereo_pred_quant_Q13[ i ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) { + lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 ); + err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 ); + if( err_Q13 < err_min_Q13 ) { + err_min_Q13 = err_Q13; + quant_pred_Q13 = lvl_Q13; + ix[ n ][ 0 ] = i; + ix[ n ][ 1 ] = j; + } else { + /* Error increasing, so we're past the optimum */ + goto done; + } + } + } + done: + ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 ); + ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3; + pred_Q13[ n ] = quant_pred_Q13; + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} diff --git a/native/codec/libraries/opus/silk/structs.h b/native/codec/libraries/opus/silk/structs.h new file mode 100644 index 0000000..3380c75 --- /dev/null +++ b/native/codec/libraries/opus/silk/structs.h @@ -0,0 +1,329 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_STRUCTS_H +#define SILK_STRUCTS_H + +#include "typedef.h" +#include "SigProc_FIX.h" +#include "define.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************/ +/* Noise shaping quantization state */ +/************************************/ +typedef struct { + opus_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */ + opus_int32 sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 sLF_AR_shp_Q14; + opus_int32 sDiff_shp_Q14; + opus_int lagPrev; + opus_int sLTP_buf_idx; + opus_int sLTP_shp_buf_idx; + opus_int32 rand_seed; + opus_int32 prev_gain_Q16; + opus_int rewhite_flag; +} silk_nsq_state; + +/********************************/ +/* VAD state */ +/********************************/ +typedef struct { + opus_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */ + opus_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */ + opus_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */ + opus_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */ + opus_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */ + opus_int16 HPstate; /* State of differentiator in the lowest band */ + opus_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */ + opus_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */ + opus_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */ + opus_int32 counter; /* Frame counter used in the initial phase */ +} silk_VAD_state; + +/* Variable cut-off low-pass filter state */ +typedef struct { + opus_int32 In_LP_State[ 2 ]; /* Low pass filter state */ + opus_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + opus_int mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */ + opus_int32 saved_fs_kHz; /* If non-zero, holds the last sampling rate before a bandwidth switching reset. */ +} silk_LP_state; + +/* Structure containing NLSF codebook */ +typedef struct { + const opus_int16 nVectors; + const opus_int16 order; + const opus_int16 quantStepSize_Q16; + const opus_int16 invQuantStepSize_Q6; + const opus_uint8 *CB1_NLSF_Q8; + const opus_int16 *CB1_Wght_Q9; + const opus_uint8 *CB1_iCDF; + const opus_uint8 *pred_Q8; + const opus_uint8 *ec_sel; + const opus_uint8 *ec_iCDF; + const opus_uint8 *ec_Rates_Q5; + const opus_int16 *deltaMin_Q15; +} silk_NLSF_CB_struct; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; + opus_int32 mid_side_amp_Q0[ 4 ]; + opus_int16 smth_width_Q14; + opus_int16 width_prev_Q14; + opus_int16 silent_side_len; + opus_int8 predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ]; + opus_int8 mid_only_flags[ MAX_FRAMES_PER_PACKET ]; +} stereo_enc_state; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; +} stereo_dec_state; + +typedef struct { + opus_int8 GainsIndices[ MAX_NB_SUBFR ]; + opus_int8 LTPIndex[ MAX_NB_SUBFR ]; + opus_int8 NLSFIndices[ MAX_LPC_ORDER + 1 ]; + opus_int16 lagIndex; + opus_int8 contourIndex; + opus_int8 signalType; + opus_int8 quantOffsetType; + opus_int8 NLSFInterpCoef_Q2; + opus_int8 PERIndex; + opus_int8 LTP_scaleIndex; + opus_int8 Seed; +} SideInfoIndices; + +/********************************/ +/* Encoder state */ +/********************************/ +typedef struct { + opus_int32 In_HP_State[ 2 ]; /* High pass filter state */ + opus_int32 variable_HP_smth1_Q15; /* State of first smoother */ + opus_int32 variable_HP_smth2_Q15; /* State of second smoother */ + silk_LP_state sLP; /* Low pass filter state */ + silk_VAD_state sVAD; /* Voice activity detector state */ + silk_nsq_state sNSQ; /* Noise Shape Quantizer State */ + opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ + opus_int speech_activity_Q8; /* Speech activity */ + opus_int allow_bandwidth_switch; /* Flag indicating that switching of internal bandwidth is allowed */ + opus_int8 LBRRprevLastGainIndex; + opus_int8 prevSignalType; + opus_int prevLag; + opus_int pitch_LPC_win_length; + opus_int max_pitch_lag; /* Highest possible pitch lag (samples) */ + opus_int32 API_fs_Hz; /* API sampling frequency (Hz) */ + opus_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */ + opus_int maxInternal_fs_Hz; /* Maximum internal sampling frequency (Hz) */ + opus_int minInternal_fs_Hz; /* Minimum internal sampling frequency (Hz) */ + opus_int desiredInternal_fs_Hz; /* Soft request for internal sampling frequency (Hz) */ + opus_int fs_kHz; /* Internal sampling frequency (kHz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int la_pitch; /* Look-ahead for pitch analysis (samples) */ + opus_int la_shape; /* Look-ahead for noise shape analysis (samples) */ + opus_int shapeWinLength; /* Window length for noise shape analysis (samples) */ + opus_int32 TargetRate_bps; /* Target bitrate (bps) */ + opus_int PacketSize_ms; /* Number of milliseconds to put in each packet */ + opus_int PacketLoss_perc; /* Packet loss rate measured by farend */ + opus_int32 frameCounter; + opus_int Complexity; /* Complexity setting */ + opus_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */ + opus_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */ + opus_int shapingLPCOrder; /* Filter order for noise shaping filters */ + opus_int predictLPCOrder; /* Filter order for prediction filters */ + opus_int pitchEstimationComplexity; /* Complexity level for pitch estimator */ + opus_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */ + opus_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */ + opus_int32 sum_log_gain_Q7; /* Cumulative max prediction gain */ + opus_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation, pitch prediction */ + opus_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */ + opus_int warping_Q16; /* Warping parameter for warped noise shaping */ + opus_int useCBR; /* Flag to enable constant bitrate */ + opus_int prefillFlag; /* Flag to indicate that only buffers are prefilled, no coding */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + opus_int input_quality_bands_Q15[ VAD_N_BANDS ]; + opus_int input_tilt_Q15; + opus_int SNR_dB_Q7; /* Quality setting */ + + opus_int8 VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int8 LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + SideInfoIndices indices; + opus_int8 pulses[ MAX_FRAME_LENGTH ]; + + int arch; + + /* Input/output buffering */ + opus_int16 inputBuf[ MAX_FRAME_LENGTH + 2 ]; /* Buffer containing input signal */ + opus_int inputBufIx; + opus_int nFramesPerPacket; + opus_int nFramesEncoded; /* Number of frames analyzed in current packet */ + + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int channelNb; + + /* Parameters For LTP scaling Control */ + opus_int frames_since_onset; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + silk_resampler_state_struct resampler_state; + + /* DTX */ + opus_int useDTX; /* Flag to enable DTX */ + opus_int inDTX; /* Flag to signal DTX period */ + opus_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */ + + /* Inband Low Bitrate Redundancy (LBRR) data */ + opus_int useInBandFEC; /* Saves the API setting for query */ + opus_int LBRR_enabled; /* Depends on useInBandFRC, bitrate and packet loss rate */ + opus_int LBRR_GainIncreases; /* Gains increment for coding LBRR frames */ + SideInfoIndices indices_LBRR[ MAX_FRAMES_PER_PACKET ]; + opus_int8 pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ]; +} silk_encoder_state; + + +/* Struct for Packet Loss Concealment */ +typedef struct { + opus_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */ + opus_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */ + opus_int16 prevLPC_Q12[ MAX_LPC_ORDER ]; + opus_int last_frame_lost; /* Was previous frame lost */ + opus_int32 rand_seed; /* Seed for unvoiced signal generation */ + opus_int16 randScale_Q14; /* Scaling of unvoiced random signal */ + opus_int32 conc_energy; + opus_int conc_energy_shift; + opus_int16 prevLTP_scale_Q14; + opus_int32 prevGain_Q16[ 2 ]; + opus_int fs_kHz; + opus_int nb_subfr; + opus_int subfr_length; +} silk_PLC_struct; + +/* Struct for CNG */ +typedef struct { + opus_int32 CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ]; + opus_int16 CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ]; + opus_int32 CNG_synth_state[ MAX_LPC_ORDER ]; + opus_int32 CNG_smth_Gain_Q16; + opus_int32 rand_seed; + opus_int fs_kHz; +} silk_CNG_struct; + +/********************************/ +/* Decoder state */ +/********************************/ +typedef struct { + opus_int32 prev_gain_Q16; + opus_int32 exc_Q14[ MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14_buf[ MAX_LPC_ORDER ]; + opus_int16 outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ]; /* Buffer for output signal */ + opus_int lagPrev; /* Previous Lag */ + opus_int8 LastGainIndex; /* Previous gain index */ + opus_int fs_kHz; /* Sampling frequency in kHz */ + opus_int32 fs_API_hz; /* API sample frequency (Hz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int LPC_order; /* LPC order */ + opus_int16 prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + + /* For buffering payload in case of more frames per packet */ + opus_int nFramesDecoded; + opus_int nFramesPerPacket; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + opus_int VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + silk_resampler_state_struct resampler_state; + + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + + /* Quantization indices */ + SideInfoIndices indices; + + /* CNG state */ + silk_CNG_struct sCNG; + + /* Stuff used for PLC */ + opus_int lossCnt; + opus_int prevSignalType; + int arch; + + silk_PLC_struct sPLC; + +} silk_decoder_state; + +/************************/ +/* Decoder control */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int pitchL[ MAX_NB_SUBFR ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + /* Holds interpolated and final coefficients, 4-byte aligned */ + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; +} silk_decoder_control; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/sum_sqr_shift.c b/native/codec/libraries/opus/silk/sum_sqr_shift.c new file mode 100644 index 0000000..4fd0c3d --- /dev/null +++ b/native/codec/libraries/opus/silk/sum_sqr_shift.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +) +{ + opus_int i, shft; + opus_uint32 nrg_tmp; + opus_int32 nrg; + + /* Do a first run with the maximum shift we could have. */ + shft = 31-silk_CLZ32(len); + /* Let's be conservative with rounding and start with nrg=len. */ + nrg = len; + for( i = 0; i < len - 1; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + if( i < len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + silk_assert( nrg >= 0 ); + /* Make sure the result will fit in a 32-bit signed integer with two bits + of headroom. */ + shft = silk_max_32(0, shft+3 - silk_CLZ32(nrg)); + nrg = 0; + for( i = 0 ; i < len - 1; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + if( i < len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + + silk_assert( nrg >= 0 ); + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} + diff --git a/native/codec/libraries/opus/silk/table_LSF_cos.c b/native/codec/libraries/opus/silk/table_LSF_cos.c new file mode 100644 index 0000000..ec9dc63 --- /dev/null +++ b/native/codec/libraries/opus/silk/table_LSF_cos.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +/* Cosine approximation table for LSF conversion */ +/* Q12 values (even) */ +const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ] = { + 8192, 8190, 8182, 8170, + 8152, 8130, 8104, 8072, + 8034, 7994, 7946, 7896, + 7840, 7778, 7714, 7644, + 7568, 7490, 7406, 7318, + 7226, 7128, 7026, 6922, + 6812, 6698, 6580, 6458, + 6332, 6204, 6070, 5934, + 5792, 5648, 5502, 5352, + 5198, 5040, 4880, 4718, + 4552, 4382, 4212, 4038, + 3862, 3684, 3502, 3320, + 3136, 2948, 2760, 2570, + 2378, 2186, 1990, 1794, + 1598, 1400, 1202, 1002, + 802, 602, 402, 202, + 0, -202, -402, -602, + -802, -1002, -1202, -1400, + -1598, -1794, -1990, -2186, + -2378, -2570, -2760, -2948, + -3136, -3320, -3502, -3684, + -3862, -4038, -4212, -4382, + -4552, -4718, -4880, -5040, + -5198, -5352, -5502, -5648, + -5792, -5934, -6070, -6204, + -6332, -6458, -6580, -6698, + -6812, -6922, -7026, -7128, + -7226, -7318, -7406, -7490, + -7568, -7644, -7714, -7778, + -7840, -7896, -7946, -7994, + -8034, -8072, -8104, -8130, + -8152, -8170, -8182, -8190, + -8192 +}; diff --git a/native/codec/libraries/opus/silk/tables.h b/native/codec/libraries/opus/silk/tables.h new file mode 100644 index 0000000..95230c4 --- /dev/null +++ b/native/codec/libraries/opus/silk/tables.h @@ -0,0 +1,114 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TABLES_H +#define SILK_TABLES_H + +#include "define.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Entropy coding tables (with size in bytes indicated) */ +extern const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ]; /* 24 */ +extern const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ]; /* 41 */ + +extern const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */ +extern const opus_uint8 silk_pitch_delta_iCDF[ 21 ]; /* 21 */ +extern const opus_uint8 silk_pitch_contour_iCDF[ 34 ]; /* 34 */ +extern const opus_uint8 silk_pitch_contour_NB_iCDF[ 11 ]; /* 11 */ +extern const opus_uint8 silk_pitch_contour_10_ms_iCDF[ 12 ]; /* 12 */ +extern const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[ 3 ]; /* 3 */ + +extern const opus_uint8 silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ SILK_MAX_PULSES + 2 ]; /* 180 */ +extern const opus_uint8 silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ SILK_MAX_PULSES + 2 ]; /* 162 */ + +extern const opus_uint8 silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ +extern const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ + +extern const opus_uint8 silk_max_pulses_table[ 4 ]; /* 4 */ + +extern const opus_uint8 silk_shell_code_table0[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table1[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table2[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table3[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table_offsets[ SILK_MAX_PULSES + 1 ]; /* 17 */ + +extern const opus_uint8 silk_lsb_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 silk_sign_iCDF[ 42 ]; /* 42 */ + +extern const opus_uint8 silk_uniform3_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 silk_uniform4_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_uniform5_iCDF[ 5 ]; /* 5 */ +extern const opus_uint8 silk_uniform6_iCDF[ 6 ]; /* 6 */ +extern const opus_uint8 silk_uniform8_iCDF[ 8 ]; /* 8 */ + +extern const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ]; /* 7 */ + +extern const opus_uint8 silk_LTP_per_index_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_int8 * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ]; /* 168 */ +extern const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS]; +extern const opus_int8 silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */ + +extern const opus_uint8 silk_LTPscale_iCDF[ 3 ]; /* 4 */ +extern const opus_int16 silk_LTPScales_table_Q14[ 3 ]; /* 6 */ + +extern const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ]; /* 2 */ + +extern const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ]; /* 32 */ +extern const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ]; /* 25 */ +extern const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ]; /* 10 */ + +extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; /* 5 */ + +extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */ +extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */ + +/* Quantization offsets */ +extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +extern const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; /* 60 */ +extern const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; /* 60 */ + +/* Rom table with cosine values */ +extern const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; /* 258 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/opus/silk/tables_LTP.c b/native/codec/libraries/opus/silk/tables_LTP.c new file mode 100644 index 0000000..5e12c86 --- /dev/null +++ b/native/codec/libraries/opus/silk/tables_LTP.c @@ -0,0 +1,294 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_LTP_per_index_iCDF[3] = { + 179, 99, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_0[8] = { + 71, 56, 43, 30, 21, 12, 6, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_1[16] = { + 199, 165, 144, 124, 109, 96, 84, 71, + 61, 51, 42, 32, 23, 15, 8, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_2[32] = { + 241, 225, 211, 199, 187, 175, 164, 153, + 142, 132, 123, 114, 105, 96, 88, 80, + 72, 64, 57, 50, 44, 38, 33, 29, + 24, 20, 16, 12, 9, 5, 2, 0 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = { + 15, 131, 138, 138, 155, 155, 173, 173 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = { + 69, 93, 115, 118, 131, 138, 141, 138, + 150, 150, 155, 150, 155, 160, 166, 160 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = { + 131, 128, 134, 141, 141, 141, 145, 145, + 145, 150, 155, 155, 155, 155, 160, 160, + 160, 160, 166, 166, 173, 173, 182, 192, + 182, 192, 192, 192, 205, 192, 205, 224 +}; + +const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_iCDF_0, + silk_LTP_gain_iCDF_1, + silk_LTP_gain_iCDF_2 +}; + +const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_BITS_Q5_0, + silk_LTP_gain_BITS_Q5_1, + silk_LTP_gain_BITS_Q5_2 +}; + +static const opus_int8 silk_LTP_gain_vq_0[8][5] = +{ +{ + 4, 6, 24, 7, 5 +}, +{ + 0, 0, 2, 0, 0 +}, +{ + 12, 28, 41, 13, -4 +}, +{ + -9, 15, 42, 25, 14 +}, +{ + 1, -2, 62, 41, -9 +}, +{ + -10, 37, 65, -4, 3 +}, +{ + -6, 4, 66, 7, -8 +}, +{ + 16, 14, 38, -3, 33 +} +}; + +static const opus_int8 silk_LTP_gain_vq_1[16][5] = +{ +{ + 13, 22, 39, 23, 12 +}, +{ + -1, 36, 64, 27, -6 +}, +{ + -7, 10, 55, 43, 17 +}, +{ + 1, 1, 8, 1, 1 +}, +{ + 6, -11, 74, 53, -9 +}, +{ + -12, 55, 76, -12, 8 +}, +{ + -3, 3, 93, 27, -4 +}, +{ + 26, 39, 59, 3, -8 +}, +{ + 2, 0, 77, 11, 9 +}, +{ + -8, 22, 44, -6, 7 +}, +{ + 40, 9, 26, 3, 9 +}, +{ + -7, 20, 101, -7, 4 +}, +{ + 3, -8, 42, 26, 0 +}, +{ + -15, 33, 68, 2, 23 +}, +{ + -2, 55, 46, -2, 15 +}, +{ + 3, -1, 21, 16, 41 +} +}; + +static const opus_int8 silk_LTP_gain_vq_2[32][5] = +{ +{ + -6, 27, 61, 39, 5 +}, +{ + -11, 42, 88, 4, 1 +}, +{ + -2, 60, 65, 6, -4 +}, +{ + -1, -5, 73, 56, 1 +}, +{ + -9, 19, 94, 29, -9 +}, +{ + 0, 12, 99, 6, 4 +}, +{ + 8, -19, 102, 46, -13 +}, +{ + 3, 2, 13, 3, 2 +}, +{ + 9, -21, 84, 72, -18 +}, +{ + -11, 46, 104, -22, 8 +}, +{ + 18, 38, 48, 23, 0 +}, +{ + -16, 70, 83, -21, 11 +}, +{ + 5, -11, 117, 22, -8 +}, +{ + -6, 23, 117, -12, 3 +}, +{ + 3, -8, 95, 28, 4 +}, +{ + -10, 15, 77, 60, -15 +}, +{ + -1, 4, 124, 2, -4 +}, +{ + 3, 38, 84, 24, -25 +}, +{ + 2, 13, 42, 13, 31 +}, +{ + 21, -4, 56, 46, -1 +}, +{ + -1, 35, 79, -13, 19 +}, +{ + -7, 65, 88, -9, -14 +}, +{ + 20, 4, 81, 49, -29 +}, +{ + 20, 0, 75, 3, -17 +}, +{ + 5, -9, 44, 92, -8 +}, +{ + 1, -3, 22, 69, 31 +}, +{ + -6, 95, 41, -12, 5 +}, +{ + 39, 67, 16, -4, 1 +}, +{ + 0, -6, 120, 55, -36 +}, +{ + -13, 44, 122, 4, -24 +}, +{ + 81, 5, 11, 3, 7 +}, +{ + 2, 0, 9, 10, 88 +} +}; + +const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = { + (opus_int8 *)&silk_LTP_gain_vq_0[0][0], + (opus_int8 *)&silk_LTP_gain_vq_1[0][0], + (opus_int8 *)&silk_LTP_gain_vq_2[0][0] +}; + +/* Maximum frequency-dependent response of the pitch taps above, + computed as max(abs(freqz(taps))) */ +static const opus_uint8 silk_LTP_gain_vq_0_gain[8] = { + 46, 2, 90, 87, 93, 91, 82, 98 +}; + +static const opus_uint8 silk_LTP_gain_vq_1_gain[16] = { + 109, 120, 118, 12, 113, 115, 117, 119, + 99, 59, 87, 111, 63, 111, 112, 80 +}; + +static const opus_uint8 silk_LTP_gain_vq_2_gain[32] = { + 126, 124, 125, 124, 129, 121, 126, 23, + 132, 127, 127, 127, 126, 127, 122, 133, + 130, 134, 101, 118, 119, 145, 126, 86, + 124, 120, 123, 119, 170, 173, 107, 109 +}; + +const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS] = { + &silk_LTP_gain_vq_0_gain[0], + &silk_LTP_gain_vq_1_gain[0], + &silk_LTP_gain_vq_2_gain[0] +}; + +const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = { + 8, 16, 32 +}; diff --git a/native/codec/libraries/opus/silk/tables_NLSF_CB_NB_MB.c b/native/codec/libraries/opus/silk/tables_NLSF_CB_NB_MB.c new file mode 100644 index 0000000..195d5b9 --- /dev/null +++ b/native/codec/libraries/opus/silk/tables_NLSF_CB_NB_MB.c @@ -0,0 +1,195 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = { + 12, 35, 60, 83, 108, 132, 157, 180, + 206, 228, 15, 32, 55, 77, 101, 125, + 151, 175, 201, 225, 19, 42, 66, 89, + 114, 137, 162, 184, 209, 230, 12, 25, + 50, 72, 97, 120, 147, 172, 200, 223, + 26, 44, 69, 90, 114, 135, 159, 180, + 205, 225, 13, 22, 53, 80, 106, 130, + 156, 180, 205, 228, 15, 25, 44, 64, + 90, 115, 142, 168, 196, 222, 19, 24, + 62, 82, 100, 120, 145, 168, 190, 214, + 22, 31, 50, 79, 103, 120, 151, 170, + 203, 227, 21, 29, 45, 65, 106, 124, + 150, 171, 196, 224, 30, 49, 75, 97, + 121, 142, 165, 186, 209, 229, 19, 25, + 52, 70, 93, 116, 143, 166, 192, 219, + 26, 34, 62, 75, 97, 118, 145, 167, + 194, 217, 25, 33, 56, 70, 91, 113, + 143, 165, 196, 223, 21, 34, 51, 72, + 97, 117, 145, 171, 196, 222, 20, 29, + 50, 67, 90, 117, 144, 168, 197, 221, + 22, 31, 48, 66, 95, 117, 146, 168, + 196, 222, 24, 33, 51, 77, 116, 134, + 158, 180, 200, 224, 21, 28, 70, 87, + 106, 124, 149, 170, 194, 217, 26, 33, + 53, 64, 83, 117, 152, 173, 204, 225, + 27, 34, 65, 95, 108, 129, 155, 174, + 210, 225, 20, 26, 72, 99, 113, 131, + 154, 176, 200, 219, 34, 43, 61, 78, + 93, 114, 155, 177, 205, 229, 23, 29, + 54, 97, 124, 138, 163, 179, 209, 229, + 30, 38, 56, 89, 118, 129, 158, 178, + 200, 231, 21, 29, 49, 63, 85, 111, + 142, 163, 193, 222, 27, 48, 77, 103, + 133, 158, 179, 196, 215, 232, 29, 47, + 74, 99, 124, 151, 176, 198, 220, 237, + 33, 42, 61, 76, 93, 121, 155, 174, + 207, 225, 29, 53, 87, 112, 136, 154, + 170, 188, 208, 227, 24, 30, 52, 84, + 131, 150, 166, 186, 203, 229, 37, 48, + 64, 84, 104, 118, 156, 177, 201, 230 +}; + +static const opus_int16 silk_NLSF_CB1_Wght_Q9[ 320 ] = { + 2897, 2314, 2314, 2314, 2287, 2287, 2314, 2300, 2327, 2287, + 2888, 2580, 2394, 2367, 2314, 2274, 2274, 2274, 2274, 2194, + 2487, 2340, 2340, 2314, 2314, 2314, 2340, 2340, 2367, 2354, + 3216, 2766, 2340, 2340, 2314, 2274, 2221, 2207, 2261, 2194, + 2460, 2474, 2367, 2394, 2394, 2394, 2394, 2367, 2407, 2314, + 3479, 3056, 2127, 2207, 2274, 2274, 2274, 2287, 2314, 2261, + 3282, 3141, 2580, 2394, 2247, 2221, 2207, 2194, 2194, 2114, + 4096, 3845, 2221, 2620, 2620, 2407, 2314, 2394, 2367, 2074, + 3178, 3244, 2367, 2221, 2553, 2434, 2340, 2314, 2167, 2221, + 3338, 3488, 2726, 2194, 2261, 2460, 2354, 2367, 2207, 2101, + 2354, 2420, 2327, 2367, 2394, 2420, 2420, 2420, 2460, 2367, + 3779, 3629, 2434, 2527, 2367, 2274, 2274, 2300, 2207, 2048, + 3254, 3225, 2713, 2846, 2447, 2327, 2300, 2300, 2274, 2127, + 3263, 3300, 2753, 2806, 2447, 2261, 2261, 2247, 2127, 2101, + 2873, 2981, 2633, 2367, 2407, 2354, 2194, 2247, 2247, 2114, + 3225, 3197, 2633, 2580, 2274, 2181, 2247, 2221, 2221, 2141, + 3178, 3310, 2740, 2407, 2274, 2274, 2274, 2287, 2194, 2114, + 3141, 3272, 2460, 2061, 2287, 2500, 2367, 2487, 2434, 2181, + 3507, 3282, 2314, 2700, 2647, 2474, 2367, 2394, 2340, 2127, + 3423, 3535, 3038, 3056, 2300, 1950, 2221, 2274, 2274, 2274, + 3404, 3366, 2087, 2687, 2873, 2354, 2420, 2274, 2474, 2540, + 3760, 3488, 1950, 2660, 2897, 2527, 2394, 2367, 2460, 2261, + 3028, 3272, 2740, 2888, 2740, 2154, 2127, 2287, 2234, 2247, + 3695, 3657, 2025, 1969, 2660, 2700, 2580, 2500, 2327, 2367, + 3207, 3413, 2354, 2074, 2888, 2888, 2340, 2487, 2247, 2167, + 3338, 3366, 2846, 2780, 2327, 2154, 2274, 2287, 2114, 2061, + 2327, 2300, 2181, 2167, 2181, 2367, 2633, 2700, 2700, 2553, + 2407, 2434, 2221, 2261, 2221, 2221, 2340, 2420, 2607, 2700, + 3038, 3244, 2806, 2888, 2474, 2074, 2300, 2314, 2354, 2380, + 2221, 2154, 2127, 2287, 2500, 2793, 2793, 2620, 2580, 2367, + 3676, 3713, 2234, 1838, 2181, 2753, 2726, 2673, 2513, 2207, + 2793, 3160, 2726, 2553, 2846, 2513, 2181, 2394, 2221, 2181 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = { + 212, 178, 148, 129, 108, 96, 85, 82, + 79, 77, 61, 59, 57, 56, 51, 49, + 48, 45, 42, 41, 40, 38, 36, 34, + 31, 30, 21, 12, 10, 3, 1, 0, + 255, 245, 244, 236, 233, 225, 217, 203, + 190, 176, 175, 161, 149, 136, 125, 114, + 102, 91, 81, 71, 60, 52, 43, 35, + 28, 20, 19, 18, 12, 11, 5, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = { + 16, 0, 0, 0, 0, 99, 66, 36, + 36, 34, 36, 34, 34, 34, 34, 83, + 69, 36, 52, 34, 116, 102, 70, 68, + 68, 176, 102, 68, 68, 34, 65, 85, + 68, 84, 36, 116, 141, 152, 139, 170, + 132, 187, 184, 216, 137, 132, 249, 168, + 185, 139, 104, 102, 100, 68, 68, 178, + 218, 185, 185, 170, 244, 216, 187, 187, + 170, 244, 187, 187, 219, 138, 103, 155, + 184, 185, 137, 116, 183, 155, 152, 136, + 132, 217, 184, 184, 170, 164, 217, 171, + 155, 139, 244, 169, 184, 185, 170, 164, + 216, 223, 218, 138, 214, 143, 188, 218, + 168, 244, 141, 136, 155, 170, 168, 138, + 220, 219, 139, 164, 219, 202, 216, 137, + 168, 186, 246, 185, 139, 116, 185, 219, + 185, 138, 100, 100, 134, 100, 102, 34, + 68, 68, 100, 68, 168, 203, 221, 218, + 168, 167, 154, 136, 104, 70, 164, 246, + 171, 137, 139, 137, 155, 218, 219, 139 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = { + 255, 254, 253, 238, 14, 3, 2, 1, + 0, 255, 254, 252, 218, 35, 3, 2, + 1, 0, 255, 254, 250, 208, 59, 4, + 2, 1, 0, 255, 254, 246, 194, 71, + 10, 2, 1, 0, 255, 252, 236, 183, + 82, 8, 2, 1, 0, 255, 252, 235, + 180, 90, 17, 2, 1, 0, 255, 248, + 224, 171, 97, 30, 4, 1, 0, 255, + 254, 236, 173, 95, 37, 7, 1, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = { + 255, 255, 255, 131, 6, 145, 255, 255, + 255, 255, 255, 236, 93, 15, 96, 255, + 255, 255, 255, 255, 194, 83, 25, 71, + 221, 255, 255, 255, 255, 162, 73, 34, + 66, 162, 255, 255, 255, 210, 126, 73, + 43, 57, 173, 255, 255, 255, 201, 125, + 71, 48, 58, 130, 255, 255, 255, 166, + 110, 73, 57, 62, 104, 210, 255, 255, + 251, 123, 65, 55, 68, 100, 171, 255 +}; + +static const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = { + 179, 138, 140, 148, 151, 149, 153, 151, + 163, 116, 67, 82, 59, 92, 72, 100, + 89, 92 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = { + 250, 3, 6, 3, 3, 3, 4, 3, + 3, 3, 461 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB = +{ + 32, + 10, + SILK_FIX_CONST( 0.18, 16 ), + SILK_FIX_CONST( 1.0 / 0.18, 6 ), + silk_NLSF_CB1_NB_MB_Q8, + silk_NLSF_CB1_Wght_Q9, + silk_NLSF_CB1_iCDF_NB_MB, + silk_NLSF_PRED_NB_MB_Q8, + silk_NLSF_CB2_SELECT_NB_MB, + silk_NLSF_CB2_iCDF_NB_MB, + silk_NLSF_CB2_BITS_NB_MB_Q5, + silk_NLSF_DELTA_MIN_NB_MB_Q15, +}; diff --git a/native/codec/libraries/opus/silk/tables_NLSF_CB_WB.c b/native/codec/libraries/opus/silk/tables_NLSF_CB_WB.c new file mode 100644 index 0000000..5cc9f57 --- /dev/null +++ b/native/codec/libraries/opus/silk/tables_NLSF_CB_WB.c @@ -0,0 +1,234 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = { + 7, 23, 38, 54, 69, 85, 100, 116, + 131, 147, 162, 178, 193, 208, 223, 239, + 13, 25, 41, 55, 69, 83, 98, 112, + 127, 142, 157, 171, 187, 203, 220, 236, + 15, 21, 34, 51, 61, 78, 92, 106, + 126, 136, 152, 167, 185, 205, 225, 240, + 10, 21, 36, 50, 63, 79, 95, 110, + 126, 141, 157, 173, 189, 205, 221, 237, + 17, 20, 37, 51, 59, 78, 89, 107, + 123, 134, 150, 164, 184, 205, 224, 240, + 10, 15, 32, 51, 67, 81, 96, 112, + 129, 142, 158, 173, 189, 204, 220, 236, + 8, 21, 37, 51, 65, 79, 98, 113, + 126, 138, 155, 168, 179, 192, 209, 218, + 12, 15, 34, 55, 63, 78, 87, 108, + 118, 131, 148, 167, 185, 203, 219, 236, + 16, 19, 32, 36, 56, 79, 91, 108, + 118, 136, 154, 171, 186, 204, 220, 237, + 11, 28, 43, 58, 74, 89, 105, 120, + 135, 150, 165, 180, 196, 211, 226, 241, + 6, 16, 33, 46, 60, 75, 92, 107, + 123, 137, 156, 169, 185, 199, 214, 225, + 11, 19, 30, 44, 57, 74, 89, 105, + 121, 135, 152, 169, 186, 202, 218, 234, + 12, 19, 29, 46, 57, 71, 88, 100, + 120, 132, 148, 165, 182, 199, 216, 233, + 17, 23, 35, 46, 56, 77, 92, 106, + 123, 134, 152, 167, 185, 204, 222, 237, + 14, 17, 45, 53, 63, 75, 89, 107, + 115, 132, 151, 171, 188, 206, 221, 240, + 9, 16, 29, 40, 56, 71, 88, 103, + 119, 137, 154, 171, 189, 205, 222, 237, + 16, 19, 36, 48, 57, 76, 87, 105, + 118, 132, 150, 167, 185, 202, 218, 236, + 12, 17, 29, 54, 71, 81, 94, 104, + 126, 136, 149, 164, 182, 201, 221, 237, + 15, 28, 47, 62, 79, 97, 115, 129, + 142, 155, 168, 180, 194, 208, 223, 238, + 8, 14, 30, 45, 62, 78, 94, 111, + 127, 143, 159, 175, 192, 207, 223, 239, + 17, 30, 49, 62, 79, 92, 107, 119, + 132, 145, 160, 174, 190, 204, 220, 235, + 14, 19, 36, 45, 61, 76, 91, 108, + 121, 138, 154, 172, 189, 205, 222, 238, + 12, 18, 31, 45, 60, 76, 91, 107, + 123, 138, 154, 171, 187, 204, 221, 236, + 13, 17, 31, 43, 53, 70, 83, 103, + 114, 131, 149, 167, 185, 203, 220, 237, + 17, 22, 35, 42, 58, 78, 93, 110, + 125, 139, 155, 170, 188, 206, 224, 240, + 8, 15, 34, 50, 67, 83, 99, 115, + 131, 146, 162, 178, 193, 209, 224, 239, + 13, 16, 41, 66, 73, 86, 95, 111, + 128, 137, 150, 163, 183, 206, 225, 241, + 17, 25, 37, 52, 63, 75, 92, 102, + 119, 132, 144, 160, 175, 191, 212, 231, + 19, 31, 49, 65, 83, 100, 117, 133, + 147, 161, 174, 187, 200, 213, 227, 242, + 18, 31, 52, 68, 88, 103, 117, 126, + 138, 149, 163, 177, 192, 207, 223, 239, + 16, 29, 47, 61, 76, 90, 106, 119, + 133, 147, 161, 176, 193, 209, 224, 240, + 15, 21, 35, 50, 61, 73, 86, 97, + 110, 119, 129, 141, 175, 198, 218, 237 +}; + +static const opus_int16 silk_NLSF_CB1_WB_Wght_Q9[ 512 ] = { + 3657, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2963, 2963, 2925, 2846, + 3216, 3085, 2972, 3056, 3056, 3010, 3010, 3010, 2963, 2963, 3010, 2972, 2888, 2846, 2846, 2726, + 3920, 4014, 2981, 3207, 3207, 2934, 3056, 2846, 3122, 3244, 2925, 2846, 2620, 2553, 2780, 2925, + 3516, 3197, 3010, 3103, 3019, 2888, 2925, 2925, 2925, 2925, 2888, 2888, 2888, 2888, 2888, 2753, + 5054, 5054, 2934, 3573, 3385, 3056, 3085, 2793, 3160, 3160, 2972, 2846, 2513, 2540, 2753, 2888, + 4428, 4149, 2700, 2753, 2972, 3010, 2925, 2846, 2981, 3019, 2925, 2925, 2925, 2925, 2888, 2726, + 3620, 3019, 2972, 3056, 3056, 2873, 2806, 3056, 3216, 3047, 2981, 3291, 3291, 2981, 3310, 2991, + 5227, 5014, 2540, 3338, 3526, 3385, 3197, 3094, 3376, 2981, 2700, 2647, 2687, 2793, 2846, 2673, + 5081, 5174, 4615, 4428, 2460, 2897, 3047, 3207, 3169, 2687, 2740, 2888, 2846, 2793, 2846, 2700, + 3122, 2888, 2963, 2925, 2925, 2925, 2925, 2963, 2963, 2963, 2963, 2925, 2925, 2963, 2963, 2963, + 4202, 3207, 2981, 3103, 3010, 2888, 2888, 2925, 2972, 2873, 2916, 3019, 2972, 3010, 3197, 2873, + 3760, 3760, 3244, 3103, 2981, 2888, 2925, 2888, 2972, 2934, 2793, 2793, 2846, 2888, 2888, 2660, + 3854, 4014, 3207, 3122, 3244, 2934, 3047, 2963, 2963, 3085, 2846, 2793, 2793, 2793, 2793, 2580, + 3845, 4080, 3357, 3516, 3094, 2740, 3010, 2934, 3122, 3085, 2846, 2846, 2647, 2647, 2846, 2806, + 5147, 4894, 3225, 3845, 3441, 3169, 2897, 3413, 3451, 2700, 2580, 2673, 2740, 2846, 2806, 2753, + 4109, 3789, 3291, 3160, 2925, 2888, 2888, 2925, 2793, 2740, 2793, 2740, 2793, 2846, 2888, 2806, + 5081, 5054, 3047, 3545, 3244, 3056, 3085, 2944, 3103, 2897, 2740, 2740, 2740, 2846, 2793, 2620, + 4309, 4309, 2860, 2527, 3207, 3376, 3376, 3075, 3075, 3376, 3056, 2846, 2647, 2580, 2726, 2753, + 3056, 2916, 2806, 2888, 2740, 2687, 2897, 3103, 3150, 3150, 3216, 3169, 3056, 3010, 2963, 2846, + 4375, 3882, 2925, 2888, 2846, 2888, 2846, 2846, 2888, 2888, 2888, 2846, 2888, 2925, 2888, 2846, + 2981, 2916, 2916, 2981, 2981, 3056, 3122, 3216, 3150, 3056, 3010, 2972, 2972, 2972, 2925, 2740, + 4229, 4149, 3310, 3347, 2925, 2963, 2888, 2981, 2981, 2846, 2793, 2740, 2846, 2846, 2846, 2793, + 4080, 4014, 3103, 3010, 2925, 2925, 2925, 2888, 2925, 2925, 2846, 2846, 2846, 2793, 2888, 2780, + 4615, 4575, 3169, 3441, 3207, 2981, 2897, 3038, 3122, 2740, 2687, 2687, 2687, 2740, 2793, 2700, + 4149, 4269, 3789, 3657, 2726, 2780, 2888, 2888, 3010, 2972, 2925, 2846, 2687, 2687, 2793, 2888, + 4215, 3554, 2753, 2846, 2846, 2888, 2888, 2888, 2925, 2925, 2888, 2925, 2925, 2925, 2963, 2888, + 5174, 4921, 2261, 3432, 3789, 3479, 3347, 2846, 3310, 3479, 3150, 2897, 2460, 2487, 2753, 2925, + 3451, 3685, 3122, 3197, 3357, 3047, 3207, 3207, 2981, 3216, 3085, 2925, 2925, 2687, 2540, 2434, + 2981, 3010, 2793, 2793, 2740, 2793, 2846, 2972, 3056, 3103, 3150, 3150, 3150, 3103, 3010, 3010, + 2944, 2873, 2687, 2726, 2780, 3010, 3432, 3545, 3357, 3244, 3056, 3010, 2963, 2925, 2888, 2846, + 3019, 2944, 2897, 3010, 3010, 2972, 3019, 3103, 3056, 3056, 3010, 2888, 2846, 2925, 2925, 2888, + 3920, 3967, 3010, 3197, 3357, 3216, 3291, 3291, 3479, 3704, 3441, 2726, 2181, 2460, 2580, 2607 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = { + 225, 204, 201, 184, 183, 175, 158, 154, + 153, 135, 119, 115, 113, 110, 109, 99, + 98, 95, 79, 68, 52, 50, 48, 45, + 43, 32, 31, 27, 18, 10, 3, 0, + 255, 251, 235, 230, 212, 201, 196, 182, + 167, 166, 163, 151, 138, 124, 110, 104, + 90, 78, 76, 70, 69, 57, 45, 34, + 24, 21, 11, 6, 5, 4, 3, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 100, 102, 102, 68, 68, 36, 34, 96, + 164, 107, 158, 185, 180, 185, 139, 102, + 64, 66, 36, 34, 34, 0, 1, 32, + 208, 139, 141, 191, 152, 185, 155, 104, + 96, 171, 104, 166, 102, 102, 102, 132, + 1, 0, 0, 0, 0, 16, 16, 0, + 80, 109, 78, 107, 185, 139, 103, 101, + 208, 212, 141, 139, 173, 153, 123, 103, + 36, 0, 0, 0, 0, 0, 0, 1, + 48, 0, 0, 0, 0, 0, 0, 32, + 68, 135, 123, 119, 119, 103, 69, 98, + 68, 103, 120, 118, 118, 102, 71, 98, + 134, 136, 157, 184, 182, 153, 139, 134, + 208, 168, 248, 75, 189, 143, 121, 107, + 32, 49, 34, 34, 34, 0, 17, 2, + 210, 235, 139, 123, 185, 137, 105, 134, + 98, 135, 104, 182, 100, 183, 171, 134, + 100, 70, 68, 70, 66, 66, 34, 131, + 64, 166, 102, 68, 36, 2, 1, 0, + 134, 166, 102, 68, 34, 34, 66, 132, + 212, 246, 158, 139, 107, 107, 87, 102, + 100, 219, 125, 122, 137, 118, 103, 132, + 114, 135, 137, 105, 171, 106, 50, 34, + 164, 214, 141, 143, 185, 151, 121, 103, + 192, 34, 0, 0, 0, 0, 0, 1, + 208, 109, 74, 187, 134, 249, 159, 137, + 102, 110, 154, 118, 87, 101, 119, 101, + 0, 2, 0, 36, 36, 66, 68, 35, + 96, 164, 102, 100, 36, 0, 2, 33, + 167, 138, 174, 102, 100, 84, 2, 2, + 100, 107, 120, 119, 36, 197, 24, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = { + 255, 254, 253, 244, 12, 3, 2, 1, + 0, 255, 254, 252, 224, 38, 3, 2, + 1, 0, 255, 254, 251, 209, 57, 4, + 2, 1, 0, 255, 254, 244, 195, 69, + 4, 2, 1, 0, 255, 251, 232, 184, + 84, 7, 2, 1, 0, 255, 254, 240, + 186, 86, 14, 2, 1, 0, 255, 254, + 239, 178, 91, 30, 5, 1, 0, 255, + 248, 227, 177, 100, 19, 2, 1, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = { + 255, 255, 255, 156, 4, 154, 255, 255, + 255, 255, 255, 227, 102, 15, 92, 255, + 255, 255, 255, 255, 213, 83, 24, 72, + 236, 255, 255, 255, 255, 150, 76, 33, + 63, 214, 255, 255, 255, 190, 121, 77, + 43, 55, 185, 255, 255, 255, 245, 137, + 71, 43, 59, 139, 255, 255, 255, 255, + 131, 66, 50, 66, 107, 194, 255, 255, + 166, 116, 76, 55, 53, 125, 255, 255 +}; + +static const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = { + 175, 148, 160, 176, 178, 173, 174, 164, + 177, 174, 196, 182, 198, 192, 182, 68, + 62, 66, 60, 72, 117, 85, 90, 118, + 136, 151, 142, 160, 142, 155 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = { + 100, 3, 40, 3, 3, 3, 5, 14, + 14, 10, 11, 3, 8, 9, 7, 3, + 347 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_WB = +{ + 32, + 16, + SILK_FIX_CONST( 0.15, 16 ), + SILK_FIX_CONST( 1.0 / 0.15, 6 ), + silk_NLSF_CB1_WB_Q8, + silk_NLSF_CB1_WB_Wght_Q9, + silk_NLSF_CB1_iCDF_WB, + silk_NLSF_PRED_WB_Q8, + silk_NLSF_CB2_SELECT_WB, + silk_NLSF_CB2_iCDF_WB, + silk_NLSF_CB2_BITS_WB_Q5, + silk_NLSF_DELTA_MIN_WB_Q15, +}; + diff --git a/native/codec/libraries/opus/silk/tables_gain.c b/native/codec/libraries/opus/silk/tables_gain.c new file mode 100644 index 0000000..37e41d8 --- /dev/null +++ b/native/codec/libraries/opus/silk/tables_gain.c @@ -0,0 +1,63 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] = +{ +{ + 224, 112, 44, 15, 3, 2, 1, 0 +}, +{ + 254, 237, 192, 132, 70, 23, 4, 0 +}, +{ + 255, 252, 226, 155, 61, 11, 2, 0 +} +}; + +const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = { + 250, 245, 234, 203, 71, 50, 42, 38, + 35, 33, 31, 29, 28, 27, 26, 25, + 24, 23, 22, 21, 20, 19, 18, 17, + 16, 15, 14, 13, 12, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1, + 0 +}; + +#ifdef __cplusplus +} +#endif diff --git a/native/codec/libraries/opus/silk/tables_other.c b/native/codec/libraries/opus/silk/tables_other.c new file mode 100644 index 0000000..e34d907 --- /dev/null +++ b/native/codec/libraries/opus/silk/tables_other.c @@ -0,0 +1,124 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "structs.h" +#include "define.h" +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Tables for stereo predictor coding */ +const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = { + -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, + 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732 +}; +const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ] = { + 249, 247, 246, 245, 244, + 234, 210, 202, 201, 200, + 197, 174, 82, 59, 56, + 55, 54, 46, 22, 12, + 11, 10, 9, 7, 0 +}; +const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 }; + +/* Tables for LBRR flags */ +static const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 }; +static const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 }; +const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = { + silk_LBRR_flags_2_iCDF, + silk_LBRR_flags_3_iCDF +}; + +/* Table for LSB coding */ +const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 }; + +/* Tables for LTPScale */ +const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 }; + +/* Tables for signal type and offset coding */ +const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = { + 232, 158, 10, 0 +}; +const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = { + 230, 0 +}; + +/* Tables for NLSF interpolation factor */ +const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 }; + +/* Quantization offsets */ +const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = { + { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 } +}; + +/* Table for LTPScale */ +const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 }; + +/* Uniform entropy tables */ +const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 }; +const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 }; +const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 }; +const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 }; +const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 }; + +const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 }; + +/* Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] = +{ +{ 250767114, 501534038, 250767114 }, +{ 209867381, 419732057, 209867381 }, +{ 170987846, 341967853, 170987846 }, +{ 131531482, 263046905, 131531482 }, +{ 89306658, 178584282, 89306658 } +}; + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] = +{ +{ 506393414, 239854379 }, +{ 411067935, 169683996 }, +{ 306733530, 116694253 }, +{ 185807084, 77959395 }, +{ 35497197, 57401098 } +}; + +#ifdef __cplusplus +} +#endif + diff --git a/native/codec/libraries/opus/silk/tables_pitch_lag.c b/native/codec/libraries/opus/silk/tables_pitch_lag.c new file mode 100644 index 0000000..e80cc59 --- /dev/null +++ b/native/codec/libraries/opus/silk/tables_pitch_lag.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = { + 253, 250, 244, 233, 212, 182, 150, 131, + 120, 110, 98, 85, 72, 60, 49, 40, + 32, 25, 19, 15, 13, 11, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_pitch_delta_iCDF[21] = { + 210, 208, 206, 203, 199, 193, 183, 168, + 142, 104, 74, 52, 37, 27, 20, 14, + 10, 6, 4, 2, 0 +}; + +const opus_uint8 silk_pitch_contour_iCDF[34] = { + 223, 201, 183, 167, 152, 138, 124, 111, + 98, 88, 79, 70, 62, 56, 50, 44, + 39, 35, 31, 27, 24, 21, 18, 16, + 14, 12, 10, 8, 6, 4, 3, 2, + 1, 0 +}; + +const opus_uint8 silk_pitch_contour_NB_iCDF[11] = { + 188, 176, 155, 138, 119, 97, 67, 43, + 26, 10, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = { + 165, 119, 80, 61, 47, 35, 27, 20, + 14, 9, 4, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = { + 113, 63, 0 +}; + + diff --git a/native/codec/libraries/opus/silk/tables_pulses_per_block.c b/native/codec/libraries/opus/silk/tables_pulses_per_block.c new file mode 100644 index 0000000..c7c01c8 --- /dev/null +++ b/native/codec/libraries/opus/silk/tables_pulses_per_block.c @@ -0,0 +1,264 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_max_pulses_table[ 4 ] = { + 8, 10, 12, 16 +}; + +const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = { +{ + 125, 51, 26, 18, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 198, 105, 45, 22, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 213, 162, 116, 83, 59, 43, 32, 24, + 18, 15, 12, 9, 7, 6, 5, 3, + 2, 0 +}, +{ + 239, 187, 116, 59, 28, 16, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 250, 229, 188, 135, 86, 51, 30, 19, + 13, 10, 8, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 249, 235, 213, 185, 156, 128, 103, 83, + 66, 53, 42, 33, 26, 21, 17, 13, + 10, 0 +}, +{ + 254, 249, 235, 206, 164, 118, 77, 46, + 27, 16, 10, 7, 5, 4, 3, 2, + 1, 0 +}, +{ + 255, 253, 249, 239, 220, 191, 156, 119, + 85, 57, 37, 23, 15, 10, 6, 4, + 2, 0 +}, +{ + 255, 253, 251, 246, 237, 223, 203, 179, + 152, 124, 98, 75, 55, 40, 29, 21, + 15, 0 +}, +{ + 255, 254, 253, 247, 220, 162, 106, 67, + 42, 28, 18, 12, 9, 6, 4, 3, + 2, 0 +} +}; + +const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = { +{ + 31, 57, 107, 160, 205, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 69, 47, 67, 111, 166, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 82, 74, 79, 95, 109, 128, 145, 160, + 173, 205, 205, 205, 224, 255, 255, 224, + 255, 224 +}, +{ + 125, 74, 59, 69, 97, 141, 182, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 173, 115, 85, 73, 76, 92, 115, 145, + 173, 205, 224, 224, 255, 255, 255, 255, + 255, 255 +}, +{ + 166, 134, 113, 102, 101, 102, 107, 118, + 125, 138, 145, 155, 166, 182, 192, 192, + 205, 150 +}, +{ + 224, 182, 134, 101, 83, 79, 85, 97, + 120, 145, 173, 205, 224, 255, 255, 255, + 255, 255 +}, +{ + 255, 224, 192, 150, 120, 101, 92, 89, + 93, 102, 118, 134, 160, 182, 192, 224, + 224, 224 +}, +{ + 255, 224, 224, 182, 155, 134, 118, 109, + 104, 102, 106, 111, 118, 131, 145, 160, + 173, 131 +} +}; + +const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] = +{ +{ + 241, 190, 178, 132, 87, 74, 41, 14, + 0 +}, +{ + 223, 193, 157, 140, 106, 57, 39, 18, + 0 +} +}; + +const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] = +{ +{ + 131, 74, 141, 79, 80, 138, 95, 104, + 134 +}, +{ + 95, 99, 91, 125, 93, 76, 123, 115, + 123 +} +}; + +const opus_uint8 silk_shell_code_table0[ 152 ] = { + 128, 0, 214, 42, 0, 235, 128, 21, + 0, 244, 184, 72, 11, 0, 248, 214, + 128, 42, 7, 0, 248, 225, 170, 80, + 25, 5, 0, 251, 236, 198, 126, 54, + 18, 3, 0, 250, 238, 211, 159, 82, + 35, 15, 5, 0, 250, 231, 203, 168, + 128, 88, 53, 25, 6, 0, 252, 238, + 216, 185, 148, 108, 71, 40, 18, 4, + 0, 253, 243, 225, 199, 166, 128, 90, + 57, 31, 13, 3, 0, 254, 246, 233, + 212, 183, 147, 109, 73, 44, 23, 10, + 2, 0, 255, 250, 240, 223, 198, 166, + 128, 90, 58, 33, 16, 6, 1, 0, + 255, 251, 244, 231, 210, 181, 146, 110, + 75, 46, 25, 12, 5, 1, 0, 255, + 253, 248, 238, 221, 196, 164, 128, 92, + 60, 35, 18, 8, 3, 1, 0, 255, + 253, 249, 242, 229, 208, 180, 146, 110, + 76, 48, 27, 14, 7, 3, 1, 0 +}; + +const opus_uint8 silk_shell_code_table1[ 152 ] = { + 129, 0, 207, 50, 0, 236, 129, 20, + 0, 245, 185, 72, 10, 0, 249, 213, + 129, 42, 6, 0, 250, 226, 169, 87, + 27, 4, 0, 251, 233, 194, 130, 62, + 20, 4, 0, 250, 236, 207, 160, 99, + 47, 17, 3, 0, 255, 240, 217, 182, + 131, 81, 41, 11, 1, 0, 255, 254, + 233, 201, 159, 107, 61, 20, 2, 1, + 0, 255, 249, 233, 206, 170, 128, 86, + 50, 23, 7, 1, 0, 255, 250, 238, + 217, 186, 148, 108, 70, 39, 18, 6, + 1, 0, 255, 252, 243, 226, 200, 166, + 128, 90, 56, 30, 13, 4, 1, 0, + 255, 252, 245, 231, 209, 180, 146, 110, + 76, 47, 25, 11, 4, 1, 0, 255, + 253, 248, 237, 219, 194, 163, 128, 93, + 62, 37, 19, 8, 3, 1, 0, 255, + 254, 250, 241, 226, 205, 177, 145, 111, + 79, 51, 30, 15, 6, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table2[ 152 ] = { + 129, 0, 203, 54, 0, 234, 129, 23, + 0, 245, 184, 73, 10, 0, 250, 215, + 129, 41, 5, 0, 252, 232, 173, 86, + 24, 3, 0, 253, 240, 200, 129, 56, + 15, 2, 0, 253, 244, 217, 164, 94, + 38, 10, 1, 0, 253, 245, 226, 189, + 132, 71, 27, 7, 1, 0, 253, 246, + 231, 203, 159, 105, 56, 23, 6, 1, + 0, 255, 248, 235, 213, 179, 133, 85, + 47, 19, 5, 1, 0, 255, 254, 243, + 221, 194, 159, 117, 70, 37, 12, 2, + 1, 0, 255, 254, 248, 234, 208, 171, + 128, 85, 48, 22, 8, 2, 1, 0, + 255, 254, 250, 240, 220, 189, 149, 107, + 67, 36, 16, 6, 2, 1, 0, 255, + 254, 251, 243, 227, 201, 166, 128, 90, + 55, 29, 13, 5, 2, 1, 0, 255, + 254, 252, 246, 234, 213, 183, 147, 109, + 73, 43, 22, 10, 4, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table3[ 152 ] = { + 130, 0, 200, 58, 0, 231, 130, 26, + 0, 244, 184, 76, 12, 0, 249, 214, + 130, 43, 6, 0, 252, 232, 173, 87, + 24, 3, 0, 253, 241, 203, 131, 56, + 14, 2, 0, 254, 246, 221, 167, 94, + 35, 8, 1, 0, 254, 249, 232, 193, + 130, 65, 23, 5, 1, 0, 255, 251, + 239, 211, 162, 99, 45, 15, 4, 1, + 0, 255, 251, 243, 223, 186, 131, 74, + 33, 11, 3, 1, 0, 255, 252, 245, + 230, 202, 158, 105, 57, 24, 8, 2, + 1, 0, 255, 253, 247, 235, 214, 179, + 132, 84, 44, 19, 7, 2, 1, 0, + 255, 254, 250, 240, 223, 196, 159, 112, + 69, 36, 15, 6, 2, 1, 0, 255, + 254, 253, 245, 231, 209, 176, 136, 93, + 55, 27, 11, 3, 2, 1, 0, 255, + 254, 253, 252, 239, 221, 194, 158, 117, + 76, 42, 18, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table_offsets[ 17 ] = { + 0, 0, 2, 5, 9, 14, 20, 27, + 35, 44, 54, 65, 77, 90, 104, 119, + 135 +}; + +const opus_uint8 silk_sign_iCDF[ 42 ] = { + 254, 49, 67, 77, 82, 93, 99, + 198, 11, 18, 24, 31, 36, 45, + 255, 46, 66, 78, 87, 94, 104, + 208, 14, 21, 32, 42, 51, 66, + 255, 94, 104, 109, 112, 115, 118, + 248, 53, 69, 80, 88, 95, 102 +}; diff --git a/native/codec/libraries/opus/silk/tests/test_unit_LPC_inv_pred_gain.c b/native/codec/libraries/opus/silk/tests/test_unit_LPC_inv_pred_gain.c new file mode 100644 index 0000000..67067ce --- /dev/null +++ b/native/codec/libraries/opus/silk/tests/test_unit_LPC_inv_pred_gain.c @@ -0,0 +1,129 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc., Jean-Marc Valin +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "celt/stack_alloc.h" +#include "cpu_support.h" +#include "SigProc_FIX.h" + +/* Computes the impulse response of the filter so we + can catch filters that are definitely unstable. Some + unstable filters may be classified as stable, but not + the other way around. */ +int check_stability(opus_int16 *A_Q12, int order) { + int i; + int j; + int sum_a, sum_abs_a; + sum_a = sum_abs_a = 0; + for( j = 0; j < order; j++ ) { + sum_a += A_Q12[ j ]; + sum_abs_a += silk_abs( A_Q12[ j ] ); + } + /* Check DC stability. */ + if( sum_a >= 4096 ) { + return 0; + } + /* If the sum of absolute values is less than 1, the filter + has to be stable. */ + if( sum_abs_a < 4096 ) { + return 1; + } + double y[SILK_MAX_ORDER_LPC] = {0}; + y[0] = 1; + for( i = 0; i < 10000; i++ ) { + double sum = 0; + for( j = 0; j < order; j++ ) { + sum += y[ j ]*A_Q12[ j ]; + } + for( j = order - 1; j > 0; j-- ) { + y[ j ] = y[ j - 1 ]; + } + y[ 0 ] = sum*(1./4096); + /* If impulse response reaches +/- 10000, the filter + is definitely unstable. */ + if( !(y[ 0 ] < 10000 && y[ 0 ] > -10000) ) { + return 0; + } + /* Test every 8 sample for low amplitude. */ + if( ( i & 0x7 ) == 0 ) { + double amp = 0; + for( j = 0; j < order; j++ ) { + amp += fabs(y[j]); + } + if( amp < 0.00001 ) { + return 1; + } + } + } + return 1; +} + +int main(void) { + const int arch = opus_select_arch(); + /* Set to 10000 so all branches in C function are triggered */ + const int loop_num = 10000; + int count = 0; + ALLOC_STACK; + + /* FIXME: Make the seed random (with option to set it explicitly) + so we get wider coverage. */ + srand(0); + + printf("Testing silk_LPC_inverse_pred_gain() optimization ...\n"); + for( count = 0; count < loop_num; count++ ) { + unsigned int i; + opus_int order; + unsigned int shift; + opus_int16 A_Q12[ SILK_MAX_ORDER_LPC ]; + opus_int32 gain; + + for( order = 2; order <= SILK_MAX_ORDER_LPC; order += 2 ) { /* order must be even. */ + for( shift = 0; shift < 16; shift++ ) { /* Different dynamic range. */ + for( i = 0; i < SILK_MAX_ORDER_LPC; i++ ) { + A_Q12[i] = ((opus_int16)rand()) >> shift; + } + gain = silk_LPC_inverse_pred_gain(A_Q12, order, arch); + /* Look for filters that silk_LPC_inverse_pred_gain() thinks are + stable but definitely aren't. */ + if( gain != 0 && !check_stability(A_Q12, order) ) { + fprintf(stderr, "**Loop %4d failed!**\n", count); + return 1; + } + } + } + if( !(count % 500) ) { + printf("Loop %4d passed\n", count); + } + } + printf("silk_LPC_inverse_pred_gain() optimization passed\n"); + return 0; +} diff --git a/native/codec/libraries/opus/silk/tuning_parameters.h b/native/codec/libraries/opus/silk/tuning_parameters.h new file mode 100644 index 0000000..d70275f --- /dev/null +++ b/native/codec/libraries/opus/silk/tuning_parameters.h @@ -0,0 +1,155 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TUNING_PARAMETERS_H +#define SILK_TUNING_PARAMETERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decay time for bitreservoir */ +#define BITRESERVOIR_DECAY_TIME_MS 500 + +/*******************/ +/* Pitch estimator */ +/*******************/ + +/* Level of noise floor for whitening filter LPC analysis in pitch analysis */ +#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f + +/* Bandwidth expansion for whitening filter in pitch analysis */ +#define FIND_PITCH_BANDWIDTH_EXPANSION 0.99f + +/*********************/ +/* Linear prediction */ +/*********************/ + +/* LPC analysis regularization */ +#define FIND_LPC_COND_FAC 1e-5f + +/* Max cumulative LTP gain */ +#define MAX_SUM_LOG_GAIN_DB 250.0f + +/* LTP analysis defines */ +#define LTP_CORR_INV_MAX 0.03f + +/***********************/ +/* High pass filtering */ +/***********************/ + +/* Smoothing parameters for low end of pitch frequency range estimation */ +#define VARIABLE_HP_SMTH_COEF1 0.1f +#define VARIABLE_HP_SMTH_COEF2 0.015f +#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + +/* Min and max cut-off frequency values (-3 dB points) */ +#define VARIABLE_HP_MIN_CUTOFF_HZ 60 +#define VARIABLE_HP_MAX_CUTOFF_HZ 100 + +/***********/ +/* Various */ +/***********/ + +/* VAD threshold */ +#define SPEECH_ACTIVITY_DTX_THRES 0.05f + +/* Speech Activity LBRR enable threshold */ +#define LBRR_SPEECH_ACTIVITY_THRES 0.3f + +/*************************/ +/* Perceptual parameters */ +/*************************/ + +/* reduction in coding SNR during low speech activity */ +#define BG_SNR_DECR_dB 2.0f + +/* factor for reducing quantization noise during voiced speech */ +#define HARM_SNR_INCR_dB 2.0f + +/* factor for reducing quantization noise for unvoiced sparse signals */ +#define SPARSE_SNR_INCR_dB 2.0f + +/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */ +#define ENERGY_VARIATION_THRESHOLD_QNT_OFFSET 0.6f + +/* warping control */ +#define WARPING_MULTIPLIER 0.015f + +/* fraction added to first autocorrelation value */ +#define SHAPE_WHITE_NOISE_FRACTION 3e-5f + +/* noise shaping filter chirp factor */ +#define BANDWIDTH_EXPANSION 0.94f + +/* harmonic noise shaping */ +#define HARMONIC_SHAPING 0.3f + +/* extra harmonic noise shaping for high bitrates or noisy input */ +#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f + +/* parameter for shaping noise towards higher frequencies */ +#define HP_NOISE_COEF 0.25f + +/* parameter for shaping noise even more towards higher frequencies during voiced speech */ +#define HARM_HP_NOISE_COEF 0.35f + +/* parameter for applying a high-pass tilt to the input signal */ +#define INPUT_TILT 0.05f + +/* parameter for extra high-pass tilt to the input signal at high rates */ +#define HIGH_RATE_INPUT_TILT 0.1f + +/* parameter for reducing noise at the very low frequencies */ +#define LOW_FREQ_SHAPING 4.0f + +/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */ +#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f + +/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */ +#define SUBFR_SMTH_COEF 0.4f + +/* parameters defining the R/D tradeoff in the residual quantizer */ +#define LAMBDA_OFFSET 1.2f +#define LAMBDA_SPEECH_ACT -0.2f +#define LAMBDA_DELAYED_DECISIONS -0.05f +#define LAMBDA_INPUT_QUALITY -0.1f +#define LAMBDA_CODING_QUALITY -0.2f +#define LAMBDA_QUANT_OFFSET 0.8f + +/* Compensation in bitrate calculations for 10 ms modes */ +#define REDUCE_BITRATE_10_MS_BPS 2200 + +/* Maximum time before allowing a bandwidth transition */ +#define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000 + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_TUNING_PARAMETERS_H */ diff --git a/native/codec/libraries/opus/silk/typedef.h b/native/codec/libraries/opus/silk/typedef.h new file mode 100644 index 0000000..97b7e70 --- /dev/null +++ b/native/codec/libraries/opus/silk/typedef.h @@ -0,0 +1,78 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TYPEDEF_H +#define SILK_TYPEDEF_H + +#include "opus_types.h" +#include "opus_defines.h" + +#ifndef FIXED_POINT +# include +# define silk_float float +# define silk_float_MAX FLT_MAX +#endif + +#define silk_int64_MAX ((opus_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ +#define silk_int64_MIN ((opus_int64)0x8000000000000000LL) /* -2^63 */ +#define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */ +#define silk_int32_MIN ((opus_int32)0x80000000) /* -2^31 = -2147483648 */ +#define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */ +#define silk_int16_MIN ((opus_int16)0x8000) /* -2^15 = -32768 */ +#define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */ +#define silk_int8_MIN ((opus_int8)0x80) /* -2^7 = -128 */ +#define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ + +#define silk_TRUE 1 +#define silk_FALSE 0 + +/* assertions */ +#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS)) +# ifndef silk_assert +# include /* ASSERTE() */ +# define silk_assert(COND) _ASSERTE(COND) +# endif +#else +# ifdef ENABLE_ASSERTIONS +# include +# include +#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__); +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +static OPUS_INLINE void _silk_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +# define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}} +# else +# define silk_assert(COND) +# endif +#endif + +#endif /* SILK_TYPEDEF_H */ diff --git a/native/codec/libraries/opus/silk/x86/NSQ_del_dec_sse4_1.c b/native/codec/libraries/opus/silk/x86/NSQ_del_dec_sse4_1.c new file mode 100644 index 0000000..2c75ede --- /dev/null +++ b/native/codec/libraries/opus/silk/x86/NSQ_del_dec_sse4_1.c @@ -0,0 +1,859 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +#include "stack_alloc.h" + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +typedef NSQ_sample_struct NSQ_sample_pair[ 2 ]; + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +); + +void silk_NSQ_del_dec_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_dec_struct, psDelDec ); + NSQ_del_dec_struct *psDD; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct ); + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, + psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 ); + silk_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states_sse4_1( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec_sse4_1( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], + Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, + psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay ); + + x_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + VARDECL( NSQ_sample_pair, psSampleState ); + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + + __m128i a_Q12_0123, a_Q12_4567, a_Q12_89AB, a_Q12_CDEF; + __m128i b_Q12_0123, b_sr_Q12_0123; + SAVE_STACK; + + celt_assert( nStatesDelayedDecision > 0 ); + ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + a_Q12_0123 = OP_CVTEPI16_EPI32_M64( a_Q12 ); + a_Q12_4567 = OP_CVTEPI16_EPI32_M64( a_Q12 + 4 ); + + if( opus_likely( predictLPCOrder == 16 ) ) { + a_Q12_89AB = OP_CVTEPI16_EPI32_M64( a_Q12 + 8 ); + a_Q12_CDEF = OP_CVTEPI16_EPI32_M64( a_Q12 + 12 ); + } + + if( signalType == TYPE_VOICED ){ + b_Q12_0123 = OP_CVTEPI16_EPI32_M64( b_Q14 ); + b_sr_Q12_0123 = _mm_shuffle_epi32( b_Q12_0123, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + } + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + { + __m128i tmpa, tmpb, pred_lag_ptr_tmp; + pred_lag_ptr_tmp = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) ); + pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, 0x1B ); + tmpa = _mm_mul_epi32( pred_lag_ptr_tmp, b_Q12_0123 ); + tmpa = _mm_srli_si128( tmpa, 2 ); + + pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) );/* equal shift right 4 bytes */ + pred_lag_ptr_tmp = _mm_mul_epi32( pred_lag_ptr_tmp, b_sr_Q12_0123 ); + pred_lag_ptr_tmp = _mm_srli_si128( pred_lag_ptr_tmp, 2 ); + pred_lag_ptr_tmp = _mm_add_epi32( pred_lag_ptr_tmp, tmpa ); + + tmpb = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 0, 3, 2 ) );/* equal shift right 8 bytes */ + pred_lag_ptr_tmp = _mm_add_epi32( pred_lag_ptr_tmp, tmpb ); + LTP_pred_Q14 += _mm_cvtsi128_si32( pred_lag_ptr_tmp ); + + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + { + __m128i tmpa, tmpb, psLPC_Q14_tmp, a_Q12_tmp; + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q14 = silk_RSHIFT( predictLPCOrder, 1 ); + + tmpb = _mm_setzero_si128(); + + /* step 1 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -3 ] ) ); /* -3, -2 , -1, 0 */ + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); /* 0, -1, -2, -3 */ + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_0123 ); /* 0, -1, -2, -3 * 0123 -> 0*0, 2*-2 */ + + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_0123, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); /* 1*-1, 3*-3 */ + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* step 2 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -7 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_4567 ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_4567, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + if ( opus_likely( predictLPCOrder == 16 ) ) + { + /* step 3 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -11 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_89AB ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_89AB, _MM_SHUFFLE(0, 3, 2, 1 ) );/* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* setp 4 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -15 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_CDEF ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_CDEF, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* add at last */ + /* equal shift right 8 bytes*/ + tmpa = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + LPC_pred_Q14 += _mm_cvtsi128_si32( tmpb ); + } + else + { + /* add at last */ + tmpa = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) ); /* equal shift right 8 bytes*/ + tmpb = _mm_add_epi32( tmpb, tmpa ); + LPC_pred_Q14 += _mm_cvtsi128_si32( tmpb ); + + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + } + + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + } + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + NSQ_del_dec_struct *psDD; + __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + + /* prepare inv_gain_Q23 in packed 4 32-bits */ + xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23); + + for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) { + xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 ); + xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 ); + + xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 ); + xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 ); + + xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ])), xmm_x_Q3_x2x0 ); + } + + for( ; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + /* Scale long-term shaping state */ + { + __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1; + + /* prepare gain_adj_Q16 in packed 4 32-bits */ + xmm_gain_adj_Q16 = _mm_set1_epi32( gain_adj_Q16 ); + + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 ) + { + xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 ); + } + + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + } + } +} diff --git a/native/codec/libraries/opus/silk/x86/NSQ_sse4_1.c b/native/codec/libraries/opus/silk/x86/NSQ_sse4_1.c new file mode 100644 index 0000000..b0315e3 --- /dev/null +++ b/native/codec/libraries/opus/silk/x86/NSQ_sse4_1.c @@ -0,0 +1,719 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" +#include "stack_alloc.h" + +static OPUS_INLINE void silk_nsq_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int32 table[][4] /* I */ +); + +void silk_NSQ_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + + opus_int32 table[ 64 ][ 4 ]; + opus_int32 tmp1; + opus_int32 q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + + SAVE_STACK; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + /* 0 */ + q1_Q10 = offset_Q10; + q2_Q10 = offset_Q10 + ( 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 32 ][ 0 ] = q1_Q10; + table[ 32 ][ 1 ] = q2_Q10; + table[ 32 ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + + /* -1 */ + q1_Q10 = offset_Q10 - ( 1024 - QUANT_LEVEL_ADJUST_Q10 ); + q2_Q10 = offset_Q10; + rd1_Q20 = - q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 31 ][ 0 ] = q1_Q10; + table[ 31 ][ 1 ] = q2_Q10; + table[ 31 ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 31 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + + /* > 0 */ + for (k = 1; k <= 31; k++) + { + tmp1 = offset_Q10 + silk_LSHIFT( k, 10 ); + + q1_Q10 = tmp1 - QUANT_LEVEL_ADJUST_Q10; + q2_Q10 = tmp1 - QUANT_LEVEL_ADJUST_Q10 + 1024; + rd1_Q20 = q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 32 + k ][ 0 ] = q1_Q10; + table[ 32 + k ][ 1 ] = q2_Q10; + table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + } + + /* < -1 */ + for (k = -32; k <= -2; k++) + { + tmp1 = offset_Q10 + silk_LSHIFT( k, 10 ); + + q1_Q10 = tmp1 + QUANT_LEVEL_ADJUST_Q10; + q2_Q10 = tmp1 + QUANT_LEVEL_ADJUST_Q10 + 1024; + rd1_Q20 = - q1_Q10 * Lambda_Q10; + rd2_Q20 = - q2_Q10 * Lambda_Q10; + + table[ 32 + k ][ 0 ] = q1_Q10; + table[ 32 + k ][ 1 ] = q2_Q10; + table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, + psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states_sse4_1( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + if ( opus_likely( ( 10 == psEncC->shapingLPCOrder ) && ( 16 == psEncC->predictLPCOrder) ) ) + { + silk_noise_shape_quantizer_10_16_sse4_1( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], + offset_Q10, psEncC->subfr_length, &(table[32]) ); + } + else + { + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10, + offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch ); + } + + x_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/***********************************/ +/* silk_noise_shape_quantizer_10_16 */ +/***********************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int32 table[][4] /* I */ +) +{ + opus_int i; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, q1_Q0, q1_Q10, q2_Q10; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; + + __m128i xmm_tempa, xmm_tempb; + + __m128i xmm_one; + + __m128i psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF; + __m128i psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF; + __m128i a_Q12_01234567, a_Q12_89ABCDEF; + + __m128i sAR2_Q14_hi_76543210, sAR2_Q14_lo_76543210; + __m128i AR_shp_Q13_76543210; + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + + sLF_AR_shp_Q14 = NSQ->sLF_AR_shp_Q14; + xq_Q14 = psLPC_Q14[ 0 ]; + LTP_pred_Q13 = 0; + + /* load a_Q12 */ + xmm_one = _mm_set_epi8( 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 ); + + /* load a_Q12[0] - a_Q12[7] */ + a_Q12_01234567 = _mm_loadu_si128( (__m128i *)(&a_Q12[ 0 ] ) ); + /* load a_Q12[ 8 ] - a_Q12[ 15 ] */ + a_Q12_89ABCDEF = _mm_loadu_si128( (__m128i *)(&a_Q12[ 8 ] ) ); + + a_Q12_01234567 = _mm_shuffle_epi8( a_Q12_01234567, xmm_one ); + a_Q12_89ABCDEF = _mm_shuffle_epi8( a_Q12_89ABCDEF, xmm_one ); + + /* load AR_shp_Q13 */ + AR_shp_Q13_76543210 = _mm_loadu_si128( (__m128i *)(&AR_shp_Q13[0] ) ); + + /* load psLPC_Q14 */ + xmm_one = _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0 ); + + xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-16]) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-12]) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + psLPC_Q14_hi_89ABCDEF = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + psLPC_Q14_lo_89ABCDEF = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -8 ]) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -4 ]) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + psLPC_Q14_hi_01234567 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + psLPC_Q14_lo_01234567 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + /* load sAR2_Q14 */ + xmm_tempa = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 0 ]) ) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 4 ]) ) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + sAR2_Q14_hi_76543210 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + sAR2_Q14_lo_76543210 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + /* prepare 1 in 8 * 16bit */ + xmm_one = _mm_set1_epi16(1); + + for( i = 0; i < length; i++ ) + { + /* Short-term prediction */ + __m128i xmm_hi_07, xmm_hi_8F, xmm_lo_07, xmm_lo_8F; + + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = 8; /* silk_RSHIFT( predictLPCOrder, 1 ); */ + + /* shift psLPC_Q14 */ + psLPC_Q14_hi_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF, 2 ); + psLPC_Q14_lo_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF, 2 ); + + psLPC_Q14_hi_01234567 = _mm_srli_si128( psLPC_Q14_hi_01234567, 2 ); + psLPC_Q14_lo_01234567 = _mm_srli_si128( psLPC_Q14_lo_01234567, 2 ); + + psLPC_Q14_hi_01234567 = _mm_insert_epi16( psLPC_Q14_hi_01234567, (xq_Q14 >> 16), 7 ); + psLPC_Q14_lo_01234567 = _mm_insert_epi16( psLPC_Q14_lo_01234567, (xq_Q14), 7 ); + + /* high part, use pmaddwd, results in 4 32-bit */ + xmm_hi_07 = _mm_madd_epi16( psLPC_Q14_hi_01234567, a_Q12_01234567 ); + xmm_hi_8F = _mm_madd_epi16( psLPC_Q14_hi_89ABCDEF, a_Q12_89ABCDEF ); + + /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed, _mm_srai_epi16(psLPC_Q14_lo_01234567, 15) */ + xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_01234567 ); + xmm_tempb = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_89ABCDEF ); + + xmm_tempa = _mm_and_si128( xmm_tempa, a_Q12_01234567 ); + xmm_tempb = _mm_and_si128( xmm_tempb, a_Q12_89ABCDEF ); + + xmm_lo_07 = _mm_mulhi_epi16( psLPC_Q14_lo_01234567, a_Q12_01234567 ); + xmm_lo_8F = _mm_mulhi_epi16( psLPC_Q14_lo_89ABCDEF, a_Q12_89ABCDEF ); + + xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa ); + xmm_lo_8F = _mm_add_epi16( xmm_lo_8F, xmm_tempb ); + + xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one ); + xmm_lo_8F = _mm_madd_epi16( xmm_lo_8F, xmm_one ); + + /* accumulate */ + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_hi_8F ); + xmm_lo_07 = _mm_add_epi32( xmm_lo_07, xmm_lo_8F ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) ); + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) ); + + LPC_pred_Q10 += _mm_cvtsi128_si32( xmm_hi_07 ); + + /* Long-term prediction */ + if ( opus_likely( signalType == TYPE_VOICED ) ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + { + __m128i b_Q14_3210, b_Q14_0123, pred_lag_ptr_0123; + + b_Q14_3210 = OP_CVTEPI16_EPI32_M64( b_Q14 ); + b_Q14_0123 = _mm_shuffle_epi32( b_Q14_3210, 0x1B ); + + /* loaded: [0] [-1] [-2] [-3] */ + pred_lag_ptr_0123 = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) ); + /* shuffle to [-3] [-2] [-1] [0] and to new xmm */ + xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, 0x1B ); + /*64-bit multiply, a[2] * b[-2], a[0] * b[0] */ + xmm_tempa = _mm_mul_epi32( xmm_tempa, b_Q14_3210 ); + /* right shift 2 bytes (16 bits), zero extended */ + xmm_tempa = _mm_srli_si128( xmm_tempa, 2 ); + + /* a[1] * b[-1], a[3] * b[-3] */ + pred_lag_ptr_0123 = _mm_mul_epi32( pred_lag_ptr_0123, b_Q14_0123 ); + pred_lag_ptr_0123 = _mm_srli_si128( pred_lag_ptr_0123, 2 ); + + pred_lag_ptr_0123 = _mm_add_epi32( pred_lag_ptr_0123, xmm_tempa ); + /* equal shift right 8 bytes*/ + xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + xmm_tempa = _mm_add_epi32( xmm_tempa, pred_lag_ptr_0123 ); + + LTP_pred_Q13 += _mm_cvtsi128_si32( xmm_tempa ); + + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } + } + + /* Noise shape feedback */ + NSQ->sAR2_Q14[ 9 ] = NSQ->sAR2_Q14[ 8 ]; + NSQ->sAR2_Q14[ 8 ] = _mm_cvtsi128_si32( _mm_srli_si128(_mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ), 12 ) ); + + sAR2_Q14_hi_76543210 = _mm_slli_si128( sAR2_Q14_hi_76543210, 2 ); + sAR2_Q14_lo_76543210 = _mm_slli_si128( sAR2_Q14_lo_76543210, 2 ); + + sAR2_Q14_hi_76543210 = _mm_insert_epi16( sAR2_Q14_hi_76543210, (xq_Q14 >> 16), 0 ); + sAR2_Q14_lo_76543210 = _mm_insert_epi16( sAR2_Q14_lo_76543210, (xq_Q14), 0 ); + + /* high part, use pmaddwd, results in 4 32-bit */ + xmm_hi_07 = _mm_madd_epi16( sAR2_Q14_hi_76543210, AR_shp_Q13_76543210 ); + + /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed,_mm_srai_epi16(sAR2_Q14_lo_76543210, 15) */ + xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), sAR2_Q14_lo_76543210 ); + xmm_tempa = _mm_and_si128( xmm_tempa, AR_shp_Q13_76543210 ); + + xmm_lo_07 = _mm_mulhi_epi16( sAR2_Q14_lo_76543210, AR_shp_Q13_76543210 ); + xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa ); + + xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one ); + + /* accumulate */ + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) ); + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) ); + + n_AR_Q12 = 5 + _mm_cvtsi128_si32( xmm_hi_07 ); + + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 8 ], AR_shp_Q13[ 8 ] ); + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 9 ], AR_shp_Q13[ 9 ] ); + + n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */ + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, sLF_AR_shp_Q14, LF_shp_Q14 ); + + silk_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Flip sign depending on dither */ + tmp2 = -r_Q10; + if ( NSQ->rand_seed < 0 ) r_Q10 = tmp2; + + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + + q1_Q10 = table[q1_Q0][0]; + q2_Q10 = table[q1_Q0][1]; + + if (r_Q10 * table[q1_Q0][2] - table[q1_Q0][3] < 0) + { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + + tmp2 = -exc_Q14; + if ( NSQ->rand_seed < 0 ) exc_Q14 = tmp2; + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 ); + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + /* Scale XQ back to normal level before saving */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH ]; + + /* write back sAR2_Q14 */ + xmm_tempa = _mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ); + xmm_tempb = _mm_unpacklo_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ); + _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 4 ]), xmm_tempa ); + _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 0 ]), xmm_tempb ); + + /* xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) ); */ + { + __m128i xmm_Gain_Q10; + __m128i xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, xmm_xq_Q14_7654, xmm_xq_Q14_x7x5; + + /* prepare (1 << 7) in packed 4 32-bits */ + xmm_tempa = _mm_set1_epi32( (1 << 7) ); + + /* prepare Gain_Q10 in packed 4 32-bits */ + xmm_Gain_Q10 = _mm_set1_epi32( Gain_Q10 ); + + /* process xq */ + for (i = 0; i < length - 7; i += 8) + { + xmm_xq_Q14_3210 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 0 ] ) ) ); + xmm_xq_Q14_7654 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 4 ] ) ) ); + + /* equal shift right 4 bytes*/ + xmm_xq_Q14_x3x1 = _mm_shuffle_epi32( xmm_xq_Q14_3210, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + /* equal shift right 4 bytes*/ + xmm_xq_Q14_x7x5 = _mm_shuffle_epi32( xmm_xq_Q14_7654, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_xq_Q14_3210 = _mm_mul_epi32( xmm_xq_Q14_3210, xmm_Gain_Q10 ); + xmm_xq_Q14_x3x1 = _mm_mul_epi32( xmm_xq_Q14_x3x1, xmm_Gain_Q10 ); + xmm_xq_Q14_7654 = _mm_mul_epi32( xmm_xq_Q14_7654, xmm_Gain_Q10 ); + xmm_xq_Q14_x7x5 = _mm_mul_epi32( xmm_xq_Q14_x7x5, xmm_Gain_Q10 ); + + xmm_xq_Q14_3210 = _mm_srli_epi64( xmm_xq_Q14_3210, 16 ); + xmm_xq_Q14_x3x1 = _mm_slli_epi64( xmm_xq_Q14_x3x1, 16 ); + xmm_xq_Q14_7654 = _mm_srli_epi64( xmm_xq_Q14_7654, 16 ); + xmm_xq_Q14_x7x5 = _mm_slli_epi64( xmm_xq_Q14_x7x5, 16 ); + + xmm_xq_Q14_3210 = _mm_blend_epi16( xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, 0xCC ); + xmm_xq_Q14_7654 = _mm_blend_epi16( xmm_xq_Q14_7654, xmm_xq_Q14_x7x5, 0xCC ); + + /* silk_RSHIFT_ROUND(xq, 8) */ + xmm_xq_Q14_3210 = _mm_add_epi32( xmm_xq_Q14_3210, xmm_tempa ); + xmm_xq_Q14_7654 = _mm_add_epi32( xmm_xq_Q14_7654, xmm_tempa ); + + xmm_xq_Q14_3210 = _mm_srai_epi32( xmm_xq_Q14_3210, 8 ); + xmm_xq_Q14_7654 = _mm_srai_epi32( xmm_xq_Q14_7654, 8 ); + + /* silk_SAT16 */ + xmm_xq_Q14_3210 = _mm_packs_epi32( xmm_xq_Q14_3210, xmm_xq_Q14_7654 ); + + /* save to xq */ + _mm_storeu_si128( (__m128i *)(&xq[ i ] ), xmm_xq_Q14_3210 ); + } + } + for ( ; i < length; i++) + { + xq[i] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static OPUS_INLINE void silk_nsq_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + + /* prepare inv_gain_Q23 in packed 4 32-bits */ + xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23); + + for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) { + xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) ); + + /* equal shift right 4 bytes*/ + xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 ); + xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 ); + + xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 ); + xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 ); + + xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ] ) ), xmm_x_Q3_x2x0 ); + } + + for( ; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + /* Scale long-term shaping state */ + __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1; + + /* prepare gain_adj_Q16 in packed 4 32-bits */ + xmm_gain_adj_Q16 = _mm_set1_epi32(gain_adj_Q16); + + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 ) + { + xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 ); + } + + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + } +} diff --git a/native/codec/libraries/opus/silk/x86/SigProc_FIX_sse.h b/native/codec/libraries/opus/silk/x86/SigProc_FIX_sse.h new file mode 100644 index 0000000..61efa8d --- /dev/null +++ b/native/codec/libraries/opus/silk/x86/SigProc_FIX_sse.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SIGPROC_FIX_SSE_H +#define SIGPROC_FIX_SSE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +void silk_burg_modified_sse4_1( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +); + +#if defined(OPUS_X86_PRESUME_SSE4_1) +#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((void)(arch), silk_burg_modified_sse4_1(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#else + +extern void (*const SILK_BURG_MODIFIED_IMPL[OPUS_ARCHMASK + 1])( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */); + +# define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((*SILK_BURG_MODIFIED_IMPL[(arch) & OPUS_ARCHMASK])(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#endif + +opus_int64 silk_inner_prod16_aligned_64_sse4_1( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len +); + + +#if defined(OPUS_X86_PRESUME_SSE4_1) + +#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((void)(arch),silk_inner_prod16_aligned_64_sse4_1(inVec1, inVec2, len)) + +#else + +extern opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[OPUS_ARCHMASK + 1])( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len); + +# define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((*SILK_INNER_PROD16_ALIGNED_64_IMPL[(arch) & OPUS_ARCHMASK])(inVec1, inVec2, len)) + +#endif +#endif +#endif diff --git a/native/codec/libraries/opus/silk/x86/VAD_sse4_1.c b/native/codec/libraries/opus/silk/x86/VAD_sse4_1.c new file mode 100644 index 0000000..d02ddf4 --- /dev/null +++ b/native/codec/libraries/opus/silk/x86/VAD_sse4_1.c @@ -0,0 +1,277 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "main.h" +#include "stack_alloc.h" + +/* Weighting factors for tilt measure */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8_sse4_1( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength1, decimated_framelength2; + opus_int decimated_framelength; + opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + VARDECL( opus_int16, X ); + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int X_offset[ VAD_N_BANDS ]; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + + SAVE_STACK; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + celt_assert( psEncC->frame_length <= 512 ); + celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 ); + decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 ); + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + /* Decimate into 4 bands: + 0 L 3L L 3L 5L + - -- - -- -- + 8 8 2 4 4 + + [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz | + + They're arranged to allow the minimal ( frame_length / 4 ) extra + scratch space during the downsampling process */ + X_offset[ 0 ] = 0; + X_offset[ 1 ] = decimated_framelength + decimated_framelength2; + X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength; + X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2; + ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 ); + + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], + X, &X[ X_offset[ 3 ] ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ], + X, &X[ X_offset[ 2 ] ], decimated_framelength1 ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ], + X, &X[ X_offset[ 1 ] ], decimated_framelength2 ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 ); + X[ i ] -= X[ i - 1 ]; + } + X[ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + __m128i xmm_X, xmm_acc; + sumSquared = 0; + + xmm_acc = _mm_setzero_si128(); + + for( i = 0; i < dec_subframe_length - 7; i += 8 ) + { + xmm_X = _mm_loadu_si128( (__m128i *)&(X[ X_offset[ b ] + i + dec_subframe_offset ] ) ); + xmm_X = _mm_srai_epi16( xmm_X, 3 ); + xmm_X = _mm_madd_epi16( xmm_X, xmm_X ); + xmm_acc = _mm_add_epi32( xmm_acc, xmm_X ); + } + + xmm_acc = _mm_add_epi32( xmm_acc, _mm_unpackhi_epi64( xmm_acc, xmm_acc ) ); + xmm_acc = _mm_add_epi32( xmm_acc, _mm_shufflelo_epi16( xmm_acc, 0x0E ) ); + + sumSquared += _mm_cvtsi128_si32( xmm_acc ); + + for( ; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( + X[ X_offset[ b ] + i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( (opus_int32)1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 32768 ) { + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 ); + } else { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 ); + } + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + RESTORE_STACK; + return( ret ); +} diff --git a/native/codec/libraries/opus/silk/x86/VQ_WMat_EC_sse4_1.c b/native/codec/libraries/opus/silk/x86/VQ_WMat_EC_sse4_1.c new file mode 100644 index 0000000..74d6c6d --- /dev/null +++ b/native/codec/libraries/opus/silk/x86/VQ_WMat_EC_sse4_1.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC_sse4_1( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k, gain_tmp_Q7; + const opus_int8 *cb_row_Q7; + opus_int16 diff_Q14[ 5 ]; + opus_int32 sum1_Q14, sum2_Q16; + + __m128i C_tmp1, C_tmp2, C_tmp3, C_tmp4, C_tmp5; + /* Loop over codebook */ + *rate_dist_Q14 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + for( k = 0; k < L; k++ ) { + gain_tmp_Q7 = cb_gain_Q7[k]; + + diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 ); + + C_tmp1 = OP_CVTEPI16_EPI32_M64( &in_Q14[ 1 ] ); + C_tmp2 = OP_CVTEPI8_EPI32_M32( &cb_row_Q7[ 1 ] ); + C_tmp2 = _mm_slli_epi32( C_tmp2, 7 ); + C_tmp1 = _mm_sub_epi32( C_tmp1, C_tmp2 ); + + diff_Q14[ 1 ] = _mm_extract_epi16( C_tmp1, 0 ); + diff_Q14[ 2 ] = _mm_extract_epi16( C_tmp1, 2 ); + diff_Q14[ 3 ] = _mm_extract_epi16( C_tmp1, 4 ); + diff_Q14[ 4 ] = _mm_extract_epi16( C_tmp1, 6 ); + + /* Weighted rate */ + sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] ); + + /* Penalty for too large gain */ + sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 ); + + silk_assert( sum1_Q14 >= 0 ); + + /* first row of W_Q18 */ + C_tmp3 = _mm_loadu_si128( (__m128i *)(&W_Q18[ 1 ] ) ); + C_tmp4 = _mm_mul_epi32( C_tmp3, C_tmp1 ); + C_tmp4 = _mm_srli_si128( C_tmp4, 2 ); + + C_tmp1 = _mm_shuffle_epi32( C_tmp1, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */ + C_tmp3 = _mm_shuffle_epi32( C_tmp3, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */ + + C_tmp5 = _mm_mul_epi32( C_tmp3, C_tmp1 ); + C_tmp5 = _mm_srli_si128( C_tmp5, 2 ); + + C_tmp5 = _mm_add_epi32( C_tmp4, C_tmp5 ); + C_tmp5 = _mm_slli_epi32( C_tmp5, 1 ); + + C_tmp5 = _mm_add_epi32( C_tmp5, _mm_shuffle_epi32( C_tmp5, _MM_SHUFFLE( 0, 0, 0, 2 ) ) ); + sum2_Q16 = _mm_cvtsi128_si32( C_tmp5 ); + + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] ); + + /* second row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] ); + + /* third row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] ); + + /* fourth row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] ); + + /* last row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] ); + + silk_assert( sum1_Q14 >= 0 ); + + /* find best */ + if( sum1_Q14 < *rate_dist_Q14 ) { + *rate_dist_Q14 = sum1_Q14; + *ind = (opus_int8)k; + *gain_Q7 = gain_tmp_Q7; + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/native/codec/libraries/opus/silk/x86/main_sse.h b/native/codec/libraries/opus/silk/x86/main_sse.h new file mode 100644 index 0000000..2f15d44 --- /dev/null +++ b/native/codec/libraries/opus/silk/x86/main_sse.h @@ -0,0 +1,248 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MAIN_SSE_H +#define MAIN_SSE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +# if defined(OPUS_X86_MAY_HAVE_SSE4_1) + +#if 0 /* FIXME: SSE disabled until silk_VQ_WMat_EC_sse4_1() gets updated. */ +# define OVERRIDE_silk_VQ_WMat_EC + +void silk_VQ_WMat_EC_sse4_1( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L, arch) \ + ((void)(arch),silk_VQ_WMat_EC_sse4_1(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L)) + +#else + +extern void (*const SILK_VQ_WMAT_EC_IMPL[OPUS_ARCHMASK + 1])( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +); + +# define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L, arch) \ + ((*SILK_VQ_WMAT_EC_IMPL[(arch) & OPUS_ARCHMASK])(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L)) + +#endif +#endif + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +# define OVERRIDE_silk_NSQ + +void silk_NSQ_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#else + +extern void (*const SILK_NSQ_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +# define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((*SILK_NSQ_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#endif + +# define OVERRIDE_silk_NSQ_del_dec + +void silk_NSQ_del_dec_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_del_dec_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#else + +extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +# define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((*SILK_NSQ_DEL_DEC_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#endif +#endif + +void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +); + +/**************************/ +/* Noise level estimation */ +/**************************/ +void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +# define OVERRIDE_silk_VAD_GetSA_Q8 + +opus_int silk_VAD_GetSA_Q8_sse4_1( + silk_encoder_state *psEnC, + const opus_int16 pIn[] +); + +#if defined(OPUS_X86_PRESUME_SSE4_1) +#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_sse4_1(psEnC, pIn)) + +#else + +# define silk_VAD_GetSA_Q8(psEnC, pIn, arch) \ + ((*SILK_VAD_GETSA_Q8_IMPL[(arch) & OPUS_ARCHMASK])(psEnC, pIn)) + +extern opus_int (*const SILK_VAD_GETSA_Q8_IMPL[OPUS_ARCHMASK + 1])( + silk_encoder_state *psEnC, + const opus_int16 pIn[]); + +#endif + +# endif +#endif diff --git a/native/codec/libraries/opus/silk/x86/x86_silk_map.c b/native/codec/libraries/opus/silk/x86/x86_silk_map.c new file mode 100644 index 0000000..32dcc3c --- /dev/null +++ b/native/codec/libraries/opus/silk/x86/x86_silk_map.c @@ -0,0 +1,164 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include "celt/x86/x86cpu.h" +#include "structs.h" +#include "SigProc_FIX.h" +#include "pitch.h" +#include "main.h" + +#if !defined(OPUS_X86_PRESUME_SSE4_1) + +#if defined(FIXED_POINT) + +#include "fixed/main_FIX.h" + +opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[ OPUS_ARCHMASK + 1 ] )( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len +) = { + silk_inner_prod16_aligned_64_c, /* non-sse */ + silk_inner_prod16_aligned_64_c, + silk_inner_prod16_aligned_64_c, + MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ) /* avx */ +}; + +#endif + +opus_int (*const SILK_VAD_GETSA_Q8_IMPL[ OPUS_ARCHMASK + 1 ] )( + silk_encoder_state *psEncC, + const opus_int16 pIn[] +) = { + silk_VAD_GetSA_Q8_c, /* non-sse */ + silk_VAD_GetSA_Q8_c, + silk_VAD_GetSA_Q8_c, + MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ) /* avx */ +}; + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +void (*const SILK_NSQ_IMPL[ OPUS_ARCHMASK + 1 ] )( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_c, /* non-sse */ + silk_NSQ_c, + silk_NSQ_c, + MAY_HAVE_SSE4_1( silk_NSQ ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_NSQ ) /* avx */ +}; +#endif + +#if 0 /* FIXME: SSE disabled until silk_VQ_WMat_EC_sse4_1() gets updated. */ +void (*const SILK_VQ_WMAT_EC_IMPL[ OPUS_ARCHMASK + 1 ] )( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +) = { + silk_VQ_WMat_EC_c, /* non-sse */ + silk_VQ_WMat_EC_c, + silk_VQ_WMat_EC_c, + MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ) /* avx */ +}; +#endif + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +void (*const SILK_NSQ_DEL_DEC_IMPL[ OPUS_ARCHMASK + 1 ] )( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_del_dec_c, /* non-sse */ + silk_NSQ_del_dec_c, + silk_NSQ_del_dec_c, + MAY_HAVE_SSE4_1( silk_NSQ_del_dec ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_NSQ_del_dec ) /* avx */ +}; +#endif + +#if defined(FIXED_POINT) + +void (*const SILK_BURG_MODIFIED_IMPL[ OPUS_ARCHMASK + 1 ] )( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) = { + silk_burg_modified_c, /* non-sse */ + silk_burg_modified_c, + silk_burg_modified_c, + MAY_HAVE_SSE4_1( silk_burg_modified ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_burg_modified ) /* avx */ +}; + +#endif +#endif diff --git a/native/codec/libraries/opus/silk_headers.mk b/native/codec/libraries/opus/silk_headers.mk new file mode 100644 index 0000000..2588067 --- /dev/null +++ b/native/codec/libraries/opus/silk_headers.mk @@ -0,0 +1,44 @@ +SILK_HEAD = \ +silk/debug.h \ +silk/control.h \ +silk/errors.h \ +silk/API.h \ +silk/typedef.h \ +silk/define.h \ +silk/main.h \ +silk/x86/main_sse.h \ +silk/PLC.h \ +silk/structs.h \ +silk/tables.h \ +silk/tuning_parameters.h \ +silk/Inlines.h \ +silk/MacroCount.h \ +silk/MacroDebug.h \ +silk/macros.h \ +silk/NSQ.h \ +silk/pitch_est_defines.h \ +silk/resampler_private.h \ +silk/resampler_rom.h \ +silk/resampler_structs.h \ +silk/SigProc_FIX.h \ +silk/x86/SigProc_FIX_sse.h \ +silk/arm/biquad_alt_arm.h \ +silk/arm/LPC_inv_pred_gain_arm.h \ +silk/arm/macros_armv4.h \ +silk/arm/macros_armv5e.h \ +silk/arm/macros_arm64.h \ +silk/arm/SigProc_FIX_armv4.h \ +silk/arm/SigProc_FIX_armv5e.h \ +silk/arm/NSQ_del_dec_arm.h \ +silk/arm/NSQ_neon.h \ +silk/fixed/main_FIX.h \ +silk/fixed/structs_FIX.h \ +silk/fixed/arm/warped_autocorrelation_FIX_arm.h \ +silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h \ +silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h \ +silk/float/main_FLP.h \ +silk/float/structs_FLP.h \ +silk/float/SigProc_FLP.h \ +silk/mips/macros_mipsr1.h \ +silk/mips/NSQ_del_dec_mipsr1.h \ +silk/mips/sigproc_fix_mipsr1.h diff --git a/native/codec/libraries/opus/silk_sources.mk b/native/codec/libraries/opus/silk_sources.mk new file mode 100644 index 0000000..d2666e6 --- /dev/null +++ b/native/codec/libraries/opus/silk_sources.mk @@ -0,0 +1,154 @@ +SILK_SOURCES = \ +silk/CNG.c \ +silk/code_signs.c \ +silk/init_decoder.c \ +silk/decode_core.c \ +silk/decode_frame.c \ +silk/decode_parameters.c \ +silk/decode_indices.c \ +silk/decode_pulses.c \ +silk/decoder_set_fs.c \ +silk/dec_API.c \ +silk/enc_API.c \ +silk/encode_indices.c \ +silk/encode_pulses.c \ +silk/gain_quant.c \ +silk/interpolate.c \ +silk/LP_variable_cutoff.c \ +silk/NLSF_decode.c \ +silk/NSQ.c \ +silk/NSQ_del_dec.c \ +silk/PLC.c \ +silk/shell_coder.c \ +silk/tables_gain.c \ +silk/tables_LTP.c \ +silk/tables_NLSF_CB_NB_MB.c \ +silk/tables_NLSF_CB_WB.c \ +silk/tables_other.c \ +silk/tables_pitch_lag.c \ +silk/tables_pulses_per_block.c \ +silk/VAD.c \ +silk/control_audio_bandwidth.c \ +silk/quant_LTP_gains.c \ +silk/VQ_WMat_EC.c \ +silk/HP_variable_cutoff.c \ +silk/NLSF_encode.c \ +silk/NLSF_VQ.c \ +silk/NLSF_unpack.c \ +silk/NLSF_del_dec_quant.c \ +silk/process_NLSFs.c \ +silk/stereo_LR_to_MS.c \ +silk/stereo_MS_to_LR.c \ +silk/check_control_input.c \ +silk/control_SNR.c \ +silk/init_encoder.c \ +silk/control_codec.c \ +silk/A2NLSF.c \ +silk/ana_filt_bank_1.c \ +silk/biquad_alt.c \ +silk/bwexpander_32.c \ +silk/bwexpander.c \ +silk/debug.c \ +silk/decode_pitch.c \ +silk/inner_prod_aligned.c \ +silk/lin2log.c \ +silk/log2lin.c \ +silk/LPC_analysis_filter.c \ +silk/LPC_inv_pred_gain.c \ +silk/table_LSF_cos.c \ +silk/NLSF2A.c \ +silk/NLSF_stabilize.c \ +silk/NLSF_VQ_weights_laroia.c \ +silk/pitch_est_tables.c \ +silk/resampler.c \ +silk/resampler_down2_3.c \ +silk/resampler_down2.c \ +silk/resampler_private_AR2.c \ +silk/resampler_private_down_FIR.c \ +silk/resampler_private_IIR_FIR.c \ +silk/resampler_private_up2_HQ.c \ +silk/resampler_rom.c \ +silk/sigm_Q15.c \ +silk/sort.c \ +silk/sum_sqr_shift.c \ +silk/stereo_decode_pred.c \ +silk/stereo_encode_pred.c \ +silk/stereo_find_predictor.c \ +silk/stereo_quant_pred.c \ +silk/LPC_fit.c + +SILK_SOURCES_SSE4_1 = \ +silk/x86/NSQ_sse4_1.c \ +silk/x86/NSQ_del_dec_sse4_1.c \ +silk/x86/x86_silk_map.c \ +silk/x86/VAD_sse4_1.c \ +silk/x86/VQ_WMat_EC_sse4_1.c + +SILK_SOURCES_ARM_NEON_INTR = \ +silk/arm/arm_silk_map.c \ +silk/arm/biquad_alt_neon_intr.c \ +silk/arm/LPC_inv_pred_gain_neon_intr.c \ +silk/arm/NSQ_del_dec_neon_intr.c \ +silk/arm/NSQ_neon.c + +SILK_SOURCES_FIXED = \ +silk/fixed/LTP_analysis_filter_FIX.c \ +silk/fixed/LTP_scale_ctrl_FIX.c \ +silk/fixed/corrMatrix_FIX.c \ +silk/fixed/encode_frame_FIX.c \ +silk/fixed/find_LPC_FIX.c \ +silk/fixed/find_LTP_FIX.c \ +silk/fixed/find_pitch_lags_FIX.c \ +silk/fixed/find_pred_coefs_FIX.c \ +silk/fixed/noise_shape_analysis_FIX.c \ +silk/fixed/process_gains_FIX.c \ +silk/fixed/regularize_correlations_FIX.c \ +silk/fixed/residual_energy16_FIX.c \ +silk/fixed/residual_energy_FIX.c \ +silk/fixed/warped_autocorrelation_FIX.c \ +silk/fixed/apply_sine_window_FIX.c \ +silk/fixed/autocorr_FIX.c \ +silk/fixed/burg_modified_FIX.c \ +silk/fixed/k2a_FIX.c \ +silk/fixed/k2a_Q16_FIX.c \ +silk/fixed/pitch_analysis_core_FIX.c \ +silk/fixed/vector_ops_FIX.c \ +silk/fixed/schur64_FIX.c \ +silk/fixed/schur_FIX.c + +SILK_SOURCES_FIXED_SSE4_1 = \ +silk/fixed/x86/vector_ops_FIX_sse4_1.c \ +silk/fixed/x86/burg_modified_FIX_sse4_1.c + +SILK_SOURCES_FIXED_ARM_NEON_INTR = \ +silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c + +SILK_SOURCES_FLOAT = \ +silk/float/apply_sine_window_FLP.c \ +silk/float/corrMatrix_FLP.c \ +silk/float/encode_frame_FLP.c \ +silk/float/find_LPC_FLP.c \ +silk/float/find_LTP_FLP.c \ +silk/float/find_pitch_lags_FLP.c \ +silk/float/find_pred_coefs_FLP.c \ +silk/float/LPC_analysis_filter_FLP.c \ +silk/float/LTP_analysis_filter_FLP.c \ +silk/float/LTP_scale_ctrl_FLP.c \ +silk/float/noise_shape_analysis_FLP.c \ +silk/float/process_gains_FLP.c \ +silk/float/regularize_correlations_FLP.c \ +silk/float/residual_energy_FLP.c \ +silk/float/warped_autocorrelation_FLP.c \ +silk/float/wrappers_FLP.c \ +silk/float/autocorrelation_FLP.c \ +silk/float/burg_modified_FLP.c \ +silk/float/bwexpander_FLP.c \ +silk/float/energy_FLP.c \ +silk/float/inner_product_FLP.c \ +silk/float/k2a_FLP.c \ +silk/float/LPC_inv_pred_gain_FLP.c \ +silk/float/pitch_analysis_core_FLP.c \ +silk/float/scale_copy_vector_FLP.c \ +silk/float/scale_vector_FLP.c \ +silk/float/schur_FLP.c \ +silk/float/sort_FLP.c diff --git a/native/codec/libraries/opus/src/analysis.c b/native/codec/libraries/opus/src/analysis.c new file mode 100644 index 0000000..cb46dec --- /dev/null +++ b/native/codec/libraries/opus/src/analysis.c @@ -0,0 +1,981 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define ANALYSIS_C + +#include + +#include "mathops.h" +#include "kiss_fft.h" +#include "celt.h" +#include "modes.h" +#include "arch.h" +#include "quant_bands.h" +#include "analysis.h" +#include "mlp.h" +#include "stack_alloc.h" +#include "float_cast.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifndef DISABLE_FLOAT_API + +#define TRANSITION_PENALTY 10 + +static const float dct_table[128] = { + 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, + 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, + 0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f, + -0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f, + 0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f, + -0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f, + 0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f, + 0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f, + 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f, + 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f, + 0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f, + -0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f, + 0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f, + -0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f, + 0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f, + 0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f, +}; + +static const float analysis_window[240] = { + 0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f, + 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f, + 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f, + 0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f, + 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f, + 0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f, + 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f, + 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f, + 0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f, + 0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f, + 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f, + 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f, + 0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f, + 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f, + 0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f, + 0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f, + 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f, + 0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f, + 0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f, + 0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f, + 0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f, + 0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f, + 0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f, + 0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f, + 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f, + 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f, + 0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f, + 0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f, + 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f, + 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f, +}; + +static const int tbands[NB_TBANDS+1] = { + 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 136, 160, 192, 240 +}; + +#define NB_TONAL_SKIP_BANDS 9 + +static opus_val32 silk_resampler_down2_hp( + opus_val32 *S, /* I/O State vector [ 2 ] */ + opus_val32 *out, /* O Output signal [ floor(len/2) ] */ + const opus_val32 *in, /* I Input signal [ len ] */ + int inLen /* I Number of input samples */ +) +{ + int k, len2 = inLen/2; + opus_val32 in32, out32, out32_hp, Y, X; + opus_val64 hp_ener = 0; + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = in[ 2 * k ]; + + /* All-pass section for even input sample */ + Y = SUB32( in32, S[ 0 ] ); + X = MULT16_32_Q15(QCONST16(0.6074371f, 15), Y); + out32 = ADD32( S[ 0 ], X ); + S[ 0 ] = ADD32( in32, X ); + out32_hp = out32; + /* Convert to Q10 */ + in32 = in[ 2 * k + 1 ]; + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = SUB32( in32, S[ 1 ] ); + X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y); + out32 = ADD32( out32, S[ 1 ] ); + out32 = ADD32( out32, X ); + S[ 1 ] = ADD32( in32, X ); + + Y = SUB32( -in32, S[ 2 ] ); + X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y); + out32_hp = ADD32( out32_hp, S[ 2 ] ); + out32_hp = ADD32( out32_hp, X ); + S[ 2 ] = ADD32( -in32, X ); + + hp_ener += out32_hp*(opus_val64)out32_hp; + /* Add, convert back to int16 and store to output */ + out[ k ] = HALF32(out32); + } +#ifdef FIXED_POINT + /* len2 can be up to 480, so we shift by 8 more to make it fit. */ + hp_ener = hp_ener >> (2*SIG_SHIFT + 8); +#endif + return (opus_val32)hp_ener; +} + +static opus_val32 downmix_and_resample(downmix_func downmix, const void *_x, opus_val32 *y, opus_val32 S[3], int subframe, int offset, int c1, int c2, int C, int Fs) +{ + VARDECL(opus_val32, tmp); + opus_val32 scale; + int j; + opus_val32 ret = 0; + SAVE_STACK; + + if (subframe==0) return 0; + if (Fs == 48000) + { + subframe *= 2; + offset *= 2; + } else if (Fs == 16000) { + subframe = subframe*2/3; + offset = offset*2/3; + } + ALLOC(tmp, subframe, opus_val32); + + downmix(_x, tmp, subframe, offset, c1, c2, C); +#ifdef FIXED_POINT + scale = (1<-1) + scale /= 2; + for (j=0;jarch = opus_select_arch(); + tonal->Fs = Fs; + /* Clear remaining fields. */ + tonality_analysis_reset(tonal); +} + +void tonality_analysis_reset(TonalityAnalysisState *tonal) +{ + /* Clear non-reusable fields. */ + char *start = (char*)&tonal->TONALITY_ANALYSIS_RESET_START; + OPUS_CLEAR(start, sizeof(TonalityAnalysisState) - (start - (char*)tonal)); +} + +void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len) +{ + int pos; + int curr_lookahead; + float tonality_max; + float tonality_avg; + int tonality_count; + int i; + int pos0; + float prob_avg; + float prob_count; + float prob_min, prob_max; + float vad_prob; + int mpos, vpos; + int bandwidth_span; + + pos = tonal->read_pos; + curr_lookahead = tonal->write_pos-tonal->read_pos; + if (curr_lookahead<0) + curr_lookahead += DETECT_SIZE; + + tonal->read_subframe += len/(tonal->Fs/400); + while (tonal->read_subframe>=8) + { + tonal->read_subframe -= 8; + tonal->read_pos++; + } + if (tonal->read_pos>=DETECT_SIZE) + tonal->read_pos-=DETECT_SIZE; + + /* On long frames, look at the second analysis window rather than the first. */ + if (len > tonal->Fs/50 && pos != tonal->write_pos) + { + pos++; + if (pos==DETECT_SIZE) + pos=0; + } + if (pos == tonal->write_pos) + pos--; + if (pos<0) + pos = DETECT_SIZE-1; + pos0 = pos; + OPUS_COPY(info_out, &tonal->info[pos], 1); + if (!info_out->valid) + return; + tonality_max = tonality_avg = info_out->tonality; + tonality_count = 1; + /* Look at the neighbouring frames and pick largest bandwidth found (to be safe). */ + bandwidth_span = 6; + /* If possible, look ahead for a tone to compensate for the delay in the tone detector. */ + for (i=0;i<3;i++) + { + pos++; + if (pos==DETECT_SIZE) + pos = 0; + if (pos == tonal->write_pos) + break; + tonality_max = MAX32(tonality_max, tonal->info[pos].tonality); + tonality_avg += tonal->info[pos].tonality; + tonality_count++; + info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth); + bandwidth_span--; + } + pos = pos0; + /* Look back in time to see if any has a wider bandwidth than the current frame. */ + for (i=0;iwrite_pos) + break; + info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth); + } + info_out->tonality = MAX32(tonality_avg/tonality_count, tonality_max-.2f); + + mpos = vpos = pos0; + /* If we have enough look-ahead, compensate for the ~5-frame delay in the music prob and + ~1 frame delay in the VAD prob. */ + if (curr_lookahead > 15) + { + mpos += 5; + if (mpos>=DETECT_SIZE) + mpos -= DETECT_SIZE; + vpos += 1; + if (vpos>=DETECT_SIZE) + vpos -= DETECT_SIZE; + } + + /* The following calculations attempt to minimize a "badness function" + for the transition. When switching from speech to music, the badness + of switching at frame k is + b_k = S*v_k + \sum_{i=0}^{k-1} v_i*(p_i - T) + where + v_i is the activity probability (VAD) at frame i, + p_i is the music probability at frame i + T is the probability threshold for switching + S is the penalty for switching during active audio rather than silence + the current frame has index i=0 + + Rather than apply badness to directly decide when to switch, what we compute + instead is the threshold for which the optimal switching point is now. When + considering whether to switch now (frame 0) or at frame k, we have: + S*v_0 = S*v_k + \sum_{i=0}^{k-1} v_i*(p_i - T) + which gives us: + T = ( \sum_{i=0}^{k-1} v_i*p_i + S*(v_k-v_0) ) / ( \sum_{i=0}^{k-1} v_i ) + We take the min threshold across all positive values of k (up to the maximum + amount of lookahead we have) to give us the threshold for which the current + frame is the optimal switch point. + + The last step is that we need to consider whether we want to switch at all. + For that we use the average of the music probability over the entire window. + If the threshold is higher than that average we're not going to + switch, so we compute a min with the average as well. The result of all these + min operations is music_prob_min, which gives the threshold for switching to music + if we're currently encoding for speech. + + We do the exact opposite to compute music_prob_max which is used for switching + from music to speech. + */ + prob_min = 1.f; + prob_max = 0.f; + vad_prob = tonal->info[vpos].activity_probability; + prob_count = MAX16(.1f, vad_prob); + prob_avg = MAX16(.1f, vad_prob)*tonal->info[mpos].music_prob; + while (1) + { + float pos_vad; + mpos++; + if (mpos==DETECT_SIZE) + mpos = 0; + if (mpos == tonal->write_pos) + break; + vpos++; + if (vpos==DETECT_SIZE) + vpos = 0; + if (vpos == tonal->write_pos) + break; + pos_vad = tonal->info[vpos].activity_probability; + prob_min = MIN16((prob_avg - TRANSITION_PENALTY*(vad_prob - pos_vad))/prob_count, prob_min); + prob_max = MAX16((prob_avg + TRANSITION_PENALTY*(vad_prob - pos_vad))/prob_count, prob_max); + prob_count += MAX16(.1f, pos_vad); + prob_avg += MAX16(.1f, pos_vad)*tonal->info[mpos].music_prob; + } + info_out->music_prob = prob_avg/prob_count; + prob_min = MIN16(prob_avg/prob_count, prob_min); + prob_max = MAX16(prob_avg/prob_count, prob_max); + prob_min = MAX16(prob_min, 0.f); + prob_max = MIN16(prob_max, 1.f); + + /* If we don't have enough look-ahead, do our best to make a decent decision. */ + if (curr_lookahead < 10) + { + float pmin, pmax; + pmin = prob_min; + pmax = prob_max; + pos = pos0; + /* Look for min/max in the past. */ + for (i=0;icount-1, 15);i++) + { + pos--; + if (pos < 0) + pos = DETECT_SIZE-1; + pmin = MIN16(pmin, tonal->info[pos].music_prob); + pmax = MAX16(pmax, tonal->info[pos].music_prob); + } + /* Bias against switching on active audio. */ + pmin = MAX16(0.f, pmin - .1f*vad_prob); + pmax = MIN16(1.f, pmax + .1f*vad_prob); + prob_min += (1.f-.1f*curr_lookahead)*(pmin - prob_min); + prob_max += (1.f-.1f*curr_lookahead)*(pmax - prob_max); + } + info_out->music_prob_min = prob_min; + info_out->music_prob_max = prob_max; + + /* printf("%f %f %f %f %f\n", prob_min, prob_max, prob_avg/prob_count, vad_prob, info_out->music_prob); */ +} + +static const float std_feature_bias[9] = { + 5.684947f, 3.475288f, 1.770634f, 1.599784f, 3.773215f, + 2.163313f, 1.260756f, 1.116868f, 1.918795f +}; + +#define LEAKAGE_OFFSET 2.5f +#define LEAKAGE_SLOPE 2.f + +#ifdef FIXED_POINT +/* For fixed-point, the input is +/-2^15 shifted up by SIG_SHIFT, so we need to + compensate for that in the energy. */ +#define SCALE_COMPENS (1.f/((opus_int32)1<<(15+SIG_SHIFT))) +#define SCALE_ENER(e) ((SCALE_COMPENS*SCALE_COMPENS)*(e)) +#else +#define SCALE_ENER(e) (e) +#endif + +#ifdef FIXED_POINT +static int is_digital_silence32(const opus_val32* pcm, int frame_size, int channels, int lsb_depth) +{ + int silence = 0; + opus_val32 sample_max = 0; +#ifdef MLP_TRAINING + return 0; +#endif + sample_max = celt_maxabs32(pcm, frame_size*channels); + + silence = (sample_max == 0); + (void)lsb_depth; + return silence; +} +#else +#define is_digital_silence32(pcm, frame_size, channels, lsb_depth) is_digital_silence(pcm, frame_size, channels, lsb_depth) +#endif + +static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix) +{ + int i, b; + const kiss_fft_state *kfft; + VARDECL(kiss_fft_cpx, in); + VARDECL(kiss_fft_cpx, out); + int N = 480, N2=240; + float * OPUS_RESTRICT A = tonal->angle; + float * OPUS_RESTRICT dA = tonal->d_angle; + float * OPUS_RESTRICT d2A = tonal->d2_angle; + VARDECL(float, tonality); + VARDECL(float, noisiness); + float band_tonality[NB_TBANDS]; + float logE[NB_TBANDS]; + float BFCC[8]; + float features[25]; + float frame_tonality; + float max_frame_tonality; + /*float tw_sum=0;*/ + float frame_noisiness; + const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI); + float slope=0; + float frame_stationarity; + float relativeE; + float frame_probs[2]; + float alpha, alphaE, alphaE2; + float frame_loudness; + float bandwidth_mask; + int is_masked[NB_TBANDS+1]; + int bandwidth=0; + float maxE = 0; + float noise_floor; + int remaining; + AnalysisInfo *info; + float hp_ener; + float tonality2[240]; + float midE[8]; + float spec_variability=0; + float band_log2[NB_TBANDS+1]; + float leakage_from[NB_TBANDS+1]; + float leakage_to[NB_TBANDS+1]; + float layer_out[MAX_NEURONS]; + float below_max_pitch; + float above_max_pitch; + int is_silence; + SAVE_STACK; + + if (!tonal->initialized) + { + tonal->mem_fill = 240; + tonal->initialized = 1; + } + alpha = 1.f/IMIN(10, 1+tonal->count); + alphaE = 1.f/IMIN(25, 1+tonal->count); + /* Noise floor related decay for bandwidth detection: -2.2 dB/second */ + alphaE2 = 1.f/IMIN(100, 1+tonal->count); + if (tonal->count <= 1) alphaE2 = 1; + + if (tonal->Fs == 48000) + { + /* len and offset are now at 24 kHz. */ + len/= 2; + offset /= 2; + } else if (tonal->Fs == 16000) { + len = 3*len/2; + offset = 3*offset/2; + } + + kfft = celt_mode->mdct.kfft[0]; + tonal->hp_ener_accum += (float)downmix_and_resample(downmix, x, + &tonal->inmem[tonal->mem_fill], tonal->downmix_state, + IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C, tonal->Fs); + if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE) + { + tonal->mem_fill += len; + /* Don't have enough to update the analysis */ + RESTORE_STACK; + return; + } + hp_ener = tonal->hp_ener_accum; + info = &tonal->info[tonal->write_pos++]; + if (tonal->write_pos>=DETECT_SIZE) + tonal->write_pos-=DETECT_SIZE; + + is_silence = is_digital_silence32(tonal->inmem, ANALYSIS_BUF_SIZE, 1, lsb_depth); + + ALLOC(in, 480, kiss_fft_cpx); + ALLOC(out, 480, kiss_fft_cpx); + ALLOC(tonality, 240, float); + ALLOC(noisiness, 240, float); + for (i=0;iinmem[i]); + in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]); + in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]); + in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]); + } + OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240); + remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill); + tonal->hp_ener_accum = (float)downmix_and_resample(downmix, x, + &tonal->inmem[240], tonal->downmix_state, remaining, + offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C, tonal->Fs); + tonal->mem_fill = 240 + remaining; + if (is_silence) + { + /* On silence, copy the previous analysis. */ + int prev_pos = tonal->write_pos-2; + if (prev_pos < 0) + prev_pos += DETECT_SIZE; + OPUS_COPY(info, &tonal->info[prev_pos], 1); + RESTORE_STACK; + return; + } + opus_fft(kfft, in, out, tonal->arch); +#ifndef FIXED_POINT + /* If there's any NaN on the input, the entire output will be NaN, so we only need to check one value. */ + if (celt_isnan(out[0].r)) + { + info->valid = 0; + RESTORE_STACK; + return; + } +#endif + + for (i=1;iactivity = 0; + frame_noisiness = 0; + frame_stationarity = 0; + if (!tonal->count) + { + for (b=0;blowE[b] = 1e10; + tonal->highE[b] = -1e10; + } + } + relativeE = 0; + frame_loudness = 0; + /* The energy of the very first band is special because of DC. */ + { + float E = 0; + float X1r, X2r; + X1r = 2*(float)out[0].r; + X2r = 2*(float)out[0].i; + E = X1r*X1r + X2r*X2r; + for (i=1;i<4;i++) + { + float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r + + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i; + E += binE; + } + E = SCALE_ENER(E); + band_log2[0] = .5f*1.442695f*(float)log(E+1e-10f); + } + for (b=0;bvalid = 0; + RESTORE_STACK; + return; + } +#endif + + tonal->E[tonal->E_count][b] = E; + frame_noisiness += nE/(1e-15f+E); + + frame_loudness += (float)sqrt(E+1e-10f); + logE[b] = (float)log(E+1e-10f); + band_log2[b+1] = .5f*1.442695f*(float)log(E+1e-10f); + tonal->logE[tonal->E_count][b] = logE[b]; + if (tonal->count==0) + tonal->highE[b] = tonal->lowE[b] = logE[b]; + if (tonal->highE[b] > tonal->lowE[b] + 7.5) + { + if (tonal->highE[b] - logE[b] > logE[b] - tonal->lowE[b]) + tonal->highE[b] -= .01f; + else + tonal->lowE[b] += .01f; + } + if (logE[b] > tonal->highE[b]) + { + tonal->highE[b] = logE[b]; + tonal->lowE[b] = MAX32(tonal->highE[b]-15, tonal->lowE[b]); + } else if (logE[b] < tonal->lowE[b]) + { + tonal->lowE[b] = logE[b]; + tonal->highE[b] = MIN32(tonal->lowE[b]+15, tonal->highE[b]); + } + relativeE += (logE[b]-tonal->lowE[b])/(1e-5f + (tonal->highE[b]-tonal->lowE[b])); + + L1=L2=0; + for (i=0;iE[i][b]); + L2 += tonal->E[i][b]; + } + + stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2)); + stationarity *= stationarity; + stationarity *= stationarity; + frame_stationarity += stationarity; + /*band_tonality[b] = tE/(1e-15+E)*/; + band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]); +#if 0 + if (b>=NB_TONAL_SKIP_BANDS) + { + frame_tonality += tweight[b]*band_tonality[b]; + tw_sum += tweight[b]; + } +#else + frame_tonality += band_tonality[b]; + if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS) + frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS]; +#endif + max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality); + slope += band_tonality[b]*(b-8); + /*printf("%f %f ", band_tonality[b], stationarity);*/ + tonal->prev_band_tonality[b] = band_tonality[b]; + } + + leakage_from[0] = band_log2[0]; + leakage_to[0] = band_log2[0] - LEAKAGE_OFFSET; + for (b=1;b=0;b--) + { + float leak_slope = LEAKAGE_SLOPE*(tbands[b+1]-tbands[b])/4; + leakage_from[b] = MIN16(leakage_from[b+1]+leak_slope, leakage_from[b]); + leakage_to[b] = MAX16(leakage_to[b+1]-leak_slope, leakage_to[b]); + } + celt_assert(NB_TBANDS+1 <= LEAK_BANDS); + for (b=0;bleak_boost[b] = IMIN(255, (int)floor(.5 + 64.f*boost)); + } + for (;bleak_boost[b] = 0; + + for (i=0;ilogE[i][k] - tonal->logE[j][k]; + dist += tmp*tmp; + } + if (j!=i) + mindist = MIN32(mindist, dist); + } + spec_variability += mindist; + } + spec_variability = (float)sqrt(spec_variability/NB_FRAMES/NB_TBANDS); + bandwidth_mask = 0; + bandwidth = 0; + maxE = 0; + noise_floor = 5.7e-4f/(1<<(IMAX(0,lsb_depth-8))); + noise_floor *= noise_floor; + below_max_pitch=0; + above_max_pitch=0; + for (b=0;bmeanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E); + Em = MAX32(E, tonal->meanE[b]); + /* Consider the band "active" only if all these conditions are met: + 1) less than 90 dB below the peak band (maximal masking possible considering + both the ATH and the loudness-dependent slope of the spreading function) + 2) above the PCM quantization noise floor + We use b+1 because the first CELT band isn't included in tbands[] + */ + if (E*1e9f > maxE && (Em > 3*noise_floor*(band_end-band_start) || E > noise_floor*(band_end-band_start))) + bandwidth = b+1; + /* Check if the band is masked (see below). */ + is_masked[b] = E < (tonal->prev_bandwidth >= b+1 ? .01f : .05f)*bandwidth_mask; + /* Use a simple follower with 13 dB/Bark slope for spreading function. */ + bandwidth_mask = MAX32(.05f*bandwidth_mask, E); + } + /* Special case for the last two bands, for which we don't have spectrum but only + the energy above 12 kHz. The difficulty here is that the high-pass we use + leaks some LF energy, so we need to increase the threshold without accidentally cutting + off the band. */ + if (tonal->Fs == 48000) { + float noise_ratio; + float Em; + float E = hp_ener*(1.f/(60*60)); + noise_ratio = tonal->prev_bandwidth==20 ? 10.f : 30.f; + +#ifdef FIXED_POINT + /* silk_resampler_down2_hp() shifted right by an extra 8 bits. */ + E *= 256.f*(1.f/Q15ONE)*(1.f/Q15ONE); +#endif + above_max_pitch += E; + tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E); + Em = MAX32(E, tonal->meanE[b]); + if (Em > 3*noise_ratio*noise_floor*160 || E > noise_ratio*noise_floor*160) + bandwidth = 20; + /* Check if the band is masked (see below). */ + is_masked[b] = E < (tonal->prev_bandwidth == 20 ? .01f : .05f)*bandwidth_mask; + } + if (above_max_pitch > below_max_pitch) + info->max_pitch_ratio = below_max_pitch/above_max_pitch; + else + info->max_pitch_ratio = 1; + /* In some cases, resampling aliasing can create a small amount of energy in the first band + being cut. So if the last band is masked, we don't include it. */ + if (bandwidth == 20 && is_masked[NB_TBANDS]) + bandwidth-=2; + else if (bandwidth > 0 && bandwidth <= NB_TBANDS && is_masked[bandwidth-1]) + bandwidth--; + if (tonal->count<=2) + bandwidth = 20; + frame_loudness = 20*(float)log10(frame_loudness); + tonal->Etracker = MAX32(tonal->Etracker-.003f, frame_loudness); + tonal->lowECount *= (1-alphaE); + if (frame_loudness < tonal->Etracker-30) + tonal->lowECount += alphaE; + + for (i=0;i<8;i++) + { + float sum=0; + for (b=0;b<16;b++) + sum += dct_table[i*16+b]*logE[b]; + BFCC[i] = sum; + } + for (i=0;i<8;i++) + { + float sum=0; + for (b=0;b<16;b++) + sum += dct_table[i*16+b]*.5f*(tonal->highE[b]+tonal->lowE[b]); + midE[i] = sum; + } + + frame_stationarity /= NB_TBANDS; + relativeE /= NB_TBANDS; + if (tonal->count<10) + relativeE = .5f; + frame_noisiness /= NB_TBANDS; +#if 1 + info->activity = frame_noisiness + (1-frame_noisiness)*relativeE; +#else + info->activity = .5*(1+frame_noisiness-frame_stationarity); +#endif + frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS)); + frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f); + tonal->prev_tonality = frame_tonality; + + slope /= 8*8; + info->tonality_slope = slope; + + tonal->E_count = (tonal->E_count+1)%NB_FRAMES; + tonal->count = IMIN(tonal->count+1, ANALYSIS_COUNT_MAX); + info->tonality = frame_tonality; + + for (i=0;i<4;i++) + features[i] = -0.12299f*(BFCC[i]+tonal->mem[i+24]) + 0.49195f*(tonal->mem[i]+tonal->mem[i+16]) + 0.69693f*tonal->mem[i+8] - 1.4349f*tonal->cmean[i]; + + for (i=0;i<4;i++) + tonal->cmean[i] = (1-alpha)*tonal->cmean[i] + alpha*BFCC[i]; + + for (i=0;i<4;i++) + features[4+i] = 0.63246f*(BFCC[i]-tonal->mem[i+24]) + 0.31623f*(tonal->mem[i]-tonal->mem[i+16]); + for (i=0;i<3;i++) + features[8+i] = 0.53452f*(BFCC[i]+tonal->mem[i+24]) - 0.26726f*(tonal->mem[i]+tonal->mem[i+16]) -0.53452f*tonal->mem[i+8]; + + if (tonal->count > 5) + { + for (i=0;i<9;i++) + tonal->std[i] = (1-alpha)*tonal->std[i] + alpha*features[i]*features[i]; + } + for (i=0;i<4;i++) + features[i] = BFCC[i]-midE[i]; + + for (i=0;i<8;i++) + { + tonal->mem[i+24] = tonal->mem[i+16]; + tonal->mem[i+16] = tonal->mem[i+8]; + tonal->mem[i+8] = tonal->mem[i]; + tonal->mem[i] = BFCC[i]; + } + for (i=0;i<9;i++) + features[11+i] = (float)sqrt(tonal->std[i]) - std_feature_bias[i]; + features[18] = spec_variability - 0.78f; + features[20] = info->tonality - 0.154723f; + features[21] = info->activity - 0.724643f; + features[22] = frame_stationarity - 0.743717f; + features[23] = info->tonality_slope + 0.069216f; + features[24] = tonal->lowECount - 0.067930f; + + compute_dense(&layer0, layer_out, features); + compute_gru(&layer1, tonal->rnn_state, layer_out); + compute_dense(&layer2, frame_probs, tonal->rnn_state); + + /* Probability of speech or music vs noise */ + info->activity_probability = frame_probs[1]; + info->music_prob = frame_probs[0]; + + /*printf("%f %f %f\n", frame_probs[0], frame_probs[1], info->music_prob);*/ +#ifdef MLP_TRAINING + for (i=0;i<25;i++) + printf("%f ", features[i]); + printf("\n"); +#endif + + info->bandwidth = bandwidth; + tonal->prev_bandwidth = bandwidth; + /*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/ + info->noisiness = frame_noisiness; + info->valid = 1; + RESTORE_STACK; +} + +void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm, + int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs, + int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info) +{ + int offset; + int pcm_len; + + analysis_frame_size -= analysis_frame_size&1; + if (analysis_pcm != NULL) + { + /* Avoid overflow/wrap-around of the analysis buffer */ + analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/50, analysis_frame_size); + + pcm_len = analysis_frame_size - analysis->analysis_offset; + offset = analysis->analysis_offset; + while (pcm_len>0) { + tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(Fs/50, pcm_len), offset, c1, c2, C, lsb_depth, downmix); + offset += Fs/50; + pcm_len -= Fs/50; + } + analysis->analysis_offset = analysis_frame_size; + + analysis->analysis_offset -= frame_size; + } + + tonality_get_info(analysis, analysis_info, frame_size); +} + +#endif /* DISABLE_FLOAT_API */ diff --git a/native/codec/libraries/opus/src/analysis.h b/native/codec/libraries/opus/src/analysis.h new file mode 100644 index 0000000..0b66555 --- /dev/null +++ b/native/codec/libraries/opus/src/analysis.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ANALYSIS_H +#define ANALYSIS_H + +#include "celt.h" +#include "opus_private.h" +#include "mlp.h" + +#define NB_FRAMES 8 +#define NB_TBANDS 18 +#define ANALYSIS_BUF_SIZE 720 /* 30 ms at 24 kHz */ + +/* At that point we can stop counting frames because it no longer matters. */ +#define ANALYSIS_COUNT_MAX 10000 + +#define DETECT_SIZE 100 + +/* Uncomment this to print the MLP features on stdout. */ +/*#define MLP_TRAINING*/ + +typedef struct { + int arch; + int application; + opus_int32 Fs; +#define TONALITY_ANALYSIS_RESET_START angle + float angle[240]; + float d_angle[240]; + float d2_angle[240]; + opus_val32 inmem[ANALYSIS_BUF_SIZE]; + int mem_fill; /* number of usable samples in the buffer */ + float prev_band_tonality[NB_TBANDS]; + float prev_tonality; + int prev_bandwidth; + float E[NB_FRAMES][NB_TBANDS]; + float logE[NB_FRAMES][NB_TBANDS]; + float lowE[NB_TBANDS]; + float highE[NB_TBANDS]; + float meanE[NB_TBANDS+1]; + float mem[32]; + float cmean[8]; + float std[9]; + float Etracker; + float lowECount; + int E_count; + int count; + int analysis_offset; + int write_pos; + int read_pos; + int read_subframe; + float hp_ener_accum; + int initialized; + float rnn_state[MAX_NEURONS]; + opus_val32 downmix_state[3]; + AnalysisInfo info[DETECT_SIZE]; +} TonalityAnalysisState; + +/** Initialize a TonalityAnalysisState struct. + * + * This performs some possibly slow initialization steps which should + * not be repeated every analysis step. No allocated memory is retained + * by the state struct, so no cleanup call is required. + */ +void tonality_analysis_init(TonalityAnalysisState *analysis, opus_int32 Fs); + +/** Reset a TonalityAnalysisState stuct. + * + * Call this when there's a discontinuity in the data. + */ +void tonality_analysis_reset(TonalityAnalysisState *analysis); + +void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len); + +void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm, + int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs, + int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info); + +#endif diff --git a/native/codec/libraries/opus/src/mapping_matrix.c b/native/codec/libraries/opus/src/mapping_matrix.c new file mode 100644 index 0000000..31298af --- /dev/null +++ b/native/codec/libraries/opus/src/mapping_matrix.c @@ -0,0 +1,378 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include "float_cast.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "mapping_matrix.h" + +#define MATRIX_INDEX(nb_rows, row, col) (nb_rows * col + row) + +opus_int32 mapping_matrix_get_size(int rows, int cols) +{ + opus_int32 size; + + /* Mapping Matrix must only support up to 255 channels in or out. + * Additionally, the total cell count must be <= 65004 octets in order + * for the matrix to be stored in an OGG header. + */ + if (rows > 255 || cols > 255) + return 0; + size = rows * (opus_int32)cols * sizeof(opus_int16); + if (size > 65004) + return 0; + + return align(sizeof(MappingMatrix)) + align(size); +} + +opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (opus_int16*)(void*)((char*)matrix + align(sizeof(MappingMatrix))); +} + +void mapping_matrix_init(MappingMatrix * const matrix, + int rows, int cols, int gain, const opus_int16 *data, opus_int32 data_size) +{ + int i; + opus_int16 *ptr; + +#if !defined(ENABLE_ASSERTIONS) + (void)data_size; +#endif + celt_assert(align(data_size) == align(rows * cols * sizeof(opus_int16))); + + matrix->rows = rows; + matrix->cols = cols; + matrix->gain = gain; + ptr = mapping_matrix_get_data(matrix); + for (i = 0; i < rows * cols; i++) + { + ptr[i] = data[i]; + } +} + +#ifndef DISABLE_FLOAT_API +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, col; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { + float tmp = 0; + for (col = 0; col < input_rows; col++) + { + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; + } +#if defined(FIXED_POINT) + output[output_rows * i] = FLOAT2INT16((1/32768.f)*tmp); +#else + output[output_rows * i] = (1/32768.f)*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + float input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (1/32768.f)*input[input_rows * i]; +#else + input_sample = input[input_rows * i]; +#endif + for (row = 0; row < output_rows; row++) + { + float tmp = + (1/32768.f)*matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += tmp; + } + } +} +#endif /* DISABLE_FLOAT_API */ + +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, col; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { + opus_val32 tmp = 0; + for (col = 0; col < input_rows; col++) + { +#if defined(FIXED_POINT) + tmp += + ((opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + (opus_int32)input[MATRIX_INDEX(input_rows, col, i)]) >> 8; +#else + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; +#endif + } +#if defined(FIXED_POINT) + output[output_rows * i] = (opus_int16)((tmp + 64) >> 7); +#else + output[output_rows * i] = (1/(32768.f*32768.f))*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + opus_int32 input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (opus_int32)input[input_rows * i]; +#else + input_sample = (opus_int32)FLOAT2INT16(input[input_rows * i]); +#endif + for (row = 0; row < output_rows; row++) + { + opus_int32 tmp = + (opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15; + } + } +} + +const MappingMatrix mapping_matrix_foa_mixing = { 6, 6, 0 }; +const opus_int16 mapping_matrix_foa_mixing_data[36] = { + 16384, 0, -16384, 23170, 0, 0, 16384, 23170, + 16384, 0, 0, 0, 16384, 0, -16384, -23170, + 0, 0, 16384, -23170, 16384, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_soa_mixing = { 11, 11, 0 }; +const opus_int16 mapping_matrix_soa_mixing_data[121] = { + 10923, 7723, 13377, -13377, 11585, 9459, 7723, -16384, + -6689, 0, 0, 10923, 7723, 13377, 13377, -11585, + 9459, 7723, 16384, -6689, 0, 0, 10923, -15447, + 13377, 0, 0, -18919, 7723, 0, 13377, 0, + 0, 10923, 7723, -13377, -13377, 11585, -9459, 7723, + 16384, -6689, 0, 0, 10923, -7723, 0, 13377, + -16384, 0, -15447, 0, 9459, 0, 0, 10923, + -7723, 0, -13377, 16384, 0, -15447, 0, 9459, + 0, 0, 10923, 15447, 0, 0, 0, 0, + -15447, 0, -18919, 0, 0, 10923, 7723, -13377, + 13377, -11585, -9459, 7723, -16384, -6689, 0, 0, + 10923, -15447, -13377, 0, 0, 18919, 7723, 0, + 13377, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767 +}; + +const MappingMatrix mapping_matrix_toa_mixing = { 18, 18, 0 }; +const opus_int16 mapping_matrix_toa_mixing_data[324] = { + 8208, 0, -881, 14369, 0, 0, -8192, -4163, + 13218, 0, 0, 0, 11095, -8836, -6218, 14833, + 0, 0, 8208, -10161, 881, 10161, -13218, -2944, + -8192, 2944, 0, -10488, -6218, 6248, -11095, -6248, + 0, -10488, 0, 0, 8208, 10161, 881, -10161, + -13218, 2944, -8192, -2944, 0, 10488, -6218, -6248, + -11095, 6248, 0, 10488, 0, 0, 8176, 5566, + -11552, 5566, 9681, -11205, 8192, -11205, 0, 4920, + -15158, 9756, -3334, 9756, 0, -4920, 0, 0, + 8176, 7871, 11552, 0, 0, 15846, 8192, 0, + -9681, -6958, 0, 13797, 3334, 0, -15158, 0, + 0, 0, 8176, 0, 11552, 7871, 0, 0, + 8192, 15846, 9681, 0, 0, 0, 3334, 13797, + 15158, 6958, 0, 0, 8176, 5566, -11552, -5566, + -9681, -11205, 8192, 11205, 0, 4920, 15158, 9756, + -3334, -9756, 0, 4920, 0, 0, 8208, 14369, + -881, 0, 0, -4163, -8192, 0, -13218, -14833, + 0, -8836, 11095, 0, 6218, 0, 0, 0, + 8208, 10161, 881, 10161, 13218, 2944, -8192, 2944, + 0, 10488, 6218, -6248, -11095, -6248, 0, -10488, + 0, 0, 8208, -14369, -881, 0, 0, 4163, + -8192, 0, -13218, 14833, 0, 8836, 11095, 0, + 6218, 0, 0, 0, 8208, 0, -881, -14369, + 0, 0, -8192, 4163, 13218, 0, 0, 0, + 11095, 8836, -6218, -14833, 0, 0, 8176, -5566, + -11552, 5566, -9681, 11205, 8192, -11205, 0, -4920, + 15158, -9756, -3334, 9756, 0, -4920, 0, 0, + 8176, 0, 11552, -7871, 0, 0, 8192, -15846, + 9681, 0, 0, 0, 3334, -13797, 15158, -6958, + 0, 0, 8176, -7871, 11552, 0, 0, -15846, + 8192, 0, -9681, 6958, 0, -13797, 3334, 0, + -15158, 0, 0, 0, 8176, -5566, -11552, -5566, + 9681, 11205, 8192, 11205, 0, -4920, -15158, -9756, + -3334, -9756, 0, 4920, 0, 0, 8208, -10161, + 881, -10161, 13218, -2944, -8192, -2944, 0, -10488, + 6218, 6248, -11095, 6248, 0, 10488, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_foa_demixing = { 6, 6, 0 }; +const opus_int16 mapping_matrix_foa_demixing_data[36] = { + 16384, 16384, 16384, 16384, 0, 0, 0, 23170, + 0, -23170, 0, 0, -16384, 16384, -16384, 16384, + 0, 0, 23170, 0, -23170, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_soa_demixing = { 11, 11, 3050 }; +const opus_int16 mapping_matrix_soa_demixing_data[121] = { + 2771, 2771, 2771, 2771, 2771, 2771, 2771, 2771, + 2771, 0, 0, 10033, 10033, -20066, 10033, 14189, + 14189, -28378, 10033, -20066, 0, 0, 3393, 3393, + 3393, -3393, 0, 0, 0, -3393, -3393, 0, + 0, -17378, 17378, 0, -17378, -24576, 24576, 0, + 17378, 0, 0, 0, -14189, 14189, 0, -14189, + -28378, 28378, 0, 14189, 0, 0, 0, 2399, + 2399, -4799, -2399, 0, 0, 0, -2399, 4799, + 0, 0, 1959, 1959, 1959, 1959, -3918, -3918, + -3918, 1959, 1959, 0, 0, -4156, 4156, 0, + 4156, 0, 0, 0, -4156, 0, 0, 0, + 8192, 8192, -16384, 8192, 16384, 16384, -32768, 8192, + -16384, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8312, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8312 +}; + +const MappingMatrix mapping_matrix_toa_demixing = { 18, 18, 0 }; +const opus_int16 mapping_matrix_toa_demixing_data[324] = { + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 0, 0, 0, -9779, 9779, 6263, 8857, 0, + 6263, 13829, 9779, -13829, 0, -6263, 0, -8857, + -6263, -9779, 0, 0, -3413, 3413, 3413, -11359, + 11359, 11359, -11359, -3413, 3413, -3413, -3413, -11359, + 11359, 11359, -11359, 3413, 0, 0, 13829, 9779, + -9779, 6263, 0, 8857, -6263, 0, 9779, 0, + -13829, 6263, -8857, 0, -6263, -9779, 0, 0, + 0, -15617, -15617, 6406, 0, 0, -6406, 0, + 15617, 0, 0, -6406, 0, 0, 6406, 15617, + 0, 0, 0, -5003, 5003, -10664, 15081, 0, + -10664, -7075, 5003, 7075, 0, 10664, 0, -15081, + 10664, -5003, 0, 0, -8176, -8176, -8176, 8208, + 8208, 8208, 8208, -8176, -8176, -8176, -8176, 8208, + 8208, 8208, 8208, -8176, 0, 0, -7075, 5003, + -5003, -10664, 0, 15081, 10664, 0, 5003, 0, + 7075, -10664, -15081, 0, 10664, -5003, 0, 0, + 15617, 0, 0, 0, -6406, 6406, 0, -15617, + 0, -15617, 15617, 0, 6406, -6406, 0, 0, + 0, 0, 0, -11393, 11393, 2993, -4233, 0, + 2993, -16112, 11393, 16112, 0, -2993, 0, 4233, + -2993, -11393, 0, 0, 0, -9974, -9974, -13617, + 0, 0, 13617, 0, 9974, 0, 0, 13617, + 0, 0, -13617, 9974, 0, 0, 0, 5579, + -5579, 10185, 14403, 0, 10185, -7890, -5579, 7890, + 0, -10185, 0, -14403, -10185, 5579, 0, 0, + 11826, -11826, -11826, -901, 901, 901, -901, 11826, + -11826, 11826, 11826, -901, 901, 901, -901, -11826, + 0, 0, -7890, -5579, 5579, 10185, 0, 14403, + -10185, 0, -5579, 0, 7890, 10185, -14403, 0, + -10185, 5579, 0, 0, -9974, 0, 0, 0, + -13617, 13617, 0, 9974, 0, 9974, -9974, 0, + 13617, -13617, 0, 0, 0, 0, 16112, -11393, + 11393, -2993, 0, 4233, 2993, 0, -11393, 0, + -16112, -2993, -4233, 0, 2993, 11393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767 +}; + diff --git a/native/codec/libraries/opus/src/mapping_matrix.h b/native/codec/libraries/opus/src/mapping_matrix.h new file mode 100644 index 0000000..98bc82d --- /dev/null +++ b/native/codec/libraries/opus/src/mapping_matrix.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file mapping_matrix.h + * @brief Opus reference implementation mapping matrix API + */ + +#ifndef MAPPING_MATRIX_H +#define MAPPING_MATRIX_H + +#include "opus_types.h" +#include "opus_projection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MappingMatrix +{ + int rows; /* number of channels outputted from matrix. */ + int cols; /* number of channels inputted to matrix. */ + int gain; /* in dB. S7.8-format. */ + /* Matrix cell data goes here using col-wise ordering. */ +} MappingMatrix; + +opus_int32 mapping_matrix_get_size(int rows, int cols); + +opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix); + +void mapping_matrix_init( + MappingMatrix * const matrix, + int rows, + int cols, + int gain, + const opus_int16 *data, + opus_int32 data_size +); + +#ifndef DISABLE_FLOAT_API +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +); +#endif /* DISABLE_FLOAT_API */ + +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size +); + +/* Pre-computed mixing and demixing matrices for 1st to 3rd-order ambisonics. + * foa: first-order ambisonics + * soa: second-order ambisonics + * toa: third-order ambisonics + */ +extern const MappingMatrix mapping_matrix_foa_mixing; +extern const opus_int16 mapping_matrix_foa_mixing_data[36]; + +extern const MappingMatrix mapping_matrix_soa_mixing; +extern const opus_int16 mapping_matrix_soa_mixing_data[121]; + +extern const MappingMatrix mapping_matrix_toa_mixing; +extern const opus_int16 mapping_matrix_toa_mixing_data[324]; + +extern const MappingMatrix mapping_matrix_foa_demixing; +extern const opus_int16 mapping_matrix_foa_demixing_data[36]; + +extern const MappingMatrix mapping_matrix_soa_demixing; +extern const opus_int16 mapping_matrix_soa_demixing_data[121]; + +extern const MappingMatrix mapping_matrix_toa_demixing; +extern const opus_int16 mapping_matrix_toa_demixing_data[324]; + +#ifdef __cplusplus +} +#endif + +#endif /* MAPPING_MATRIX_H */ diff --git a/native/codec/libraries/opus/src/mlp.c b/native/codec/libraries/opus/src/mlp.c new file mode 100644 index 0000000..964c6a9 --- /dev/null +++ b/native/codec/libraries/opus/src/mlp.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2008-2011 Octasic Inc. + 2012-2017 Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "opus_types.h" +#include "opus_defines.h" +#include "arch.h" +#include "tansig_table.h" +#include "mlp.h" + +static OPUS_INLINE float tansig_approx(float x) +{ + int i; + float y, dy; + float sign=1; + /* Tests are reversed to catch NaNs */ + if (!(x<8)) + return 1; + if (!(x>-8)) + return -1; +#ifndef FIXED_POINT + /* Another check in case of -ffast-math */ + if (celt_isnan(x)) + return 0; +#endif + if (x<0) + { + x=-x; + sign=-1; + } + i = (int)floor(.5f+25*x); + x -= .04f*i; + y = tansig_table[i]; + dy = 1-y*y; + y = y + x*dy*(1 - y*x); + return sign*y; +} + +static OPUS_INLINE float sigmoid_approx(float x) +{ + return .5f + .5f*tansig_approx(.5f*x); +} + +static void gemm_accum(float *out, const opus_int8 *weights, int rows, int cols, int col_stride, const float *x) +{ + int i, j; + for (i=0;inb_inputs; + N = layer->nb_neurons; + stride = N; + for (i=0;ibias[i]; + gemm_accum(output, layer->input_weights, N, M, stride, input); + for (i=0;isigmoid) { + for (i=0;inb_inputs; + N = gru->nb_neurons; + stride = 3*N; + /* Compute update gate. */ + for (i=0;ibias[i]; + gemm_accum(z, gru->input_weights, N, M, stride, input); + gemm_accum(z, gru->recurrent_weights, N, N, stride, state); + for (i=0;ibias[N + i]; + gemm_accum(r, &gru->input_weights[N], N, M, stride, input); + gemm_accum(r, &gru->recurrent_weights[N], N, N, stride, state); + for (i=0;ibias[2*N + i]; + for (i=0;iinput_weights[2*N], N, M, stride, input); + gemm_accum(h, &gru->recurrent_weights[2*N], N, N, stride, tmp); + for (i=0;i=0) + break; + x[i*C] = x[i*C]+a*x[i*C]*x[i*C]; + } + + curr=0; + x0 = x[0]; + while(1) + { + int start, end; + float maxval; + int special=0; + int peak_pos; + for (i=curr;i1 || x[i*C]<-1) + break; + } + if (i==N) + { + a=0; + break; + } + peak_pos = i; + start=end=i; + maxval=ABS16(x[i*C]); + /* Look for first zero crossing before clipping */ + while (start>0 && x[i*C]*x[(start-1)*C]>=0) + start--; + /* Look for first zero crossing after clipping */ + while (end=0) + { + /* Look for other peaks until the next zero-crossing. */ + if (ABS16(x[end*C])>maxval) + { + maxval = ABS16(x[end*C]); + peak_pos = end; + } + end++; + } + /* Detect the special case where we clip before the first zero crossing */ + special = (start==0 && x[i*C]*x[0]>=0); + + /* Compute a such that maxval + a*maxval^2 = 1 */ + a=(maxval-1)/(maxval*maxval); + /* Slightly boost "a" by 2^-22. This is just enough to ensure -ffast-math + does not cause output values larger than +/-1, but small enough not + to matter even for 24-bit output. */ + a += a*2.4e-7f; + if (x[i*C]>0) + a = -a; + /* Apply soft clipping */ + for (i=start;i=2) + { + /* Add a linear ramp from the first sample to the signal peak. + This avoids a discontinuity at the beginning of the frame. */ + float delta; + float offset = x0-x[0]; + delta = offset / peak_pos; + for (i=curr;i>2; + return 2; + } +} + +static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size) +{ + if (len<1) + { + *size = -1; + return -1; + } else if (data[0]<252) + { + *size = data[0]; + return 1; + } else if (len<2) + { + *size = -1; + return -1; + } else { + *size = 4*data[1] + data[0]; + return 2; + } +} + +int opus_packet_get_samples_per_frame(const unsigned char *data, + opus_int32 Fs) +{ + int audiosize; + if (data[0]&0x80) + { + audiosize = ((data[0]>>3)&0x3); + audiosize = (Fs<>3)&0x3); + if (audiosize == 3) + audiosize = Fs*60/1000; + else + audiosize = (Fs< len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size = len-size[0]; + break; + /* Multiple CBR/VBR frames (from 0 to 120 ms) */ + default: /*case 3:*/ + if (len<1) + return OPUS_INVALID_PACKET; + /* Number of frames encoded in bits 0 to 5 */ + ch = *data++; + count = ch&0x3F; + if (count <= 0 || framesize*(opus_int32)count > 5760) + return OPUS_INVALID_PACKET; + len--; + /* Padding flag is bit 6 */ + if (ch&0x40) + { + int p; + do { + int tmp; + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; + tmp = p==255 ? 254: p; + len -= tmp; + pad += tmp; + } while (p==255); + } + if (len<0) + return OPUS_INVALID_PACKET; + /* VBR flag is bit 7 */ + cbr = !(ch&0x80); + if (!cbr) + { + /* VBR case */ + last_size = len; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size -= bytes+size[i]; + } + if (last_size<0) + return OPUS_INVALID_PACKET; + } else if (!self_delimited) + { + /* CBR case */ + last_size = len/count; + if (last_size*count!=len) + return OPUS_INVALID_PACKET; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + /* For CBR packets, apply the size to all the frames. */ + if (cbr) + { + if (size[count-1]*count > len) + return OPUS_INVALID_PACKET; + for (i=0;i last_size) + return OPUS_INVALID_PACKET; + } else + { + /* Because it's not encoded explicitly, it's possible the size of the + last packet (or all the packets, for the CBR case) is larger than + 1275. Reject them here.*/ + if (last_size > 1275) + return OPUS_INVALID_PACKET; + size[count-1] = (opus_int16)last_size; + } + + if (payload_offset) + *payload_offset = (int)(data-data0); + + for (i=0;i +#include +#include +#include + +#define OPUS_PI (3.14159265F) + +#define OPUS_COSF(_x) ((float)cos(_x)) +#define OPUS_SINF(_x) ((float)sin(_x)) + +static void *check_alloc(void *_ptr){ + if(_ptr==NULL){ + fprintf(stderr,"Out of memory.\n"); + exit(EXIT_FAILURE); + } + return _ptr; +} + +static void *opus_malloc(size_t _size){ + return check_alloc(malloc(_size)); +} + +static void *opus_realloc(void *_ptr,size_t _size){ + return check_alloc(realloc(_ptr,_size)); +} + +static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){ + unsigned char buf[1024]; + float *samples; + size_t nsamples; + size_t csamples; + size_t xi; + size_t nread; + samples=NULL; + nsamples=csamples=0; + for(;;){ + nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin); + if(nread<=0)break; + if(nsamples+nread>csamples){ + do csamples=csamples<<1|1; + while(nsamples+nread>csamples); + samples=(float *)opus_realloc(samples, + _nchannels*csamples*sizeof(*samples)); + } + for(xi=0;xi=_window_sz)ti-=_window_sz; + } + re*=_downsample; + im*=_downsample; + _ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000; + p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci]; + } + } + if(_out){ + _out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]); + if(_nchannels==2){ + _out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]); + } + } + } + } + free(window); +} + +#define NBANDS (21) +#define NFREQS (240) + +/*Bands on which we compute the pseudo-NMR (Bark-derived + CELT bands).*/ +static const int BANDS[NBANDS+1]={ + 0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200 +}; + +#define TEST_WIN_SIZE (480) +#define TEST_WIN_STEP (120) + +int main(int _argc,const char **_argv){ + FILE *fin1; + FILE *fin2; + float *x; + float *y; + float *xb; + float *X; + float *Y; + double err; + float Q; + size_t xlength; + size_t ylength; + size_t nframes; + size_t xi; + int ci; + int xj; + int bi; + int nchannels; + unsigned rate; + int downsample; + int ybands; + int yfreqs; + int max_compare; + if(_argc<3||_argc>6){ + fprintf(stderr,"Usage: %s [-s] [-r rate2] \n", + _argv[0]); + return EXIT_FAILURE; + } + nchannels=1; + if(strcmp(_argv[1],"-s")==0){ + nchannels=2; + _argv++; + } + rate=48000; + ybands=NBANDS; + yfreqs=NFREQS; + downsample=1; + if(strcmp(_argv[1],"-r")==0){ + rate=atoi(_argv[2]); + if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){ + fprintf(stderr, + "Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n"); + return EXIT_FAILURE; + } + downsample=48000/rate; + switch(rate){ + case 8000:ybands=13;break; + case 12000:ybands=15;break; + case 16000:ybands=17;break; + case 24000:ybands=19;break; + } + yfreqs=NFREQS/downsample; + _argv+=2; + } + fin1=fopen(_argv[1],"rb"); + if(fin1==NULL){ + fprintf(stderr,"Error opening '%s'.\n",_argv[1]); + return EXIT_FAILURE; + } + fin2=fopen(_argv[2],"rb"); + if(fin2==NULL){ + fprintf(stderr,"Error opening '%s'.\n",_argv[2]); + fclose(fin1); + return EXIT_FAILURE; + } + /*Read in the data and allocate scratch space.*/ + xlength=read_pcm16(&x,fin1,2); + if(nchannels==1){ + for(xi=0;xi0;){ + for(ci=0;ci0){ + /*Temporal masking: -3 dB/2.5ms slope.*/ + for(bi=0;bi=79&&xj<=81)im*=0.1F; + if(xj==80)im*=0.1F; + Eb+=im; + } + } + Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels; + Ef += Eb*Eb; + } + /*Using a fixed normalization value means we're willing to accept slightly + lower quality for lower sampling rates.*/ + Ef/=NBANDS; + Ef*=Ef; + err+=Ef*Ef; + } + free(xb); + free(X); + free(Y); + err=pow(err/nframes,1.0/16); + Q=100*(1-0.5*log(1+err)/log(1.13)); + if(Q<0){ + fprintf(stderr,"Test vector FAILS\n"); + fprintf(stderr,"Internal weighted error is %f\n",err); + return EXIT_FAILURE; + } + else{ + fprintf(stderr,"Test vector PASSES\n"); + fprintf(stderr, + "Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err); + return EXIT_SUCCESS; + } +} diff --git a/native/codec/libraries/opus/src/opus_decoder.c b/native/codec/libraries/opus/src/opus_decoder.c new file mode 100644 index 0000000..9113638 --- /dev/null +++ b/native/codec/libraries/opus/src/opus_decoder.c @@ -0,0 +1,1032 @@ +/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef OPUS_BUILD +# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details." +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(OPUS_WILL_BE_SLOW) +# pragma message "You appear to be compiling without optimization, if so opus will be very slow." +#endif + +#include +#include "celt.h" +#include "opus.h" +#include "entdec.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus_private.h" +#include "os_support.h" +#include "structs.h" +#include "define.h" +#include "mathops.h" +#include "cpu_support.h" + +struct OpusDecoder { + int celt_dec_offset; + int silk_dec_offset; + int channels; + opus_int32 Fs; /** Sampling rate (at the API level) */ + silk_DecControlStruct DecControl; + int decode_gain; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define OPUS_DECODER_RESET_START stream_channels + int stream_channels; + + int bandwidth; + int mode; + int prev_mode; + int frame_size; + int prev_redundancy; + int last_packet_duration; +#ifndef FIXED_POINT + opus_val16 softclip_mem[2]; +#endif + + opus_uint32 rangeFinal; +}; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +static void validate_opus_decoder(OpusDecoder *st) +{ + celt_assert(st->channels == 1 || st->channels == 2); + celt_assert(st->Fs == 48000 || st->Fs == 24000 || st->Fs == 16000 || st->Fs == 12000 || st->Fs == 8000); + celt_assert(st->DecControl.API_sampleRate == st->Fs); + celt_assert(st->DecControl.internalSampleRate == 0 || st->DecControl.internalSampleRate == 16000 || st->DecControl.internalSampleRate == 12000 || st->DecControl.internalSampleRate == 8000); + celt_assert(st->DecControl.nChannelsAPI == st->channels); + celt_assert(st->DecControl.nChannelsInternal == 0 || st->DecControl.nChannelsInternal == 1 || st->DecControl.nChannelsInternal == 2); + celt_assert(st->DecControl.payloadSize_ms == 0 || st->DecControl.payloadSize_ms == 10 || st->DecControl.payloadSize_ms == 20 || st->DecControl.payloadSize_ms == 40 || st->DecControl.payloadSize_ms == 60); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif + celt_assert(st->stream_channels == 1 || st->stream_channels == 2); +} +#define VALIDATE_OPUS_DECODER(st) validate_opus_decoder(st) +#else +#define VALIDATE_OPUS_DECODER(st) +#endif + +int opus_decoder_get_size(int channels) +{ + int silkDecSizeBytes, celtDecSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Decoder_Size( &silkDecSizeBytes ); + if(ret) + return 0; + silkDecSizeBytes = align(silkDecSizeBytes); + celtDecSizeBytes = celt_decoder_get_size(channels); + return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes; +} + +int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) +{ + void *silk_dec; + CELTDecoder *celt_dec; + int ret, silkDecSizeBytes; + + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); + /* Initialize SILK decoder */ + ret = silk_Get_Decoder_Size(&silkDecSizeBytes); + if (ret) + return OPUS_INTERNAL_ERROR; + + silkDecSizeBytes = align(silkDecSizeBytes); + st->silk_dec_offset = align(sizeof(OpusDecoder)); + st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes; + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + st->DecControl.API_sampleRate = st->Fs; + st->DecControl.nChannelsAPI = st->channels; + + /* Reset decoder */ + ret = silk_InitDecoder( silk_dec ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* Initialize CELT decoder */ + ret = celt_decoder_init(celt_dec, Fs, channels); + if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0)); + + st->prev_mode = 0; + st->frame_size = Fs/400; + st->arch = opus_select_arch(); + return OPUS_OK; +} + +OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int ret; + OpusDecoder *st; + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels)); + if (st == NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_decoder_init(st, Fs, channels); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, + opus_val16 *out, int overlap, int channels, + const opus_val16 *window, opus_int32 Fs) +{ + int i, c; + int inc = 48000/Fs; + for (c=0;csilk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + F20 = st->Fs/50; + F10 = F20>>1; + F5 = F10>>1; + F2_5 = F5>>1; + if (frame_size < F2_5) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + /* Limit frame_size to avoid excessive stack allocations. */ + frame_size = IMIN(frame_size, st->Fs/25*3); + /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ + if (len<=1) + { + data = NULL; + /* In that case, don't conceal more than what the ToC says */ + frame_size = IMIN(frame_size, st->frame_size); + } + if (data != NULL) + { + audiosize = st->frame_size; + mode = st->mode; + bandwidth = st->bandwidth; + ec_dec_init(&dec,(unsigned char*)data,len); + } else { + audiosize = frame_size; + mode = st->prev_mode; + bandwidth = 0; + + if (mode == 0) + { + /* If we haven't got any packet yet, all we can do is return zeros */ + for (i=0;ichannels;i++) + pcm[i] = 0; + RESTORE_STACK; + return audiosize; + } + + /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT), + 10, or 20 (e.g. 12.5 or 30 ms). */ + if (audiosize > F20) + { + do { + int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0); + if (ret<0) + { + RESTORE_STACK; + return ret; + } + pcm += ret*st->channels; + audiosize -= ret; + } while (audiosize > 0); + RESTORE_STACK; + return frame_size; + } else if (audiosize < F20) + { + if (audiosize > F10) + audiosize = F10; + else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) + audiosize = F5; + } + } + + /* In fixed-point, we can tell CELT to do the accumulation on top of the + SILK PCM buffer. This saves some stack space. */ +#ifdef FIXED_POINT + celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10); +#else + celt_accum = 0; +#endif + + pcm_transition_silk_size = ALLOC_NONE; + pcm_transition_celt_size = ALLOC_NONE; + if (data!=NULL && st->prev_mode > 0 && ( + (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) + || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) + ) + { + transition = 1; + /* Decide where to allocate the stack memory for pcm_transition */ + if (mode == MODE_CELT_ONLY) + pcm_transition_celt_size = F5*st->channels; + else + pcm_transition_silk_size = F5*st->channels; + } + ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16); + if (transition && mode == MODE_CELT_ONLY) + { + pcm_transition = pcm_transition_celt; + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + if (audiosize > frame_size) + { + /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ + RESTORE_STACK; + return OPUS_BAD_ARG; + } else { + frame_size = audiosize; + } + + /* Don't allocate any memory when in CELT-only mode */ + pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; + ALLOC(pcm_silk, pcm_silk_size, opus_int16); + + /* SILK processing */ + if (mode != MODE_CELT_ONLY) + { + int lost_flag, decoded_samples; + opus_int16 *pcm_ptr; +#ifdef FIXED_POINT + if (celt_accum) + pcm_ptr = pcm; + else +#endif + pcm_ptr = pcm_silk; + + if (st->prev_mode==MODE_CELT_ONLY) + silk_InitDecoder( silk_dec ); + + /* The SILK PLC cannot produce frames of less than 10 ms */ + st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); + + if (data != NULL) + { + st->DecControl.nChannelsInternal = st->stream_channels; + if( mode == MODE_SILK_ONLY ) { + if( bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { + st->DecControl.internalSampleRate = 8000; + } else if( bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { + st->DecControl.internalSampleRate = 12000; + } else if( bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { + st->DecControl.internalSampleRate = 16000; + } else { + st->DecControl.internalSampleRate = 16000; + celt_assert( 0 ); + } + } else { + /* Hybrid mode */ + st->DecControl.internalSampleRate = 16000; + } + } + + lost_flag = data == NULL ? 1 : 2 * decode_fec; + decoded_samples = 0; + do { + /* Call SILK decoder */ + int first_frame = decoded_samples == 0; + silk_ret = silk_Decode( silk_dec, &st->DecControl, + lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch ); + if( silk_ret ) { + if (lost_flag) { + /* PLC failure should not be fatal */ + silk_frame_size = frame_size; + for (i=0;ichannels;i++) + pcm_ptr[i] = 0; + } else { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + pcm_ptr += silk_frame_size * st->channels; + decoded_samples += silk_frame_size; + } while( decoded_samples < frame_size ); + } + + start_band = 0; + if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL + && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) + { + /* Check if we have a redundant 0-8 kHz band */ + if (mode == MODE_HYBRID) + redundancy = ec_dec_bit_logp(&dec, 12); + else + redundancy = 1; + if (redundancy) + { + celt_to_silk = ec_dec_bit_logp(&dec, 1); + /* redundancy_bytes will be at least two, in the non-hybrid + case due to the ec_tell() check above */ + redundancy_bytes = mode==MODE_HYBRID ? + (opus_int32)ec_dec_uint(&dec, 256)+2 : + len-((ec_tell(&dec)+7)>>3); + len -= redundancy_bytes; + /* This is a sanity check. It should never happen for a valid + packet, so the exact behaviour is not normative. */ + if (len*8 < ec_tell(&dec)) + { + len = 0; + redundancy_bytes = 0; + redundancy = 0; + } + /* Shrink decoder because of raw bits */ + dec.storage -= redundancy_bytes; + } + } + if (mode != MODE_CELT_ONLY) + start_band = 17; + + if (redundancy) + { + transition = 0; + pcm_transition_silk_size=ALLOC_NONE; + } + + ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16); + + if (transition && mode != MODE_CELT_ONLY) + { + pcm_transition = pcm_transition_silk; + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + + + if (bandwidth) + { + int endband=21; + + switch(bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + default: + celt_assert(0); + break; + } + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband))); + } + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels))); + + /* Only allocation memory for redundancy if/when needed */ + redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE; + ALLOC(redundant_audio, redundant_audio_size, opus_val16); + + /* 5 ms redundant frame for CELT->SILK*/ + if (redundancy && celt_to_silk) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, + redundant_audio, F5, NULL, 0); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng))); + } + + /* MUST be after PLC */ + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band))); + + if (mode != MODE_SILK_ONLY) + { + int celt_frame_size = IMIN(F20, frame_size); + /* Make sure to discard any previous CELT state */ + if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); + /* Decode CELT */ + celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, + len, pcm, celt_frame_size, &dec, celt_accum); + } else { + unsigned char silence[2] = {0xFF, 0xFF}; + if (!celt_accum) + { + for (i=0;ichannels;i++) + pcm[i] = 0; + } + /* For hybrid -> SILK transitions, we let the CELT MDCT + do a fade-out by decoding a silence frame */ + if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum); + } + } + + if (mode != MODE_CELT_ONLY && !celt_accum) + { +#ifdef FIXED_POINT + for (i=0;ichannels;i++) + pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i])); +#else + for (i=0;ichannels;i++) + pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); +#endif + } + + { + const CELTMode *celt_mode; + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode))); + window = celt_mode->window; + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng))); + smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, + pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); + } + if (redundancy && celt_to_silk) + { + for (c=0;cchannels;c++) + { + for (i=0;ichannels*i+c] = redundant_audio[st->channels*i+c]; + } + smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); + } + if (transition) + { + if (audiosize >= F5) + { + for (i=0;ichannels*F2_5;i++) + pcm[i] = pcm_transition[i]; + smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, + st->channels, window, st->Fs); + } else { + /* Not enough time to do a clean transition, but we do it anyway + This will not preserve amplitude perfectly and may introduce + a bit of temporal aliasing, but it shouldn't be too bad and + that's pretty much the best we can do. In any case, generating this + transition it pretty silly in the first place */ + smooth_fade(pcm_transition, pcm, + pcm, F2_5, + st->channels, window, st->Fs); + } + } + + if(st->decode_gain) + { + opus_val32 gain; + gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); + for (i=0;ichannels;i++) + { + opus_val32 x; + x = MULT16_32_P16(pcm[i],gain); + pcm[i] = SATURATE(x, 32767); + } + } + + if (len <= 1) + st->rangeFinal = 0; + else + st->rangeFinal = dec.rng ^ redundant_rng; + + st->prev_mode = mode; + st->prev_redundancy = redundancy && !celt_to_silk; + + if (celt_ret>=0) + { + if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels)) + OPUS_PRINT_INT(audiosize); + } + + RESTORE_STACK; + return celt_ret < 0 ? celt_ret : audiosize; + +} + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, + int self_delimited, opus_int32 *packet_offset, int soft_clip) +{ + int i, nb_samples; + int count, offset; + unsigned char toc; + int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; + /* 48 x 2.5 ms = 120 ms */ + opus_int16 size[48]; + VALIDATE_OPUS_DECODER(st); + if (decode_fec<0 || decode_fec>1) + return OPUS_BAD_ARG; + /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ + if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) + return OPUS_BAD_ARG; + if (len==0 || data==NULL) + { + int pcm_count=0; + do { + int ret; + ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0); + if (ret<0) + return ret; + pcm_count += ret; + } while (pcm_count < frame_size); + celt_assert(pcm_count == frame_size); + if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels)) + OPUS_PRINT_INT(pcm_count); + st->last_packet_duration = pcm_count; + return pcm_count; + } else if (len<0) + return OPUS_BAD_ARG; + + packet_mode = opus_packet_get_mode(data); + packet_bandwidth = opus_packet_get_bandwidth(data); + packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); + packet_stream_channels = opus_packet_get_nb_channels(data); + + count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, + size, &offset, packet_offset); + if (count<0) + return count; + + data += offset; + + if (decode_fec) + { + int duration_copy; + int ret; + /* If no FEC can be present, run the PLC (recursive call) */ + if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) + return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip); + /* Otherwise, run the PLC on everything except the size for which we might have FEC */ + duration_copy = st->last_packet_duration; + if (frame_size-packet_frame_size!=0) + { + ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip); + if (ret<0) + { + st->last_packet_duration = duration_copy; + return ret; + } + celt_assert(ret==frame_size-packet_frame_size); + } + /* Complete with FEC */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), + packet_frame_size, 1); + if (ret<0) + return ret; + else { + if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels)) + OPUS_PRINT_INT(frame_size); + st->last_packet_duration = frame_size; + return frame_size; + } + } + + if (count*packet_frame_size > frame_size) + return OPUS_BUFFER_TOO_SMALL; + + /* Update the state as the last step to avoid updating it on an invalid packet */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + + nb_samples=0; + for (i=0;ichannels, frame_size-nb_samples, 0); + if (ret<0) + return ret; + celt_assert(ret==packet_frame_size); + data += size[i]; + nb_samples += ret; + } + st->last_packet_duration = nb_samples; + if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels)) + OPUS_PRINT_INT(nb_samples); +#ifndef FIXED_POINT + if (soft_clip) + opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem); + else + st->softclip_mem[0]=st->softclip_mem[1]=0; +#endif + return nb_samples; +} + +#ifdef FIXED_POINT + +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); +} + +#ifndef DISABLE_FLOAT_API +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + VARDECL(opus_int16, out); + int ret, i; + int nb_samples; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + if (data != NULL && len > 0 && !decode_fec) + { + nb_samples = opus_decoder_get_nb_samples(st, data, len); + if (nb_samples>0) + frame_size = IMIN(frame_size, nb_samples); + else + return OPUS_INVALID_PACKET; + } + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, opus_int16); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = (1.f/32768.f)*(out[i]); + } + RESTORE_STACK; + return ret; +} +#endif + + +#else +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) +{ + VARDECL(float, out); + int ret, i; + int nb_samples; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + if (data != NULL && len > 0 && !decode_fec) + { + nb_samples = opus_decoder_get_nb_samples(st, data, len); + if (nb_samples>0) + frame_size = IMIN(frame_size, nb_samples); + else + return OPUS_INVALID_PACKET; + } + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, float); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = FLOAT2INT16(out[i]); + } + RESTORE_STACK; + return ret; +} + +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); +} + +#endif + +int opus_decoder_ctl(OpusDecoder *st, int request, ...) +{ + int ret = OPUS_OK; + va_list ap; + void *silk_dec; + CELTDecoder *celt_dec; + + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + + + va_start(ap, request); + + switch (request) + { + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->bandwidth; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + if (!value) + { + goto bad_arg; + } + *value = st->rangeFinal; + } + break; + case OPUS_RESET_STATE: + { + OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START, + sizeof(OpusDecoder)- + ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); + + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + silk_InitDecoder( silk_dec ); + st->stream_channels = st->channels; + st->frame_size = st->Fs/400; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->prev_mode == MODE_CELT_ONLY) + ret = celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); + else + *value = st->DecControl.prevPitchLag; + } + break; + case OPUS_GET_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->decode_gain; + } + break; + case OPUS_SET_GAIN_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-32768 || value>32767) + { + goto bad_arg; + } + st->decode_gain = value; + } + break; + case OPUS_GET_LAST_PACKET_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->last_packet_duration; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + ret = celt_decoder_ctl(celt_dec, OPUS_SET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + ret = celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value)); + } + break; + default: + /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_decoder_destroy(OpusDecoder *st) +{ + opus_free(st); +} + + +int opus_packet_get_bandwidth(const unsigned char *data) +{ + int bandwidth; + if (data[0]&0x80) + { + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3); + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if ((data[0]&0x60) == 0x60) + { + bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND : + OPUS_BANDWIDTH_SUPERWIDEBAND; + } else { + bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3); + } + return bandwidth; +} + +int opus_packet_get_nb_channels(const unsigned char *data) +{ + return (data[0]&0x4) ? 2 : 1; +} + +int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) +{ + int count; + if (len<1) + return OPUS_BAD_ARG; + count = packet[0]&0x3; + if (count==0) + return 1; + else if (count!=3) + return 2; + else if (len<2) + return OPUS_INVALID_PACKET; + else + return packet[1]&0x3F; +} + +int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, + opus_int32 Fs) +{ + int samples; + int count = opus_packet_get_nb_frames(packet, len); + + if (count<0) + return count; + + samples = count*opus_packet_get_samples_per_frame(packet, Fs); + /* Can't have more than 120 ms */ + if (samples*25 > Fs*3) + return OPUS_INVALID_PACKET; + else + return samples; +} + +int opus_decoder_get_nb_samples(const OpusDecoder *dec, + const unsigned char packet[], opus_int32 len) +{ + return opus_packet_get_nb_samples(packet, len, dec->Fs); +} diff --git a/native/codec/libraries/opus/src/opus_demo.c b/native/codec/libraries/opus/src/opus_demo.c new file mode 100644 index 0000000..4cc26a6 --- /dev/null +++ b/native/codec/libraries/opus/src/opus_demo.c @@ -0,0 +1,892 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "opus.h" +#include "debug.h" +#include "opus_types.h" +#include "opus_private.h" +#include "opus_multistream.h" + +#define MAX_PACKET 1500 + +void print_usage( char* argv[] ) +{ + fprintf(stderr, "Usage: %s [-e] " + " [options] \n", argv[0]); + fprintf(stderr, " %s -d " + "[options] \n\n", argv[0]); + fprintf(stderr, "application: voip | audio | restricted-lowdelay\n" ); + fprintf(stderr, "options:\n" ); + fprintf(stderr, "-e : only runs the encoder (output the bit-stream)\n" ); + fprintf(stderr, "-d : only runs the decoder (reads the bit-stream as input)\n" ); + fprintf(stderr, "-cbr : enable constant bitrate; default: variable bitrate\n" ); + fprintf(stderr, "-cvbr : enable constrained variable bitrate; default: unconstrained\n" ); + fprintf(stderr, "-delayed-decision : use look-ahead for speech/music detection (experts only); default: disabled\n" ); + fprintf(stderr, "-bandwidth : audio bandwidth (from narrowband to fullband); default: sampling rate\n" ); + fprintf(stderr, "-framesize <2.5|5|10|20|40|60|80|100|120> : frame size in ms; default: 20 \n" ); + fprintf(stderr, "-max_payload : maximum payload size in bytes, default: 1024\n" ); + fprintf(stderr, "-complexity : complexity, 0 (lowest) ... 10 (highest); default: 10\n" ); + fprintf(stderr, "-inbandfec : enable SILK inband FEC\n" ); + fprintf(stderr, "-forcemono : force mono encoding, even for stereo input\n" ); + fprintf(stderr, "-dtx : enable SILK DTX\n" ); + fprintf(stderr, "-loss : simulate packet loss, in percent (0-100); default: 0\n" ); +} + +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static opus_uint32 char_to_int(unsigned char ch[4]) +{ + return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16) + | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3]; +} + +#define check_encoder_option(decode_only, opt) do {if (decode_only) {fprintf(stderr, "option %s is only for encoding\n", opt); goto failure;}} while(0) + +static const int silk8_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2} +}; + +static const int silk12_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 2} +}; + +static const int silk16_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2} +}; + +static const int hybrid24_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2} +}; + +static const int hybrid48_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2} +}; + +static const int celt_test[][4] = { + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 2}, + +}; + +static const int celt_hq_test[][4] = { + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2}, +}; + +#if 0 /* This is a hack that replaces the normal encoder/decoder with the multistream version */ +#define OpusEncoder OpusMSEncoder +#define OpusDecoder OpusMSDecoder +#define opus_encode opus_multistream_encode +#define opus_decode opus_multistream_decode +#define opus_encoder_ctl opus_multistream_encoder_ctl +#define opus_decoder_ctl opus_multistream_decoder_ctl +#define opus_encoder_create ms_opus_encoder_create +#define opus_decoder_create ms_opus_decoder_create +#define opus_encoder_destroy opus_multistream_encoder_destroy +#define opus_decoder_destroy opus_multistream_decoder_destroy + +static OpusEncoder *ms_opus_encoder_create(opus_int32 Fs, int channels, int application, int *error) +{ + int streams, coupled_streams; + unsigned char mapping[256]; + return (OpusEncoder *)opus_multistream_surround_encoder_create(Fs, channels, 1, &streams, &coupled_streams, mapping, application, error); +} +static OpusDecoder *ms_opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int streams; + int coupled_streams; + unsigned char mapping[256]={0,1}; + streams = 1; + coupled_streams = channels==2; + return (OpusDecoder *)opus_multistream_decoder_create(Fs, channels, streams, coupled_streams, mapping, error); +} +#endif + +int main(int argc, char *argv[]) +{ + int err; + char *inFile, *outFile; + FILE *fin=NULL; + FILE *fout=NULL; + OpusEncoder *enc=NULL; + OpusDecoder *dec=NULL; + int args; + int len[2]; + int frame_size, channels; + opus_int32 bitrate_bps=0; + unsigned char *data[2] = {NULL, NULL}; + unsigned char *fbytes=NULL; + opus_int32 sampling_rate; + int use_vbr; + int max_payload_bytes; + int complexity; + int use_inbandfec; + int use_dtx; + int forcechannels; + int cvbr = 0; + int packet_loss_perc; + opus_int32 count=0, count_act=0; + int k; + opus_int32 skip=0; + int stop=0; + short *in=NULL; + short *out=NULL; + int application=OPUS_APPLICATION_AUDIO; + double bits=0.0, bits_max=0.0, bits_act=0.0, bits2=0.0, nrg; + double tot_samples=0; + opus_uint64 tot_in, tot_out; + int bandwidth=OPUS_AUTO; + const char *bandwidth_string; + int lost = 0, lost_prev = 1; + int toggle = 0; + opus_uint32 enc_final_range[2]; + opus_uint32 dec_final_range; + int encode_only=0, decode_only=0; + int max_frame_size = 48000*2; + size_t num_read; + int curr_read=0; + int sweep_bps = 0; + int random_framesize=0, newsize=0, delayed_celt=0; + int sweep_max=0, sweep_min=0; + int random_fec=0; + const int (*mode_list)[4]=NULL; + int nb_modes_in_list=0; + int curr_mode=0; + int curr_mode_count=0; + int mode_switch_time = 48000; + int nb_encoded=0; + int remaining=0; + int variable_duration=OPUS_FRAMESIZE_ARG; + int delayed_decision=0; + int ret = EXIT_FAILURE; + + if (argc < 5 ) + { + print_usage( argv ); + goto failure; + } + + tot_in=tot_out=0; + fprintf(stderr, "%s\n", opus_get_version_string()); + + args = 1; + if (strcmp(argv[args], "-e")==0) + { + encode_only = 1; + args++; + } else if (strcmp(argv[args], "-d")==0) + { + decode_only = 1; + args++; + } + if (!decode_only && argc < 7 ) + { + print_usage( argv ); + goto failure; + } + + if (!decode_only) + { + if (strcmp(argv[args], "voip")==0) + application = OPUS_APPLICATION_VOIP; + else if (strcmp(argv[args], "restricted-lowdelay")==0) + application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; + else if (strcmp(argv[args], "audio")!=0) { + fprintf(stderr, "unknown application: %s\n", argv[args]); + print_usage(argv); + goto failure; + } + args++; + } + sampling_rate = (opus_int32)atol(argv[args]); + args++; + + if (sampling_rate != 8000 && sampling_rate != 12000 + && sampling_rate != 16000 && sampling_rate != 24000 + && sampling_rate != 48000) + { + fprintf(stderr, "Supported sampling rates are 8000, 12000, " + "16000, 24000 and 48000.\n"); + goto failure; + } + frame_size = sampling_rate/50; + + channels = atoi(argv[args]); + args++; + + if (channels < 1 || channels > 2) + { + fprintf(stderr, "Opus_demo supports only 1 or 2 channels.\n"); + goto failure; + } + + if (!decode_only) + { + bitrate_bps = (opus_int32)atol(argv[args]); + args++; + } + + /* defaults: */ + use_vbr = 1; + max_payload_bytes = MAX_PACKET; + complexity = 10; + use_inbandfec = 0; + forcechannels = OPUS_AUTO; + use_dtx = 0; + packet_loss_perc = 0; + + while( args < argc - 2 ) { + /* process command line options */ + if( strcmp( argv[ args ], "-cbr" ) == 0 ) { + check_encoder_option(decode_only, "-cbr"); + use_vbr = 0; + args++; + } else if( strcmp( argv[ args ], "-bandwidth" ) == 0 ) { + check_encoder_option(decode_only, "-bandwidth"); + if (strcmp(argv[ args + 1 ], "NB")==0) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (strcmp(argv[ args + 1 ], "MB")==0) + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (strcmp(argv[ args + 1 ], "WB")==0) + bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (strcmp(argv[ args + 1 ], "SWB")==0) + bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else if (strcmp(argv[ args + 1 ], "FB")==0) + bandwidth = OPUS_BANDWIDTH_FULLBAND; + else { + fprintf(stderr, "Unknown bandwidth %s. " + "Supported are NB, MB, WB, SWB, FB.\n", + argv[ args + 1 ]); + goto failure; + } + args += 2; + } else if( strcmp( argv[ args ], "-framesize" ) == 0 ) { + check_encoder_option(decode_only, "-framesize"); + if (strcmp(argv[ args + 1 ], "2.5")==0) + frame_size = sampling_rate/400; + else if (strcmp(argv[ args + 1 ], "5")==0) + frame_size = sampling_rate/200; + else if (strcmp(argv[ args + 1 ], "10")==0) + frame_size = sampling_rate/100; + else if (strcmp(argv[ args + 1 ], "20")==0) + frame_size = sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "40")==0) + frame_size = sampling_rate/25; + else if (strcmp(argv[ args + 1 ], "60")==0) + frame_size = 3*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "80")==0) + frame_size = 4*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "100")==0) + frame_size = 5*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "120")==0) + frame_size = 6*sampling_rate/50; + else { + fprintf(stderr, "Unsupported frame size: %s ms. " + "Supported are 2.5, 5, 10, 20, 40, 60, 80, 100, 120.\n", + argv[ args + 1 ]); + goto failure; + } + args += 2; + } else if( strcmp( argv[ args ], "-max_payload" ) == 0 ) { + check_encoder_option(decode_only, "-max_payload"); + max_payload_bytes = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-complexity" ) == 0 ) { + check_encoder_option(decode_only, "-complexity"); + complexity = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-inbandfec" ) == 0 ) { + use_inbandfec = 1; + args++; + } else if( strcmp( argv[ args ], "-forcemono" ) == 0 ) { + check_encoder_option(decode_only, "-forcemono"); + forcechannels = 1; + args++; + } else if( strcmp( argv[ args ], "-cvbr" ) == 0 ) { + check_encoder_option(decode_only, "-cvbr"); + cvbr = 1; + args++; + } else if( strcmp( argv[ args ], "-delayed-decision" ) == 0 ) { + check_encoder_option(decode_only, "-delayed-decision"); + delayed_decision = 1; + args++; + } else if( strcmp( argv[ args ], "-dtx") == 0 ) { + check_encoder_option(decode_only, "-dtx"); + use_dtx = 1; + args++; + } else if( strcmp( argv[ args ], "-loss" ) == 0 ) { + packet_loss_perc = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-sweep" ) == 0 ) { + check_encoder_option(decode_only, "-sweep"); + sweep_bps = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-random_framesize" ) == 0 ) { + check_encoder_option(decode_only, "-random_framesize"); + random_framesize = 1; + args++; + } else if( strcmp( argv[ args ], "-sweep_max" ) == 0 ) { + check_encoder_option(decode_only, "-sweep_max"); + sweep_max = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-random_fec" ) == 0 ) { + check_encoder_option(decode_only, "-random_fec"); + random_fec = 1; + args++; + } else if( strcmp( argv[ args ], "-silk8k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk8k_test"); + mode_list = silk8_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-silk12k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk12k_test"); + mode_list = silk12_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-silk16k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk16k_test"); + mode_list = silk16_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-hybrid24k_test" ) == 0 ) { + check_encoder_option(decode_only, "-hybrid24k_test"); + mode_list = hybrid24_test; + nb_modes_in_list = 4; + args++; + } else if( strcmp( argv[ args ], "-hybrid48k_test" ) == 0 ) { + check_encoder_option(decode_only, "-hybrid48k_test"); + mode_list = hybrid48_test; + nb_modes_in_list = 4; + args++; + } else if( strcmp( argv[ args ], "-celt_test" ) == 0 ) { + check_encoder_option(decode_only, "-celt_test"); + mode_list = celt_test; + nb_modes_in_list = 32; + args++; + } else if( strcmp( argv[ args ], "-celt_hq_test" ) == 0 ) { + check_encoder_option(decode_only, "-celt_hq_test"); + mode_list = celt_hq_test; + nb_modes_in_list = 4; + args++; + } else { + printf( "Error: unrecognized setting: %s\n\n", argv[ args ] ); + print_usage( argv ); + goto failure; + } + } + + if (sweep_max) + sweep_min = bitrate_bps; + + if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET) + { + fprintf (stderr, "max_payload_bytes must be between 0 and %d\n", + MAX_PACKET); + goto failure; + } + + inFile = argv[argc-2]; + fin = fopen(inFile, "rb"); + if (!fin) + { + fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); + goto failure; + } + if (mode_list) + { + int size; + fseek(fin, 0, SEEK_END); + size = ftell(fin); + fprintf(stderr, "File size is %d bytes\n", size); + fseek(fin, 0, SEEK_SET); + mode_switch_time = size/sizeof(short)/channels/nb_modes_in_list; + fprintf(stderr, "Switching mode every %d samples\n", mode_switch_time); + } + + outFile = argv[argc-1]; + fout = fopen(outFile, "wb+"); + if (!fout) + { + fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); + goto failure; + } + + if (!decode_only) + { + enc = opus_encoder_create(sampling_rate, channels, application, &err); + if (err != OPUS_OK) + { + fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err)); + goto failure; + } + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth)); + opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr)); + opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr)); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(use_inbandfec)); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels)); + opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc)); + + opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip)); + opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16)); + opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration)); + } + if (!encode_only) + { + dec = opus_decoder_create(sampling_rate, channels, &err); + if (err != OPUS_OK) + { + fprintf(stderr, "Cannot create decoder: %s\n", opus_strerror(err)); + goto failure; + } + } + + + switch(bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + bandwidth_string = "narrowband"; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + bandwidth_string = "mediumband"; + break; + case OPUS_BANDWIDTH_WIDEBAND: + bandwidth_string = "wideband"; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + bandwidth_string = "superwideband"; + break; + case OPUS_BANDWIDTH_FULLBAND: + bandwidth_string = "fullband"; + break; + case OPUS_AUTO: + bandwidth_string = "auto bandwidth"; + break; + default: + bandwidth_string = "unknown"; + break; + } + + if (decode_only) + fprintf(stderr, "Decoding with %ld Hz output (%d channels)\n", + (long)sampling_rate, channels); + else + fprintf(stderr, "Encoding %ld Hz input at %.3f kb/s " + "in %s with %d-sample frames.\n", + (long)sampling_rate, bitrate_bps*0.001, + bandwidth_string, frame_size); + + in = (short*)malloc(max_frame_size*channels*sizeof(short)); + out = (short*)malloc(max_frame_size*channels*sizeof(short)); + /* We need to allocate for 16-bit PCM data, but we store it as unsigned char. */ + fbytes = (unsigned char*)malloc(max_frame_size*channels*sizeof(short)); + data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char)); + if ( use_inbandfec ) { + data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char)); + } + if(delayed_decision) + { + if (frame_size==sampling_rate/400) + variable_duration = OPUS_FRAMESIZE_2_5_MS; + else if (frame_size==sampling_rate/200) + variable_duration = OPUS_FRAMESIZE_5_MS; + else if (frame_size==sampling_rate/100) + variable_duration = OPUS_FRAMESIZE_10_MS; + else if (frame_size==sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_20_MS; + else if (frame_size==sampling_rate/25) + variable_duration = OPUS_FRAMESIZE_40_MS; + else if (frame_size==3*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_60_MS; + else if (frame_size==4*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_80_MS; + else if (frame_size==5*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_100_MS; + else + variable_duration = OPUS_FRAMESIZE_120_MS; + opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration)); + frame_size = 2*48000; + } + while (!stop) + { + if (delayed_celt) + { + frame_size = newsize; + delayed_celt = 0; + } else if (random_framesize && rand()%20==0) + { + newsize = rand()%6; + switch(newsize) + { + case 0: newsize=sampling_rate/400; break; + case 1: newsize=sampling_rate/200; break; + case 2: newsize=sampling_rate/100; break; + case 3: newsize=sampling_rate/50; break; + case 4: newsize=sampling_rate/25; break; + case 5: newsize=3*sampling_rate/50; break; + } + while (newsize < sampling_rate/25 && bitrate_bps-abs(sweep_bps) <= 3*12*sampling_rate/newsize) + newsize*=2; + if (newsize < sampling_rate/100 && frame_size >= sampling_rate/100) + { + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + delayed_celt=1; + } else { + frame_size = newsize; + } + } + if (random_fec && rand()%30==0) + { + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rand()%4==0)); + } + if (decode_only) + { + unsigned char ch[4]; + num_read = fread(ch, 1, 4, fin); + if (num_read!=4) + break; + len[toggle] = char_to_int(ch); + if (len[toggle]>max_payload_bytes || len[toggle]<0) + { + fprintf(stderr, "Invalid payload length: %d\n",len[toggle]); + break; + } + num_read = fread(ch, 1, 4, fin); + if (num_read!=4) + break; + enc_final_range[toggle] = char_to_int(ch); + num_read = fread(data[toggle], 1, len[toggle], fin); + if (num_read!=(size_t)len[toggle]) + { + fprintf(stderr, "Ran out of input, " + "expecting %d bytes got %d\n", + len[toggle],(int)num_read); + break; + } + } else { + int i; + if (mode_list!=NULL) + { + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(mode_list[curr_mode][1])); + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(mode_list[curr_mode][0])); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(mode_list[curr_mode][3])); + frame_size = mode_list[curr_mode][2]; + } + num_read = fread(fbytes, sizeof(short)*channels, frame_size-remaining, fin); + curr_read = (int)num_read; + tot_in += curr_read; + for(i=0;i sweep_max) + sweep_bps = -sweep_bps; + else if (bitrate_bps < sweep_min) + sweep_bps = -sweep_bps; + } + /* safety */ + if (bitrate_bps<1000) + bitrate_bps = 1000; + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + } + opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range[toggle])); + if (len[toggle] < 0) + { + fprintf (stderr, "opus_encode() returned %d\n", len[toggle]); + goto failure; + } + curr_mode_count += frame_size; + if (curr_mode_count > mode_switch_time && curr_mode < nb_modes_in_list-1) + { + curr_mode++; + curr_mode_count = 0; + } + } + +#if 0 /* This is for testing the padding code, do not enable by default */ + if (len[toggle]<1275) + { + int new_len = len[toggle]+rand()%(max_payload_bytes-len[toggle]); + if ((err = opus_packet_pad(data[toggle], len[toggle], new_len)) != OPUS_OK) + { + fprintf(stderr, "padding failed: %s\n", opus_strerror(err)); + goto failure; + } + len[toggle] = new_len; + } +#endif + if (encode_only) + { + unsigned char int_field[4]; + int_to_char(len[toggle], int_field); + if (fwrite(int_field, 1, 4, fout) != 4) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + int_to_char(enc_final_range[toggle], int_field); + if (fwrite(int_field, 1, 4, fout) != 4) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + if (fwrite(data[toggle], 1, len[toggle], fout) != (unsigned)len[toggle]) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + tot_samples += nb_encoded; + } else { + opus_int32 output_samples; + lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc); + if (lost) + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); + else + output_samples = max_frame_size; + if( count >= use_inbandfec ) { + /* delay by one packet when using in-band FEC */ + if( use_inbandfec ) { + if( lost_prev ) { + /* attempt to decode with in-band FEC from next packet */ + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); + output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 1); + } else { + /* regular decode */ + output_samples = max_frame_size; + output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, output_samples, 0); + } + } else { + output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 0); + } + if (output_samples>0) + { + if (!decode_only && tot_out + output_samples > tot_in) + { + stop=1; + output_samples = (opus_int32)(tot_in - tot_out); + } + if (output_samples>skip) { + int i; + for(i=0;i<(output_samples-skip)*channels;i++) + { + short s; + s=out[i+(skip*channels)]; + fbytes[2*i]=s&0xFF; + fbytes[2*i+1]=(s>>8)&0xFF; + } + if (fwrite(fbytes, sizeof(short)*channels, output_samples-skip, fout) != (unsigned)(output_samples-skip)){ + fprintf(stderr, "Error writing.\n"); + goto failure; + } + tot_out += output_samples-skip; + } + if (output_samples= use_inbandfec ) { + /* count bits */ + bits += len[toggle]*8; + bits_max = ( len[toggle]*8 > bits_max ) ? len[toggle]*8 : bits_max; + bits2 += len[toggle]*len[toggle]*64; + if (!decode_only) + { + nrg = 0.0; + for ( k = 0; k < frame_size * channels; k++ ) { + nrg += in[ k ] * (double)in[ k ]; + } + nrg /= frame_size * channels; + if( nrg > 1e5 ) { + bits_act += len[toggle]*8; + count_act++; + } + } + } + count++; + toggle = (toggle + use_inbandfec) & 1; + } + + if(decode_only && count > 0) + frame_size = (int)(tot_samples / count); + count -= use_inbandfec; + if (tot_samples >= 1 && count > 0 && frame_size) + { + /* Print out bitrate statistics */ + double var; + fprintf (stderr, "average bitrate: %7.3f kb/s\n", + 1e-3*bits*sampling_rate/tot_samples); + fprintf (stderr, "maximum bitrate: %7.3f kb/s\n", + 1e-3*bits_max*sampling_rate/frame_size); + if (!decode_only) + fprintf (stderr, "active bitrate: %7.3f kb/s\n", + 1e-3*bits_act*sampling_rate/(1e-15+frame_size*(double)count_act)); + var = bits2/count - bits*bits/(count*(double)count); + if (var < 0) + var = 0; + fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n", + 1e-3*sqrt(var)*sampling_rate/frame_size); + } else { + fprintf(stderr, "bitrate statistics are undefined\n"); + } + silk_TimerSave("opus_timing.txt"); + ret = EXIT_SUCCESS; +failure: + opus_encoder_destroy(enc); + opus_decoder_destroy(dec); + free(data[0]); + free(data[1]); + if (fin) + fclose(fin); + if (fout) + fclose(fout); + free(in); + free(out); + free(fbytes); + return ret; +} diff --git a/native/codec/libraries/opus/src/opus_encoder.c b/native/codec/libraries/opus/src/opus_encoder.c new file mode 100644 index 0000000..e98ac5b --- /dev/null +++ b/native/codec/libraries/opus/src/opus_encoder.c @@ -0,0 +1,2783 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "celt.h" +#include "entenc.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus.h" +#include "arch.h" +#include "pitch.h" +#include "opus_private.h" +#include "os_support.h" +#include "cpu_support.h" +#include "analysis.h" +#include "mathops.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "fixed/structs_FIX.h" +#else +#include "float/structs_FLP.h" +#endif + +#define MAX_ENCODER_BUFFER 480 + +#ifndef DISABLE_FLOAT_API +#define PSEUDO_SNR_THRESHOLD 316.23f /* 10^(25/10) */ +#endif + +typedef struct { + opus_val32 XX, XY, YY; + opus_val16 smoothed_width; + opus_val16 max_follower; +} StereoWidthState; + +struct OpusEncoder { + int celt_enc_offset; + int silk_enc_offset; + silk_EncControlStruct silk_mode; + int application; + int channels; + int delay_compensation; + int force_channels; + int signal_type; + int user_bandwidth; + int max_bandwidth; + int user_forced_mode; + int voice_ratio; + opus_int32 Fs; + int use_vbr; + int vbr_constraint; + int variable_duration; + opus_int32 bitrate_bps; + opus_int32 user_bitrate_bps; + int lsb_depth; + int encoder_buffer; + int lfe; + int arch; + int use_dtx; /* general DTX for both SILK and CELT */ +#ifndef DISABLE_FLOAT_API + TonalityAnalysisState analysis; +#endif + +#define OPUS_ENCODER_RESET_START stream_channels + int stream_channels; + opus_int16 hybrid_stereo_width_Q14; + opus_int32 variable_HP_smth2_Q15; + opus_val16 prev_HB_gain; + opus_val32 hp_mem[4]; + int mode; + int prev_mode; + int prev_channels; + int prev_framesize; + int bandwidth; + /* Bandwidth determined automatically from the rate (before any other adjustment) */ + int auto_bandwidth; + int silk_bw_switch; + /* Sampling rate (at the API level) */ + int first; + opus_val16 * energy_masking; + StereoWidthState width_mem; + opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2]; +#ifndef DISABLE_FLOAT_API + int detected_bandwidth; + int nb_no_activity_frames; + opus_val32 peak_signal_energy; +#endif + int nonfinal_frame; /* current frame is not the final in a packet */ + opus_uint32 rangeFinal; +}; + +/* Transition tables for the voice and music. First column is the + middle (memoriless) threshold. The second column is the hysteresis + (difference with the middle) */ +static const opus_int32 mono_voice_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 13500, 1000, /* WB<->SWB */ + 14000, 2000, /* SWB<->FB */ +}; +static const opus_int32 mono_music_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 11000, 1000, /* WB<->SWB */ + 12000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_voice_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 13500, 1000, /* WB<->SWB */ + 14000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_music_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 11000, 1000, /* WB<->SWB */ + 12000, 2000, /* SWB<->FB */ +}; +/* Threshold bit-rates for switching between mono and stereo */ +static const opus_int32 stereo_voice_threshold = 19000; +static const opus_int32 stereo_music_threshold = 17000; + +/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */ +static const opus_int32 mode_thresholds[2][2] = { + /* voice */ /* music */ + { 64000, 10000}, /* mono */ + { 44000, 10000}, /* stereo */ +}; + +static const opus_int32 fec_thresholds[] = { + 12000, 1000, /* NB */ + 14000, 1000, /* MB */ + 16000, 1000, /* WB */ + 20000, 1000, /* SWB */ + 22000, 1000, /* FB */ +}; + +int opus_encoder_get_size(int channels) +{ + int silkEncSizeBytes, celtEncSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return 0; + silkEncSizeBytes = align(silkEncSizeBytes); + celtEncSizeBytes = celt_encoder_get_size(channels); + return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes; +} + +int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int err; + int ret, silkEncSizeBytes; + + if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)|| + (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO + && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_encoder_get_size(channels)); + /* Create SILK encoder */ + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return OPUS_BAD_ARG; + silkEncSizeBytes = align(silkEncSizeBytes); + st->silk_enc_offset = align(sizeof(OpusEncoder)); + st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes; + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + + st->arch = opus_select_arch(); + + ret = silk_InitEncoder( silk_enc, st->arch, &st->silk_mode ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* default SILK parameters */ + st->silk_mode.nChannelsAPI = channels; + st->silk_mode.nChannelsInternal = channels; + st->silk_mode.API_sampleRate = st->Fs; + st->silk_mode.maxInternalSampleRate = 16000; + st->silk_mode.minInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = 16000; + st->silk_mode.payloadSize_ms = 20; + st->silk_mode.bitRate = 25000; + st->silk_mode.packetLossPercentage = 0; + st->silk_mode.complexity = 9; + st->silk_mode.useInBandFEC = 0; + st->silk_mode.useDTX = 0; + st->silk_mode.useCBR = 0; + st->silk_mode.reducedDependency = 0; + + /* Create CELT encoder */ + /* Initialize CELT encoder */ + err = celt_encoder_init(celt_enc, Fs, channels, st->arch); + if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity)); + + st->use_vbr = 1; + /* Makes constrained VBR the default (safer for real-time use) */ + st->vbr_constraint = 1; + st->user_bitrate_bps = OPUS_AUTO; + st->bitrate_bps = 3000+Fs*channels; + st->application = application; + st->signal_type = OPUS_AUTO; + st->user_bandwidth = OPUS_AUTO; + st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->force_channels = OPUS_AUTO; + st->user_forced_mode = OPUS_AUTO; + st->voice_ratio = -1; + st->encoder_buffer = st->Fs/100; + st->lsb_depth = 24; + st->variable_duration = OPUS_FRAMESIZE_ARG; + + /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead + + 1.5 ms for SILK resamplers and stereo prediction) */ + st->delay_compensation = st->Fs/250; + + st->hybrid_stereo_width_Q14 = 1 << 14; + st->prev_HB_gain = Q15ONE; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + +#ifndef DISABLE_FLOAT_API + tonality_analysis_init(&st->analysis, st->Fs); + st->analysis.application = st->application; +#endif + + return OPUS_OK; +} + +static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels) +{ + int period; + unsigned char toc; + period = 0; + while (framerate < 400) + { + framerate <<= 1; + period++; + } + if (mode == MODE_SILK_ONLY) + { + toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5; + toc |= (period-2)<<3; + } else if (mode == MODE_CELT_ONLY) + { + int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND; + if (tmp < 0) + tmp = 0; + toc = 0x80; + toc |= tmp << 5; + toc |= period<<3; + } else /* Hybrid */ + { + toc = 0x60; + toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4; + toc |= (period-2)<<3; + } + toc |= (channels==2)<<2; + return toc; +} + +#ifndef FIXED_POINT +static void silk_biquad_float( + const opus_val16 *in, /* I: Input signal */ + const opus_int32 *B_Q28, /* I: MA coefficients [3] */ + const opus_int32 *A_Q28, /* I: AR coefficients [2] */ + opus_val32 *S, /* I/O: State vector [2] */ + opus_val16 *out, /* O: Output signal */ + const opus_int32 len, /* I: Signal length (must be even) */ + int stride +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_val32 vout; + opus_val32 inval; + opus_val32 A[2], B[3]; + + A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28))); + A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28))); + B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28))); + B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28))); + B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28))); + + /* Negate A_Q28 values and split in two parts */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k*stride ]; + vout = S[ 0 ] + B[0]*inval; + + S[ 0 ] = S[1] - vout*A[0] + B[1]*inval; + + S[ 1 ] = - vout*A[1] + B[2]*inval + VERY_SMALL; + + /* Scale back to Q0 and saturate */ + out[ k*stride ] = vout; + } +} +#endif + +static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs, int arch) +{ + opus_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + opus_int32 Fc_Q19, r_Q28, r_Q22; + (void)arch; + + silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) ); + Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 ); + silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 ); + + r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 ); + + /* b = r * [ 1; -2; 1 ]; */ + /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */ + B_Q28[ 0 ] = r_Q28; + B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 ); + B_Q28[ 2 ] = r_Q28; + + /* -r * ( 2 - Fc * Fc ); */ + r_Q22 = silk_RSHIFT( r_Q28, 6 ); + A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) ); + A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 ); + +#ifdef FIXED_POINT + if( channels == 1 ) { + silk_biquad_alt_stride1( in, B_Q28, A_Q28, hp_mem, out, len ); + } else { + silk_biquad_alt_stride2( in, B_Q28, A_Q28, hp_mem, out, len, arch ); + } +#else + silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); + } +#endif +} + +#ifdef FIXED_POINT +static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs) +{ + int c, i; + int shift; + + /* Approximates -round(log2(6.3*cutoff_Hz/Fs)) */ + shift=celt_ilog2(Fs/(cutoff_Hz*4)); + for (c=0;cFs/400; + if (st->user_bitrate_bps==OPUS_AUTO) + return 60*st->Fs/frame_size + st->Fs*st->channels; + else if (st->user_bitrate_bps==OPUS_BITRATE_MAX) + return max_data_bytes*8*st->Fs/frame_size; + else + return st->user_bitrate_bps; +} + +#ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT +#define PCM2VAL(x) FLOAT2INT16(x) +#else +#define PCM2VAL(x) SCALEIN(x) +#endif + +void downmix_float(const void *_x, opus_val32 *y, int subframe, int offset, int c1, int c2, int C) +{ + const float *x; + int j; + + x = (const float *)_x; + for (j=0;j-1) + { + for (j=0;j-1) + { + for (j=0;j= OPUS_FRAMESIZE_2_5_MS && variable_duration <= OPUS_FRAMESIZE_120_MS) + { + if (variable_duration <= OPUS_FRAMESIZE_40_MS) + new_size = (Fs/400)<<(variable_duration-OPUS_FRAMESIZE_2_5_MS); + else + new_size = (variable_duration-OPUS_FRAMESIZE_2_5_MS-2)*Fs/50; + } + else + return -1; + if (new_size>frame_size) + return -1; + if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs && + 50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs && + 50*new_size!=4*Fs && 50*new_size!=5*Fs && 50*new_size!=6*Fs) + return -1; + return new_size; +} + +opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem) +{ + opus_val32 xx, xy, yy; + opus_val16 sqrt_xx, sqrt_yy; + opus_val16 qrrt_xx, qrrt_yy; + int frame_rate; + int i; + opus_val16 short_alpha; + + frame_rate = Fs/frame_size; + short_alpha = Q15ONE - MULT16_16(25, Q15ONE)/IMAX(50,frame_rate); + xx=xy=yy=0; + /* Unroll by 4. The frame size is always a multiple of 4 *except* for + 2.5 ms frames at 12 kHz. Since this setting is very rare (and very + stupid), we just discard the last two samples. */ + for (i=0;iXX += MULT16_32_Q15(short_alpha, xx-mem->XX); + mem->XY += MULT16_32_Q15(short_alpha, xy-mem->XY); + mem->YY += MULT16_32_Q15(short_alpha, yy-mem->YY); + mem->XX = MAX32(0, mem->XX); + mem->XY = MAX32(0, mem->XY); + mem->YY = MAX32(0, mem->YY); + if (MAX32(mem->XX, mem->YY)>QCONST16(8e-4f, 18)) + { + opus_val16 corr; + opus_val16 ldiff; + opus_val16 width; + sqrt_xx = celt_sqrt(mem->XX); + sqrt_yy = celt_sqrt(mem->YY); + qrrt_xx = celt_sqrt(sqrt_xx); + qrrt_yy = celt_sqrt(sqrt_yy); + /* Inter-channel correlation */ + mem->XY = MIN32(mem->XY, sqrt_xx*sqrt_yy); + corr = SHR32(frac_div32(mem->XY,EPSILON+MULT16_16(sqrt_xx,sqrt_yy)),16); + /* Approximate loudness difference */ + ldiff = MULT16_16(Q15ONE, ABS16(qrrt_xx-qrrt_yy))/(EPSILON+qrrt_xx+qrrt_yy); + width = MULT16_16_Q15(celt_sqrt(QCONST32(1.f,30)-MULT16_16(corr,corr)), ldiff); + /* Smoothing over one second */ + mem->smoothed_width += (width-mem->smoothed_width)/frame_rate; + /* Peak follower */ + mem->max_follower = MAX16(mem->max_follower-QCONST16(.02f,15)/frame_rate, mem->smoothed_width); + } + /*printf("%f %f %f %f %f ", corr/(float)Q15ONE, ldiff/(float)Q15ONE, width/(float)Q15ONE, mem->smoothed_width/(float)Q15ONE, mem->max_follower/(float)Q15ONE);*/ + return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower))); +} + +static int decide_fec(int useInBandFEC, int PacketLoss_perc, int last_fec, int mode, int *bandwidth, opus_int32 rate) +{ + int orig_bandwidth; + if (!useInBandFEC || PacketLoss_perc == 0 || mode == MODE_CELT_ONLY) + return 0; + orig_bandwidth = *bandwidth; + for (;;) + { + opus_int32 hysteresis; + opus_int32 LBRR_rate_thres_bps; + /* Compute threshold for using FEC at the current bandwidth setting */ + LBRR_rate_thres_bps = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND)]; + hysteresis = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND) + 1]; + if (last_fec == 1) LBRR_rate_thres_bps -= hysteresis; + if (last_fec == 0) LBRR_rate_thres_bps += hysteresis; + LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, + 125 - silk_min( PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); + /* If loss <= 5%, we look at whether we have enough rate to enable FEC. + If loss > 5%, we decrease the bandwidth until we can enable FEC. */ + if (rate > LBRR_rate_thres_bps) + return 1; + else if (PacketLoss_perc <= 5) + return 0; + else if (*bandwidth > OPUS_BANDWIDTH_NARROWBAND) + (*bandwidth)--; + else + break; + } + /* Couldn't find any bandwidth to enable FEC, keep original bandwidth. */ + *bandwidth = orig_bandwidth; + return 0; +} + +static int compute_silk_rate_for_hybrid(int rate, int bandwidth, int frame20ms, int vbr, int fec, int channels) { + int entry; + int i; + int N; + int silk_rate; + static int rate_table[][5] = { + /* |total| |-------- SILK------------| + |-- No FEC -| |--- FEC ---| + 10ms 20ms 10ms 20ms */ + { 0, 0, 0, 0, 0}, + {12000, 10000, 10000, 11000, 11000}, + {16000, 13500, 13500, 15000, 15000}, + {20000, 16000, 16000, 18000, 18000}, + {24000, 18000, 18000, 21000, 21000}, + {32000, 22000, 22000, 28000, 28000}, + {64000, 38000, 38000, 50000, 50000} + }; + /* Do the allocation per-channel. */ + rate /= channels; + entry = 1 + frame20ms + 2*fec; + N = sizeof(rate_table)/sizeof(rate_table[0]); + for (i=1;i rate) break; + } + if (i == N) + { + silk_rate = rate_table[i-1][entry]; + /* For now, just give 50% of the extra bits to SILK. */ + silk_rate += (rate-rate_table[i-1][0])/2; + } else { + opus_int32 lo, hi, x0, x1; + lo = rate_table[i-1][entry]; + hi = rate_table[i][entry]; + x0 = rate_table[i-1][0]; + x1 = rate_table[i][0]; + silk_rate = (lo*(x1-rate) + hi*(rate-x0))/(x1-x0); + } + if (!vbr) + { + /* Tiny boost to SILK for CBR. We should probably tune this better. */ + silk_rate += 100; + } + if (bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND) + silk_rate += 300; + silk_rate *= channels; + /* Small adjustment for stereo (calibrated for 32 kb/s, haven't tried other bitrates). */ + if (channels == 2 && rate >= 12000) + silk_rate -= 1000; + return silk_rate; +} + +/* Returns the equivalent bitrate corresponding to 20 ms frames, + complexity 10 VBR operation. */ +static opus_int32 compute_equiv_rate(opus_int32 bitrate, int channels, + int frame_rate, int vbr, int mode, int complexity, int loss) +{ + opus_int32 equiv; + equiv = bitrate; + /* Take into account overhead from smaller frames. */ + if (frame_rate > 50) + equiv -= (40*channels+20)*(frame_rate - 50); + /* CBR is about a 8% penalty for both SILK and CELT. */ + if (!vbr) + equiv -= equiv/12; + /* Complexity makes about 10% difference (from 0 to 10) in general. */ + equiv = equiv * (90+complexity)/100; + if (mode == MODE_SILK_ONLY || mode == MODE_HYBRID) + { + /* SILK complexity 0-1 uses the non-delayed-decision NSQ, which + costs about 20%. */ + if (complexity<2) + equiv = equiv*4/5; + equiv -= equiv*loss/(6*loss + 10); + } else if (mode == MODE_CELT_ONLY) { + /* CELT complexity 0-4 doesn't have the pitch filter, which costs + about 10%. */ + if (complexity<5) + equiv = equiv*9/10; + } else { + /* Mode not known yet */ + /* Half the SILK loss*/ + equiv -= equiv*loss/(12*loss + 20); + } + return equiv; +} + +#ifndef DISABLE_FLOAT_API + +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth) +{ + int silence = 0; + opus_val32 sample_max = 0; +#ifdef MLP_TRAINING + return 0; +#endif + sample_max = celt_maxabs16(pcm, frame_size*channels); + +#ifdef FIXED_POINT + silence = (sample_max == 0); + (void)lsb_depth; +#else + silence = (sample_max <= (opus_val16) 1 / (1 << lsb_depth)); +#endif + + return silence; +} + +#ifdef FIXED_POINT +static opus_val32 compute_frame_energy(const opus_val16 *pcm, int frame_size, int channels, int arch) +{ + int i; + opus_val32 sample_max; + int max_shift; + int shift; + opus_val32 energy = 0; + int len = frame_size*channels; + (void)arch; + /* Max amplitude in the signal */ + sample_max = celt_maxabs16(pcm, len); + + /* Compute the right shift required in the MAC to avoid an overflow */ + max_shift = celt_ilog2(len); + shift = IMAX(0, (celt_ilog2(sample_max) << 1) + max_shift - 28); + + /* Compute the energy */ + for (i=0; i= (PSEUDO_SNR_THRESHOLD * noise_energy); + } + } + + if (is_silence) + { + /* The number of consecutive DTX frames should be within the allowed bounds */ + (*nb_no_activity_frames)++; + + if (*nb_no_activity_frames > NB_SPEECH_FRAMES_BEFORE_DTX) + { + if (*nb_no_activity_frames <= (NB_SPEECH_FRAMES_BEFORE_DTX + MAX_CONSECUTIVE_DTX)) + /* Valid frame for DTX! */ + return 1; + else + (*nb_no_activity_frames) = NB_SPEECH_FRAMES_BEFORE_DTX; + } + } else + (*nb_no_activity_frames) = 0; + + return 0; +} + +#endif + +static opus_int32 encode_multiframe_packet(OpusEncoder *st, + const opus_val16 *pcm, + int nb_frames, + int frame_size, + unsigned char *data, + opus_int32 out_data_bytes, + int to_celt, + int lsb_depth, + int float_api) +{ + int i; + int ret = 0; + VARDECL(unsigned char, tmp_data); + int bak_mode, bak_bandwidth, bak_channels, bak_to_mono; + VARDECL(OpusRepacketizer, rp); + int max_header_bytes; + opus_int32 bytes_per_frame; + opus_int32 cbr_bytes; + opus_int32 repacketize_len; + int tmp_len; + ALLOC_STACK; + + /* Worst cases: + * 2 frames: Code 2 with different compressed sizes + * >2 frames: Code 3 VBR */ + max_header_bytes = nb_frames == 2 ? 3 : (2+(nb_frames-1)*2); + + if (st->use_vbr || st->user_bitrate_bps==OPUS_BITRATE_MAX) + repacketize_len = out_data_bytes; + else { + cbr_bytes = 3*st->bitrate_bps/(3*8*st->Fs/(frame_size*nb_frames)); + repacketize_len = IMIN(cbr_bytes, out_data_bytes); + } + bytes_per_frame = IMIN(1276, 1+(repacketize_len-max_header_bytes)/nb_frames); + + ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char); + ALLOC(rp, 1, OpusRepacketizer); + opus_repacketizer_init(rp); + + bak_mode = st->user_forced_mode; + bak_bandwidth = st->user_bandwidth; + bak_channels = st->force_channels; + + st->user_forced_mode = st->mode; + st->user_bandwidth = st->bandwidth; + st->force_channels = st->stream_channels; + + bak_to_mono = st->silk_mode.toMono; + if (bak_to_mono) + st->force_channels = 1; + else + st->prev_channels = st->stream_channels; + + for (i=0;isilk_mode.toMono = 0; + st->nonfinal_frame = i<(nb_frames-1); + + /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */ + if (to_celt && i==nb_frames-1) + st->user_forced_mode = MODE_CELT_ONLY; + + tmp_len = opus_encode_native(st, pcm+i*(st->channels*frame_size), frame_size, + tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth, NULL, 0, 0, 0, 0, + NULL, float_api); + + if (tmp_len<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len); + + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + + ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr); + + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + /* Discard configs that were forced locally for the purpose of repacketization */ + st->user_forced_mode = bak_mode; + st->user_bandwidth = bak_bandwidth; + st->force_channels = bak_channels; + st->silk_mode.toMono = bak_to_mono; + + RESTORE_STACK; + return ret; +} + +static int compute_redundancy_bytes(opus_int32 max_data_bytes, opus_int32 bitrate_bps, int frame_rate, int channels) +{ + int redundancy_bytes_cap; + int redundancy_bytes; + opus_int32 redundancy_rate; + int base_bits; + opus_int32 available_bits; + base_bits = (40*channels+20); + + /* Equivalent rate for 5 ms frames. */ + redundancy_rate = bitrate_bps + base_bits*(200 - frame_rate); + /* For VBR, further increase the bitrate if we can afford it. It's pretty short + and we'll avoid artefacts. */ + redundancy_rate = 3*redundancy_rate/2; + redundancy_bytes = redundancy_rate/1600; + + /* Compute the max rate we can use given CBR or VBR with cap. */ + available_bits = max_data_bytes*8 - 2*base_bits; + redundancy_bytes_cap = (available_bits*240/(240+48000/frame_rate) + base_bits)/8; + redundancy_bytes = IMIN(redundancy_bytes, redundancy_bytes_cap); + /* It we can't get enough bits for redundancy to be worth it, rely on the decoder PLC. */ + if (redundancy_bytes > 4 + 8*channels) + redundancy_bytes = IMIN(257, redundancy_bytes); + else + redundancy_bytes = 0; + return redundancy_bytes; +} + +opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, + const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, + int analysis_channels, downmix_func downmix, int float_api) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int i; + int ret=0; + opus_int32 nBytes; + ec_enc enc; + int bytes_target; + int prefill=0; + int start_band = 0; + int redundancy = 0; + int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */ + int celt_to_silk = 0; + VARDECL(opus_val16, pcm_buf); + int nb_compr_bytes; + int to_celt = 0; + opus_uint32 redundant_rng = 0; + int cutoff_Hz, hp_freq_smth1; + int voice_est; /* Probability of voice in Q7 */ + opus_int32 equiv_rate; + int delay_compensation; + int frame_rate; + opus_int32 max_rate; /* Max bitrate we're allowed to use */ + int curr_bandwidth; + opus_val16 HB_gain; + opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */ + int total_buffer; + opus_val16 stereo_width; + const CELTMode *celt_mode; +#ifndef DISABLE_FLOAT_API + AnalysisInfo analysis_info; + int analysis_read_pos_bak=-1; + int analysis_read_subframe_bak=-1; + int is_silence = 0; +#endif + VARDECL(opus_val16, tmp_prefill); + + ALLOC_STACK; + + max_data_bytes = IMIN(1276, out_data_bytes); + + st->rangeFinal = 0; + if (frame_size <= 0 || max_data_bytes <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Cannot encode 100 ms in 1 byte */ + if (max_data_bytes==1 && st->Fs==(frame_size*10)) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + + lsb_depth = IMIN(lsb_depth, st->lsb_depth); + + celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode)); +#ifndef DISABLE_FLOAT_API + analysis_info.valid = 0; +#ifdef FIXED_POINT + if (st->silk_mode.complexity >= 10 && st->Fs>=16000) +#else + if (st->silk_mode.complexity >= 7 && st->Fs>=16000) +#endif + { + is_silence = is_digital_silence(pcm, frame_size, st->channels, lsb_depth); + analysis_read_pos_bak = st->analysis.read_pos; + analysis_read_subframe_bak = st->analysis.read_subframe; + run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size, + c1, c2, analysis_channels, st->Fs, + lsb_depth, downmix, &analysis_info); + + /* Track the peak signal energy */ + if (!is_silence && analysis_info.activity_probability > DTX_ACTIVITY_THRESHOLD) + st->peak_signal_energy = MAX32(MULT16_32_Q15(QCONST16(0.999f, 15), st->peak_signal_energy), + compute_frame_energy(pcm, frame_size, st->channels, st->arch)); + } else if (st->analysis.initialized) { + tonality_analysis_reset(&st->analysis); + } +#else + (void)analysis_pcm; + (void)analysis_size; + (void)c1; + (void)c2; + (void)analysis_channels; + (void)downmix; +#endif + +#ifndef DISABLE_FLOAT_API + /* Reset voice_ratio if this frame is not silent or if analysis is disabled. + * Otherwise, preserve voice_ratio from the last non-silent frame */ + if (!is_silence) + st->voice_ratio = -1; + + st->detected_bandwidth = 0; + if (analysis_info.valid) + { + int analysis_bandwidth; + if (st->signal_type == OPUS_AUTO) + { + float prob; + if (st->prev_mode == 0) + prob = analysis_info.music_prob; + else if (st->prev_mode == MODE_CELT_ONLY) + prob = analysis_info.music_prob_max; + else + prob = analysis_info.music_prob_min; + st->voice_ratio = (int)floor(.5+100*(1-prob)); + } + + analysis_bandwidth = analysis_info.bandwidth; + if (analysis_bandwidth<=12) + st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (analysis_bandwidth<=14) + st->detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (analysis_bandwidth<=16) + st->detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (analysis_bandwidth<=18) + st->detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else + st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; + } +#else + st->voice_ratio = -1; +#endif + + if (st->channels==2 && st->force_channels!=1) + stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem); + else + stereo_width = 0; + total_buffer = delay_compensation; + st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes); + + frame_rate = st->Fs/frame_size; + if (!st->use_vbr) + { + int cbrBytes; + /* Multiply by 12 to make sure the division is exact. */ + int frame_rate12 = 12*st->Fs/frame_size; + /* We need to make sure that "int" values always fit in 16 bits. */ + cbrBytes = IMIN( (12*st->bitrate_bps/8 + frame_rate12/2)/frame_rate12, max_data_bytes); + st->bitrate_bps = cbrBytes*(opus_int32)frame_rate12*8/12; + /* Make sure we provide at least one byte to avoid failing. */ + max_data_bytes = IMAX(1, cbrBytes); + } + if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8 + || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400))) + { + /*If the space is too low to do something useful, emit 'PLC' frames.*/ + int tocmode = st->mode; + int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth; + int packet_code = 0; + int num_multiframes = 0; + + if (tocmode==0) + tocmode = MODE_SILK_ONLY; + if (frame_rate>100) + tocmode = MODE_CELT_ONLY; + /* 40 ms -> 2 x 20 ms if in CELT_ONLY or HYBRID mode */ + if (frame_rate==25 && tocmode!=MODE_SILK_ONLY) + { + frame_rate = 50; + packet_code = 1; + } + + /* >= 60 ms frames */ + if (frame_rate<=16) + { + /* 1 x 60 ms, 2 x 40 ms, 2 x 60 ms */ + if (out_data_bytes==1 || (tocmode==MODE_SILK_ONLY && frame_rate!=10)) + { + tocmode = MODE_SILK_ONLY; + + packet_code = frame_rate <= 12; + frame_rate = frame_rate == 12 ? 25 : 16; + } + else + { + num_multiframes = 50/frame_rate; + frame_rate = 50; + packet_code = 3; + } + } + + if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND) + bw=OPUS_BANDWIDTH_WIDEBAND; + else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND) + bw=OPUS_BANDWIDTH_NARROWBAND; + else if (tocmode==MODE_HYBRID&&bw<=OPUS_BANDWIDTH_SUPERWIDEBAND) + bw=OPUS_BANDWIDTH_SUPERWIDEBAND; + + data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels); + data[0] |= packet_code; + + ret = packet_code <= 1 ? 1 : 2; + + max_data_bytes = IMAX(max_data_bytes, ret); + + if (packet_code==3) + data[1] = num_multiframes; + + if (!st->use_vbr) + { + ret = opus_packet_pad(data, ret, max_data_bytes); + if (ret == OPUS_OK) + ret = max_data_bytes; + else + ret = OPUS_INTERNAL_ERROR; + } + RESTORE_STACK; + return ret; + } + max_rate = frame_rate*max_data_bytes*8; + + /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->channels, st->Fs/frame_size, + st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + if (st->signal_type == OPUS_SIGNAL_VOICE) + voice_est = 127; + else if (st->signal_type == OPUS_SIGNAL_MUSIC) + voice_est = 0; + else if (st->voice_ratio >= 0) + { + voice_est = st->voice_ratio*327>>8; + /* For AUDIO, never be more than 90% confident of having speech */ + if (st->application == OPUS_APPLICATION_AUDIO) + voice_est = IMIN(voice_est, 115); + } else if (st->application == OPUS_APPLICATION_VOIP) + voice_est = 115; + else + voice_est = 48; + + if (st->force_channels!=OPUS_AUTO && st->channels == 2) + { + st->stream_channels = st->force_channels; + } else { +#ifdef FUZZING + /* Random mono/stereo decision */ + if (st->channels == 2 && (rand()&0x1F)==0) + st->stream_channels = 3-st->stream_channels; +#else + /* Rate-dependent mono-stereo decision */ + if (st->channels == 2) + { + opus_int32 stereo_threshold; + stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14); + if (st->stream_channels == 2) + stereo_threshold -= 1000; + else + stereo_threshold += 1000; + st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1; + } else { + st->stream_channels = st->channels; + } +#endif + } + /* Update equivalent rate for channels decision. */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, + st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + /* Allow SILK DTX if DTX is enabled but the generalized DTX cannot be used, + e.g. because of the complexity setting or sample rate. */ +#ifndef DISABLE_FLOAT_API + st->silk_mode.useDTX = st->use_dtx && !(analysis_info.valid || is_silence); +#else + st->silk_mode.useDTX = st->use_dtx; +#endif + + /* Mode selection depending on application and signal type */ + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + { + st->mode = MODE_CELT_ONLY; + } else if (st->user_forced_mode == OPUS_AUTO) + { +#ifdef FUZZING + /* Random mode switching */ + if ((rand()&0xF)==0) + { + if ((rand()&0x1)==0) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } else { + if (st->prev_mode==MODE_CELT_ONLY) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } +#else + opus_int32 mode_voice, mode_music; + opus_int32 threshold; + + /* Interpolate based on stereo width */ + mode_voice = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[0][0]) + + MULT16_32_Q15(stereo_width,mode_thresholds[1][0])); + mode_music = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[1][1]) + + MULT16_32_Q15(stereo_width,mode_thresholds[1][1])); + /* Interpolate based on speech/music probability */ + threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14); + /* Bias towards SILK for VoIP because of some useful features */ + if (st->application == OPUS_APPLICATION_VOIP) + threshold += 8000; + + /*printf("%f %d\n", stereo_width/(float)Q15ONE, threshold);*/ + /* Hysteresis */ + if (st->prev_mode == MODE_CELT_ONLY) + threshold -= 4000; + else if (st->prev_mode>0) + threshold += 4000; + + st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY; + + /* When FEC is enabled and there's enough packet loss, use SILK */ + if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4) + st->mode = MODE_SILK_ONLY; + /* When encoding voice and DTX is enabled but the generalized DTX cannot be used, + use SILK in order to make use of its DTX. */ + if (st->silk_mode.useDTX && voice_est > 100) + st->mode = MODE_SILK_ONLY; +#endif + + /* If max_data_bytes represents less than 6 kb/s, switch to CELT-only mode */ + if (max_data_bytes < (frame_rate > 50 ? 9000 : 6000)*frame_size / (st->Fs * 8)) + st->mode = MODE_CELT_ONLY; + } else { + st->mode = st->user_forced_mode; + } + + /* Override the chosen mode to make sure we meet the requested frame size */ + if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100) + st->mode = MODE_CELT_ONLY; + if (st->lfe) + st->mode = MODE_CELT_ONLY; + + if (st->prev_mode > 0 && + ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) || + (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY))) + { + redundancy = 1; + celt_to_silk = (st->mode != MODE_CELT_ONLY); + if (!celt_to_silk) + { + /* Switch to SILK/hybrid if frame size is 10 ms or more*/ + if (frame_size >= st->Fs/100) + { + st->mode = st->prev_mode; + to_celt = 1; + } else { + redundancy=0; + } + } + } + + /* When encoding multiframes, we can ask for a switch to CELT only in the last frame. This switch + * is processed above as the requested mode shouldn't interrupt stereo->mono transition. */ + if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0 + && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY) + { + /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */ + st->silk_mode.toMono = 1; + st->stream_channels = 2; + } else { + st->silk_mode.toMono = 0; + } + + /* Update equivalent rate with mode decision. */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, + st->use_vbr, st->mode, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) + { + silk_EncControlStruct dummy; + silk_InitEncoder( silk_enc, st->arch, &dummy); + prefill=1; + } + + /* Automatic (rate-dependent) bandwidth selection */ + if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch) + { + const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds; + opus_int32 bandwidth_thresholds[8]; + int bandwidth = OPUS_BANDWIDTH_FULLBAND; + + if (st->channels==2 && st->force_channels!=1) + { + voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds; + music_bandwidth_thresholds = stereo_music_bandwidth_thresholds; + } else { + voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds; + music_bandwidth_thresholds = mono_music_bandwidth_thresholds; + } + /* Interpolate bandwidth thresholds depending on voice estimation */ + for (i=0;i<8;i++) + { + bandwidth_thresholds[i] = music_bandwidth_thresholds[i] + + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14); + } + do { + int threshold, hysteresis; + threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)]; + hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1]; + if (!st->first) + { + if (st->auto_bandwidth >= bandwidth) + threshold -= hysteresis; + else + threshold += hysteresis; + } + if (equiv_rate >= threshold) + break; + } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND); + /* We don't use mediumband anymore, except when explicitly requested or during + mode transitions. */ + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_WIDEBAND; + st->bandwidth = st->auto_bandwidth = bandwidth; + /* Prevents any transition to SWB/FB until the SILK layer has fully + switched to WB mode and turned the variable LP filter off */ + if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + + if (st->bandwidth>st->max_bandwidth) + st->bandwidth = st->max_bandwidth; + + if (st->user_bandwidth != OPUS_AUTO) + st->bandwidth = st->user_bandwidth; + + /* This prevents us from using hybrid at unsafe CBR/max rates */ + if (st->mode != MODE_CELT_ONLY && max_rate < 15000) + { + st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND); + } + + /* Prevents Opus from wasting bits on frequencies that are above + the Nyquist rate of the input signal */ + if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; +#ifndef DISABLE_FLOAT_API + /* Use detected bandwidth to reduce the encoded bandwidth. */ + if (st->detected_bandwidth && st->user_bandwidth == OPUS_AUTO) + { + int min_detected_bandwidth; + /* Makes bandwidth detection more conservative just in case the detector + gets it wrong when we could have coded a high bandwidth transparently. + When operating in SILK/hybrid mode, we don't go below wideband to avoid + more complicated switches that require redundancy. */ + if (equiv_rate <= 18000*st->stream_channels && st->mode == MODE_CELT_ONLY) + min_detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (equiv_rate <= 24000*st->stream_channels && st->mode == MODE_CELT_ONLY) + min_detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (equiv_rate <= 30000*st->stream_channels) + min_detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (equiv_rate <= 44000*st->stream_channels) + min_detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else + min_detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; + + st->detected_bandwidth = IMAX(st->detected_bandwidth, min_detected_bandwidth); + st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth); + } +#endif + st->silk_mode.LBRR_coded = decide_fec(st->silk_mode.useInBandFEC, st->silk_mode.packetLossPercentage, + st->silk_mode.LBRR_coded, st->mode, &st->bandwidth, equiv_rate); + celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth)); + + /* CELT mode doesn't support mediumband, use wideband instead */ + if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->lfe) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; + + curr_bandwidth = st->bandwidth; + + /* Chooses the appropriate mode for speech + *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */ + if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_HYBRID; + if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_SILK_ONLY; + + /* Can't support higher than >60 ms frames, and >20 ms when in Hybrid or CELT-only modes */ + if ((frame_size > st->Fs/50 && (st->mode != MODE_SILK_ONLY)) || frame_size > 3*st->Fs/50) + { + int enc_frame_size; + int nb_frames; + + if (st->mode == MODE_SILK_ONLY) + { + if (frame_size == 2*st->Fs/25) /* 80 ms -> 2x 40 ms */ + enc_frame_size = st->Fs/25; + else if (frame_size == 3*st->Fs/25) /* 120 ms -> 2x 60 ms */ + enc_frame_size = 3*st->Fs/50; + else /* 100 ms -> 5x 20 ms */ + enc_frame_size = st->Fs/50; + } + else + enc_frame_size = st->Fs/50; + + nb_frames = frame_size/enc_frame_size; + +#ifndef DISABLE_FLOAT_API + if (analysis_read_pos_bak!= -1) + { + st->analysis.read_pos = analysis_read_pos_bak; + st->analysis.read_subframe = analysis_read_subframe_bak; + } +#endif + + ret = encode_multiframe_packet(st, pcm, nb_frames, enc_frame_size, data, + out_data_bytes, to_celt, lsb_depth, float_api); + + RESTORE_STACK; + return ret; + } + + /* For the first frame at a new SILK bandwidth */ + if (st->silk_bw_switch) + { + redundancy = 1; + celt_to_silk = 1; + st->silk_bw_switch = 0; + /* Do a prefill without reseting the sampling rate control. */ + prefill=2; + } + + /* If we decided to go with CELT, make sure redundancy is off, no matter what + we decided earlier. */ + if (st->mode == MODE_CELT_ONLY) + redundancy = 0; + + if (redundancy) + { + redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); + if (redundancy_bytes == 0) + redundancy = 0; + } + + /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */ + bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1; + + data += 1; + + ec_enc_init(&enc, data, max_data_bytes-1); + + ALLOC(pcm_buf, (total_buffer+frame_size)*st->channels, opus_val16); + OPUS_COPY(pcm_buf, &st->delay_buffer[(st->encoder_buffer-total_buffer)*st->channels], total_buffer*st->channels); + + if (st->mode == MODE_CELT_ONLY) + hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + else + hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15; + + st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15, + hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) ); + + /* convert from log scale to Hertz */ + cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) ); + + if (st->application == OPUS_APPLICATION_VOIP) + { + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs, st->arch); + } else { + dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); + } +#ifndef FIXED_POINT + if (float_api) + { + opus_val32 sum; + sum = celt_inner_prod(&pcm_buf[total_buffer*st->channels], &pcm_buf[total_buffer*st->channels], frame_size*st->channels, st->arch); + /* This should filter out both NaNs and ridiculous signals that could + cause NaNs further down. */ + if (!(sum < 1e9f) || celt_isnan(sum)) + { + OPUS_CLEAR(&pcm_buf[total_buffer*st->channels], frame_size*st->channels); + st->hp_mem[0] = st->hp_mem[1] = st->hp_mem[2] = st->hp_mem[3] = 0; + } + } +#endif + + + /* SILK processing */ + HB_gain = Q15ONE; + if (st->mode != MODE_CELT_ONLY) + { + opus_int32 total_bitRate, celt_rate; + opus_int activity; +#ifdef FIXED_POINT + const opus_int16 *pcm_silk; +#else + VARDECL(opus_int16, pcm_silk); + ALLOC(pcm_silk, st->channels*frame_size, opus_int16); +#endif + + activity = VAD_NO_DECISION; +#ifndef DISABLE_FLOAT_API + if( analysis_info.valid ) { + /* Inform SILK about the Opus VAD decision */ + activity = ( analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD ); + } +#endif + + /* Distribute bits between SILK and CELT */ + total_bitRate = 8 * bytes_target * frame_rate; + if( st->mode == MODE_HYBRID ) { + /* Base rate for SILK */ + st->silk_mode.bitRate = compute_silk_rate_for_hybrid(total_bitRate, + curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded, + st->stream_channels); + if (!st->energy_masking) + { + /* Increasingly attenuate high band when it gets allocated fewer bits */ + celt_rate = total_bitRate - st->silk_mode.bitRate; + HB_gain = Q15ONE - SHR32(celt_exp2(-celt_rate * QCONST16(1.f/1024, 10)), 1); + } + } else { + /* SILK gets all bits */ + st->silk_mode.bitRate = total_bitRate; + } + + /* Surround masking for SILK */ + if (st->energy_masking && st->use_vbr && !st->lfe) + { + opus_val32 mask_sum=0; + opus_val16 masking_depth; + opus_int32 rate_offset; + int c; + int end = 17; + opus_int16 srate = 16000; + if (st->bandwidth == OPUS_BANDWIDTH_NARROWBAND) + { + end = 13; + srate = 8000; + } else if (st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + { + end = 15; + srate = 12000; + } + for (c=0;cchannels;c++) + { + for(i=0;ienergy_masking[21*c+i], + QCONST16(.5f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT)); + if (mask > 0) + mask = HALF16(mask); + mask_sum += mask; + } + } + /* Conservative rate reduction, we cut the masking in half */ + masking_depth = mask_sum / end*st->channels; + masking_depth += QCONST16(.2f, DB_SHIFT); + rate_offset = (opus_int32)PSHR32(MULT16_16(srate, masking_depth), DB_SHIFT); + rate_offset = MAX32(rate_offset, -2*st->silk_mode.bitRate/3); + /* Split the rate change between the SILK and CELT part for hybrid. */ + if (st->bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND || st->bandwidth==OPUS_BANDWIDTH_FULLBAND) + st->silk_mode.bitRate += 3*rate_offset/5; + else + st->silk_mode.bitRate += rate_offset; + } + + st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs; + st->silk_mode.nChannelsAPI = st->channels; + st->silk_mode.nChannelsInternal = st->stream_channels; + if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.desiredInternalSampleRate = 8000; + } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.desiredInternalSampleRate = 12000; + } else { + celt_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND ); + st->silk_mode.desiredInternalSampleRate = 16000; + } + if( st->mode == MODE_HYBRID ) { + /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */ + st->silk_mode.minInternalSampleRate = 16000; + } else { + st->silk_mode.minInternalSampleRate = 8000; + } + + st->silk_mode.maxInternalSampleRate = 16000; + if (st->mode == MODE_SILK_ONLY) + { + opus_int32 effective_max_rate = max_rate; + if (frame_rate > 50) + effective_max_rate = effective_max_rate*2/3; + if (effective_max_rate < 8000) + { + st->silk_mode.maxInternalSampleRate = 12000; + st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate); + } + if (effective_max_rate < 7000) + { + st->silk_mode.maxInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate); + } + } + + st->silk_mode.useCBR = !st->use_vbr; + + /* Call SILK encoder for the low band */ + + /* Max bits for SILK, counting ToC, redundancy bytes, and optionally redundancy. */ + st->silk_mode.maxBits = (max_data_bytes-1)*8; + if (redundancy && redundancy_bytes >= 2) + { + /* Counting 1 bit for redundancy position and 20 bits for flag+size (only for hybrid). */ + st->silk_mode.maxBits -= redundancy_bytes*8 + 1; + if (st->mode == MODE_HYBRID) + st->silk_mode.maxBits -= 20; + } + if (st->silk_mode.useCBR) + { + if (st->mode == MODE_HYBRID) + { + st->silk_mode.maxBits = IMIN(st->silk_mode.maxBits, st->silk_mode.bitRate * frame_size / st->Fs); + } + } else { + /* Constrained VBR. */ + if (st->mode == MODE_HYBRID) + { + /* Compute SILK bitrate corresponding to the max total bits available */ + opus_int32 maxBitRate = compute_silk_rate_for_hybrid(st->silk_mode.maxBits*st->Fs / frame_size, + curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded, + st->stream_channels); + st->silk_mode.maxBits = maxBitRate * frame_size / st->Fs; + } + } + + if (prefill) + { + opus_int32 zero=0; + int prefill_offset; + /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode + a discontinuity. The exact location is what we need to avoid leaving any "gap" + in the audio when mixing with the redundant CELT frame. Here we can afford to + overwrite st->delay_buffer because the only thing that uses it before it gets + rewritten is tmp_prefill[] and even then only the part after the ramp really + gets used (rather than sent to the encoder and discarded) */ + prefill_offset = st->channels*(st->encoder_buffer-st->delay_compensation-st->Fs/400); + gain_fade(st->delay_buffer+prefill_offset, st->delay_buffer+prefill_offset, + 0, Q15ONE, celt_mode->overlap, st->Fs/400, st->channels, celt_mode->window, st->Fs); + OPUS_CLEAR(st->delay_buffer, prefill_offset); +#ifdef FIXED_POINT + pcm_silk = st->delay_buffer; +#else + for (i=0;iencoder_buffer*st->channels;i++) + pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]); +#endif + silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, prefill, activity ); + /* Prevent a second switch in the real encode call. */ + st->silk_mode.opusCanSwitch = 0; + } + +#ifdef FIXED_POINT + pcm_silk = pcm_buf+total_buffer*st->channels; +#else + for (i=0;ichannels;i++) + pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]); +#endif + ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0, activity ); + if( ret ) { + /*fprintf (stderr, "SILK encode error: %d\n", ret);*/ + /* Handle error */ + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + /* Extract SILK internal bandwidth for signaling in first byte */ + if( st->mode == MODE_SILK_ONLY ) { + if( st->silk_mode.internalSampleRate == 8000 ) { + curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if( st->silk_mode.internalSampleRate == 12000 ) { + curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + } else if( st->silk_mode.internalSampleRate == 16000 ) { + curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + } else { + celt_assert( st->silk_mode.internalSampleRate == 16000 ); + } + + st->silk_mode.opusCanSwitch = st->silk_mode.switchReady && !st->nonfinal_frame; + + if (nBytes==0) + { + st->rangeFinal = 0; + data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + + /* FIXME: How do we allocate the redundancy for CBR? */ + if (st->silk_mode.opusCanSwitch) + { + redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); + redundancy = (redundancy_bytes != 0); + celt_to_silk = 0; + st->silk_bw_switch = 1; + } + } + + /* CELT processing */ + { + int endband=21; + + switch(curr_bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + } + celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband)); + celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels)); + } + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + if (st->mode != MODE_SILK_ONLY) + { + opus_val32 celt_pred=2; + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + /* We may still decide to disable prediction later */ + if (st->silk_mode.reducedDependency) + celt_pred = 0; + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred)); + + if (st->mode == MODE_HYBRID) + { + if( st->use_vbr ) { + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); + } + } else { + if (st->use_vbr) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); + } + } + } + + ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); + if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0) + { + OPUS_COPY(tmp_prefill, &st->delay_buffer[(st->encoder_buffer-total_buffer-st->Fs/400)*st->channels], st->channels*st->Fs/400); + } + + if (st->channels*(st->encoder_buffer-(frame_size+total_buffer)) > 0) + { + OPUS_MOVE(st->delay_buffer, &st->delay_buffer[st->channels*frame_size], st->channels*(st->encoder_buffer-frame_size-total_buffer)); + OPUS_COPY(&st->delay_buffer[st->channels*(st->encoder_buffer-frame_size-total_buffer)], + &pcm_buf[0], + (frame_size+total_buffer)*st->channels); + } else { + OPUS_COPY(st->delay_buffer, &pcm_buf[(frame_size+total_buffer-st->encoder_buffer)*st->channels], st->encoder_buffer*st->channels); + } + /* gain_fade() and stereo_fade() need to be after the buffer copying + because we don't want any of this to affect the SILK part */ + if( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) { + gain_fade(pcm_buf, pcm_buf, + st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs); + } + st->prev_HB_gain = HB_gain; + if (st->mode != MODE_HYBRID || st->stream_channels==1) + { + if (equiv_rate > 32000) + st->silk_mode.stereoWidth_Q14 = 16384; + else if (equiv_rate < 16000) + st->silk_mode.stereoWidth_Q14 = 0; + else + st->silk_mode.stereoWidth_Q14 = 16384 - 2048*(opus_int32)(32000-equiv_rate)/(equiv_rate-14000); + } + if( !st->energy_masking && st->channels == 2 ) { + /* Apply stereo width reduction (at low bitrates) */ + if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) { + opus_val16 g1, g2; + g1 = st->hybrid_stereo_width_Q14; + g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14); +#ifdef FIXED_POINT + g1 = g1==16384 ? Q15ONE : SHL16(g1,1); + g2 = g2==16384 ? Q15ONE : SHL16(g2,1); +#else + g1 *= (1.f/16384); + g2 *= (1.f/16384); +#endif + stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap, + frame_size, st->channels, celt_mode->window, st->Fs); + st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14; + } + } + + if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1)) + { + /* For SILK mode, the redundancy is inferred from the length */ + if (st->mode == MODE_HYBRID) + ec_enc_bit_logp(&enc, redundancy, 12); + if (redundancy) + { + int max_redundancy; + ec_enc_bit_logp(&enc, celt_to_silk, 1); + if (st->mode == MODE_HYBRID) + { + /* Reserve the 8 bits needed for the redundancy length, + and at least a few bits for CELT if possible */ + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+8+3+7)>>3); + } + else + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3); + /* Target the same bit-rate for redundancy as for the rest, + up to a max of 257 bytes */ + redundancy_bytes = IMIN(max_redundancy, redundancy_bytes); + redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes)); + if (st->mode == MODE_HYBRID) + ec_enc_uint(&enc, redundancy_bytes-2, 256); + } + } else { + redundancy = 0; + } + + if (!redundancy) + { + st->silk_bw_switch = 0; + redundancy_bytes = 0; + } + if (st->mode != MODE_CELT_ONLY)start_band=17; + + if (st->mode == MODE_SILK_ONLY) + { + ret = (ec_tell(&enc)+7)>>3; + ec_enc_done(&enc); + nb_compr_bytes = ret; + } else { + nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; + ec_enc_shrink(&enc, nb_compr_bytes); + } + +#ifndef DISABLE_FLOAT_API + if (redundancy || st->mode != MODE_SILK_ONLY) + celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info)); +#endif + if (st->mode == MODE_HYBRID) { + SILKInfo info; + info.signalType = st->silk_mode.signalType; + info.offset = st->silk_mode.offset; + celt_encoder_ctl(celt_enc, CELT_SET_SILK_INFO(&info)); + } + + /* 5 ms redundant frame for CELT->SILK */ + if (redundancy && celt_to_silk) + { + int err; + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + } + + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band)); + + if (st->mode != MODE_SILK_ONLY) + { + if (st->mode != st->prev_mode && st->prev_mode > 0) + { + unsigned char dummy[2]; + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + + /* Prefilling */ + celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + } + /* If false, we already busted the budget and we'll end up with a "PLC frame" */ + if (ec_tell(&enc) <= 8*nb_compr_bytes) + { + /* Set the bitrate again if it was overridden in the redundancy code above*/ + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr)); + ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); + if (ret < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + /* Put CELT->SILK redundancy data in the right place. */ + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + { + OPUS_MOVE(data+ret, data+nb_compr_bytes, redundancy_bytes); + nb_compr_bytes = nb_compr_bytes+redundancy_bytes; + } + } + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + int err; + unsigned char dummy[2]; + int N2, N4; + N2 = st->Fs/200; + N4 = st->Fs/400; + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + + if (st->mode == MODE_HYBRID) + { + /* Shrink packet to what the encoder actually used. */ + nb_compr_bytes = ret; + ec_enc_shrink(&enc, nb_compr_bytes); + } + /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */ + celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL); + + err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + } + + + + /* Signalling the mode in the first byte */ + data--; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + + st->rangeFinal = enc.rng ^ redundant_rng; + + if (to_celt) + st->prev_mode = MODE_CELT_ONLY; + else + st->prev_mode = st->mode; + st->prev_channels = st->stream_channels; + st->prev_framesize = frame_size; + + st->first = 0; + + /* DTX decision */ +#ifndef DISABLE_FLOAT_API + if (st->use_dtx && (analysis_info.valid || is_silence)) + { + if (decide_dtx_mode(analysis_info.activity_probability, &st->nb_no_activity_frames, + st->peak_signal_energy, pcm, frame_size, st->channels, is_silence, st->arch)) + { + st->rangeFinal = 0; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + } else { + st->nb_no_activity_frames = 0; + } +#endif + + /* In the unlikely case that the SILK encoder busted its target, tell + the decoder to call the PLC */ + if (ec_tell(&enc) > (max_data_bytes-1)*8) + { + if (max_data_bytes < 2) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + data[1] = 0; + ret = 1; + st->rangeFinal = 0; + } else if (st->mode==MODE_SILK_ONLY&&!redundancy) + { + /*When in LPC only mode it's perfectly + reasonable to strip off trailing zero bytes as + the required range decoder behavior is to + fill these in. This can't be done when the MDCT + modes are used because the decoder needs to know + the actual length for allocation purposes.*/ + while(ret>2&&data[ret]==0)ret--; + } + /* Count ToC and redundancy */ + ret += 1+redundancy_bytes; + if (!st->use_vbr) + { + if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + ret = max_data_bytes; + } + RESTORE_STACK; + return ret; +} + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + int frame_size; + VARDECL(opus_int16, in); + ALLOC_STACK; + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(in, frame_size*st->channels, opus_int16); + + for (i=0;ichannels;i++) + in[i] = FLOAT2INT16(pcm[i]); + ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); + RESTORE_STACK; + return ret; +} +#endif + +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 out_data_bytes) +{ + int frame_size; + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); +} + +#else +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + int frame_size; + VARDECL(float, in); + ALLOC_STACK; + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(in, frame_size*st->channels, float); + + for (i=0;ichannels;i++) + in[i] = (1.0f/32768)*pcm[i]; + ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); + RESTORE_STACK; + return ret; +} +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 out_data_bytes) +{ + int frame_size; + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); +} +#endif + + +int opus_encoder_ctl(OpusEncoder *st, int request, ...) +{ + int ret; + CELTEncoder *celt_enc; + va_list ap; + + ret = OPUS_OK; + va_start(ap, request); + + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + switch (request) + { + case OPUS_SET_APPLICATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO + && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + || (!st->first && st->application != value)) + { + ret = OPUS_BAD_ARG; + break; + } + st->application = value; +#ifndef DISABLE_FLOAT_API + st->analysis.application = value; +#endif + } + break; + case OPUS_GET_APPLICATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->application; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX) + { + if (value <= 0) + goto bad_arg; + else if (value <= 500) + value = 500; + else if (value > (opus_int32)300000*st->channels) + value = (opus_int32)300000*st->channels; + } + st->user_bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276); + } + break; + case OPUS_SET_FORCE_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if((value<1 || value>st->channels) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->force_channels = value; + } + break; + case OPUS_GET_FORCE_CHANNELS_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->force_channels; + } + break; + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) + { + goto bad_arg; + } + st->max_bandwidth = value; + if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->max_bandwidth; + } + break; + case OPUS_SET_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->user_bandwidth = value; + if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->bandwidth; + } + break; + case OPUS_SET_DTX_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->use_dtx = value; + } + break; + case OPUS_GET_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->use_dtx; + } + break; + case OPUS_SET_COMPLEXITY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>10) + { + goto bad_arg; + } + st->silk_mode.complexity = value; + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value)); + } + break; + case OPUS_GET_COMPLEXITY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.complexity; + } + break; + case OPUS_SET_INBAND_FEC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->silk_mode.useInBandFEC = value; + } + break; + case OPUS_GET_INBAND_FEC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.useInBandFEC; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < 0 || value > 100) + { + goto bad_arg; + } + st->silk_mode.packetLossPercentage = value; + celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value)); + } + break; + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.packetLossPercentage; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->use_vbr = value; + st->silk_mode.useCBR = 1-value; + } + break; + case OPUS_GET_VBR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->use_vbr; + } + break; + case OPUS_SET_VOICE_RATIO_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-1 || value>100) + { + goto bad_arg; + } + st->voice_ratio = value; + } + break; + case OPUS_GET_VOICE_RATIO_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->voice_ratio; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->vbr_constraint = value; + } + break; + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->vbr_constraint; + } + break; + case OPUS_SET_SIGNAL_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC) + { + goto bad_arg; + } + st->signal_type = value; + } + break; + case OPUS_GET_SIGNAL_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->signal_type; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs/400; + if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + *value += st->delay_compensation; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + if (!value) + { + goto bad_arg; + } + *value = st->rangeFinal; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + { + goto bad_arg; + } + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->lsb_depth; + } + break; + case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_FRAMESIZE_ARG && value != OPUS_FRAMESIZE_2_5_MS && + value != OPUS_FRAMESIZE_5_MS && value != OPUS_FRAMESIZE_10_MS && + value != OPUS_FRAMESIZE_20_MS && value != OPUS_FRAMESIZE_40_MS && + value != OPUS_FRAMESIZE_60_MS && value != OPUS_FRAMESIZE_80_MS && + value != OPUS_FRAMESIZE_100_MS && value != OPUS_FRAMESIZE_120_MS) + { + goto bad_arg; + } + st->variable_duration = value; + } + break; + case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->variable_duration; + } + break; + case OPUS_SET_PREDICTION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value > 1 || value < 0) + goto bad_arg; + st->silk_mode.reducedDependency = value; + } + break; + case OPUS_GET_PREDICTION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + goto bad_arg; + *value = st->silk_mode.reducedDependency; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + celt_encoder_ctl(celt_enc, OPUS_SET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_RESET_STATE: + { + void *silk_enc; + silk_EncControlStruct dummy; + char *start; + silk_enc = (char*)st+st->silk_enc_offset; +#ifndef DISABLE_FLOAT_API + tonality_analysis_reset(&st->analysis); +#endif + + start = (char*)&st->OPUS_ENCODER_RESET_START; + OPUS_CLEAR(start, sizeof(OpusEncoder) - (start - (char*)st)); + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + silk_InitEncoder( silk_enc, st->arch, &dummy ); + st->stream_channels = st->channels; + st->hybrid_stereo_width_Q14 = 1 << 14; + st->prev_HB_gain = Q15ONE; + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + } + break; + case OPUS_SET_FORCE_MODE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->user_forced_mode = value; + } + break; + case OPUS_SET_LFE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->lfe = value; + ret = celt_encoder_ctl(celt_enc, OPUS_SET_LFE(value)); + } + break; + case OPUS_SET_ENERGY_MASK_REQUEST: + { + opus_val16 *value = va_arg(ap, opus_val16*); + st->energy_masking = value; + ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value)); + } + break; + case OPUS_GET_IN_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->silk_mode.useDTX && (st->prev_mode == MODE_SILK_ONLY || st->prev_mode == MODE_HYBRID)) { + /* DTX determined by Silk. */ + int n; + void *silk_enc = (char*)st+st->silk_enc_offset; + *value = 1; + for (n=0;nsilk_mode.nChannelsInternal;n++) { + *value = *value && ((silk_encoder*)silk_enc)->state_Fxx[n].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX; + } + } +#ifndef DISABLE_FLOAT_API + else if (st->use_dtx) { + /* DTX determined by Opus. */ + *value = st->nb_no_activity_frames >= NB_SPEECH_FRAMES_BEFORE_DTX; + } +#endif + else { + *value = 0; + } + } + break; + + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (!value) + { + goto bad_arg; + } + ret = celt_encoder_ctl(celt_enc, CELT_GET_MODE(value)); + } + break; + default: + /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_encoder_destroy(OpusEncoder *st) +{ + opus_free(st); +} diff --git a/native/codec/libraries/opus/src/opus_multistream.c b/native/codec/libraries/opus/src/opus_multistream.c new file mode 100644 index 0000000..09c3639 --- /dev/null +++ b/native/codec/libraries/opus/src/opus_multistream.c @@ -0,0 +1,92 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" + + +int validate_layout(const ChannelLayout *layout) +{ + int i, max_channel; + + max_channel = layout->nb_streams+layout->nb_coupled_streams; + if (max_channel>255) + return 0; + for (i=0;inb_channels;i++) + { + if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255) + return 0; + } + return 1; +} + + +int get_left_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2) + return i; + } + return -1; +} + +int get_right_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2+1) + return i; + } + return -1; +} + +int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id+layout->nb_coupled_streams) + return i; + } + return -1; +} + diff --git a/native/codec/libraries/opus/src/opus_multistream_decoder.c b/native/codec/libraries/opus/src/opus_multistream_decoder.c new file mode 100644 index 0000000..0018517 --- /dev/null +++ b/native/codec/libraries/opus/src/opus_multistream_decoder.c @@ -0,0 +1,549 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" + +/* DECODER */ + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +static void validate_ms_decoder(OpusMSDecoder *st) +{ + validate_layout(&st->layout); +} +#define VALIDATE_MS_DECODER(st) validate_ms_decoder(st) +#else +#define VALIDATE_MS_DECODER(st) +#endif + + +opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) +{ + int coupled_size; + int mono_size; + + if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + return align(sizeof(OpusMSDecoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + return OPUS_BAD_ARG; + + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); + if(ret!=OPUS_OK)return ret; + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + return OPUS_OK; +} + + +OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) +{ + int ret; + OpusMSDecoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static int opus_multistream_packet_validate(const unsigned char *data, + opus_int32 len, int nb_streams, opus_int32 Fs) +{ + int s; + int count; + unsigned char toc; + opus_int16 size[48]; + int samples=0; + opus_int32 packet_offset; + + for (s=0;slayout.nb_streams-1) + { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + if (!do_plc) + { + int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs); + if (ret < 0) + { + RESTORE_STACK; + return ret; + } else if (ret > frame_size) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + } + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + opus_int32 packet_offset; + int ret; + + dec = (OpusDecoder*)ptr; + ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); + + if (!do_plc && len<=0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + packet_offset = 0; + ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); + data += packet_offset; + len -= packet_offset; + if (ret <= 0) + { + RESTORE_STACK; + return ret; + } + frame_size = ret; + if (s < st->layout.nb_coupled_streams) + { + int chan, prev; + prev = -1; + /* Copy "left" audio to the channel(s) where it belongs */ + while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 2, frame_size, user_data); + prev = chan; + } + prev = -1; + /* Copy "right" audio to the channel(s) where it belongs */ + while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf+1, 2, frame_size, user_data); + prev = chan; + } + } else { + int chan, prev; + prev = -1; + /* Copy audio to the channel(s) where it belongs */ + while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 1, frame_size, user_data); + prev = chan; + } + } + } + /* Handle muted channels */ + for (c=0;clayout.nb_channels;c++) + { + if (st->layout.mapping[c] == 255) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, c, + NULL, 0, frame_size, user_data); + } + } + RESTORE_STACK; + return frame_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +) +{ + float *float_dst; + opus_int32 i; + (void)user_data; + float_dst = (float*)dst; + if (src != NULL) + { + for (i=0;ilayout.nb_streams;s++) + { + OpusDecoder *dec; + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_RESET_STATE: + { + int s; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusDecoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + goto bad_arg; + value = va_arg(ap, OpusDecoder**); + if (!value) + { + goto bad_arg; + } + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusDecoder*)ptr; + } + break; + case OPUS_SET_GAIN_REQUEST: + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + return ret; +bad_arg: + return OPUS_BAD_ARG; +} + +int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) +{ + int ret; + va_list ap; + va_start(ap, request); + ret = opus_multistream_decoder_ctl_va_list(st, request, ap); + va_end(ap); + return ret; +} + +void opus_multistream_decoder_destroy(OpusMSDecoder *st) +{ + opus_free(st); +} diff --git a/native/codec/libraries/opus/src/opus_multistream_encoder.c b/native/codec/libraries/opus/src/opus_multistream_encoder.c new file mode 100644 index 0000000..93204a1 --- /dev/null +++ b/native/codec/libraries/opus/src/opus_multistream_encoder.c @@ -0,0 +1,1328 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" +#include "mathops.h" +#include "mdct.h" +#include "modes.h" +#include "bands.h" +#include "quant_bands.h" +#include "pitch.h" + +typedef struct { + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[8]; +} VorbisLayout; + +/* Index is nb_channel-1*/ +static const VorbisLayout vorbis_mappings[8] = { + {1, 0, {0}}, /* 1: mono */ + {1, 1, {0, 1}}, /* 2: stereo */ + {2, 1, {0, 2, 1}}, /* 3: 1-d surround */ + {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */ + {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */ + {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */ + {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */ + {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */ +}; + +static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st) +{ + int s; + char *ptr; + int coupled_size, mono_size; + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + /* void* cast avoids clang -Wcast-align warning */ + return (opus_val32*)(void*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32)); +} + +static opus_val32 *ms_get_window_mem(OpusMSEncoder *st) +{ + int s; + char *ptr; + int coupled_size, mono_size; + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + /* void* cast avoids clang -Wcast-align warning */ + return (opus_val32*)(void*)ptr; +} + +static int validate_ambisonics(int nb_channels, int *nb_streams, int *nb_coupled_streams) +{ + int order_plus_one; + int acn_channels; + int nondiegetic_channels; + + if (nb_channels < 1 || nb_channels > 227) + return 0; + + order_plus_one = isqrt32(nb_channels); + acn_channels = order_plus_one * order_plus_one; + nondiegetic_channels = nb_channels - acn_channels; + + if (nondiegetic_channels != 0 && nondiegetic_channels != 2) + return 0; + + if (nb_streams) + *nb_streams = acn_channels + (nondiegetic_channels != 0); + if (nb_coupled_streams) + *nb_coupled_streams = nondiegetic_channels != 0; + return 1; +} + +static int validate_encoder_layout(const ChannelLayout *layout) +{ + int s; + for (s=0;snb_streams;s++) + { + if (s < layout->nb_coupled_streams) + { + if (get_left_channel(layout, s, -1)==-1) + return 0; + if (get_right_channel(layout, s, -1)==-1) + return 0; + } else { + if (get_mono_channel(layout, s, -1)==-1) + return 0; + } + } + return 1; +} + +static void channel_pos(int channels, int pos[8]) +{ + /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */ + if (channels==4) + { + pos[0]=1; + pos[1]=3; + pos[2]=1; + pos[3]=3; + } else if (channels==3||channels==5||channels==6) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=0; + } else if (channels==7) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=2; + pos[6]=0; + } else if (channels==8) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=1; + pos[6]=3; + pos[7]=0; + } +} + +#if 1 +/* Computes a rough approximation of log2(2^a + 2^b) */ +static opus_val16 logSum(opus_val16 a, opus_val16 b) +{ + opus_val16 max; + opus_val32 diff; + opus_val16 frac; + static const opus_val16 diff_table[17] = { + QCONST16(0.5000000f, DB_SHIFT), QCONST16(0.2924813f, DB_SHIFT), QCONST16(0.1609640f, DB_SHIFT), QCONST16(0.0849625f, DB_SHIFT), + QCONST16(0.0437314f, DB_SHIFT), QCONST16(0.0221971f, DB_SHIFT), QCONST16(0.0111839f, DB_SHIFT), QCONST16(0.0056136f, DB_SHIFT), + QCONST16(0.0028123f, DB_SHIFT) + }; + int low; + if (a>b) + { + max = a; + diff = SUB32(EXTEND32(a),EXTEND32(b)); + } else { + max = b; + diff = SUB32(EXTEND32(b),EXTEND32(a)); + } + if (!(diff < QCONST16(8.f, DB_SHIFT))) /* inverted to catch NaNs */ + return max; +#ifdef FIXED_POINT + low = SHR32(diff, DB_SHIFT-1); + frac = SHL16(diff - SHL16(low, DB_SHIFT-1), 16-DB_SHIFT); +#else + low = (int)floor(2*diff); + frac = 2*diff - low; +#endif + return max + diff_table[low] + MULT16_16_Q15(frac, SUB16(diff_table[low+1], diff_table[low])); +} +#else +opus_val16 logSum(opus_val16 a, opus_val16 b) +{ + return log2(pow(4, a)+ pow(4, b))/2; +} +#endif + +void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem, + int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in, int arch +) +{ + int c; + int i; + int LM; + int pos[8] = {0}; + int upsample; + int frame_size; + int freq_size; + opus_val16 channel_offset; + opus_val32 bandE[21]; + opus_val16 maskLogE[3][21]; + VARDECL(opus_val32, in); + VARDECL(opus_val16, x); + VARDECL(opus_val32, freq); + SAVE_STACK; + + upsample = resampling_factor(rate); + frame_size = len*upsample; + freq_size = IMIN(960, frame_size); + + /* LM = log2(frame_size / 120) */ + for (LM=0;LMmaxLM;LM++) + if (celt_mode->shortMdctSize<preemph, preemph_mem+c, 0); +#ifndef FIXED_POINT + { + opus_val32 sum; + sum = celt_inner_prod(in, in, frame_size+overlap, 0); + /* This should filter out both NaNs and ridiculous signals that could + cause NaNs further down. */ + if (!(sum < 1e18f) || celt_isnan(sum)) + { + OPUS_CLEAR(in, frame_size+overlap); + preemph_mem[c] = 0; + } + } +#endif + OPUS_CLEAR(bandE, 21); + for (frame=0;framemdct, in+960*frame, freq, celt_mode->window, + overlap, celt_mode->maxLM-LM, 1, arch); + if (upsample != 1) + { + int bound = freq_size/upsample; + for (i=0;i=0;i--) + bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i+1]-QCONST16(2.f, DB_SHIFT)); + if (pos[c]==1) + { + for (i=0;i<21;i++) + maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]); + } else if (pos[c]==3) + { + for (i=0;i<21;i++) + maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]); + } else if (pos[c]==2) + { + for (i=0;i<21;i++) + { + maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT)); + maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT)); + } + } +#if 0 + for (i=0;i<21;i++) + printf("%f ", bandLogE[21*c+i]); + float sum=0; + for (i=0;i<21;i++) + sum += bandLogE[21*c+i]; + printf("%f ", sum/21); +#endif + OPUS_COPY(mem+c*overlap, in+frame_size, overlap); + } + for (i=0;i<21;i++) + maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]); + channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1))); + for (c=0;c<3;c++) + for (i=0;i<21;i++) + maskLogE[c][i] += channel_offset; +#if 0 + for (c=0;c<3;c++) + { + for (i=0;i<21;i++) + printf("%f ", maskLogE[c][i]); + } +#endif + for (c=0;cnb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + return align(sizeof(OpusMSEncoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family) +{ + int nb_streams; + int nb_coupled_streams; + opus_int32 size; + + if (mapping_family==0) + { + if (channels==1) + { + nb_streams=1; + nb_coupled_streams=0; + } else if (channels==2) + { + nb_streams=1; + nb_coupled_streams=1; + } else + return 0; + } else if (mapping_family==1 && channels<=8 && channels>=1) + { + nb_streams=vorbis_mappings[channels-1].nb_streams; + nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; + } else if (mapping_family==255) + { + nb_streams=channels; + nb_coupled_streams=0; + } else if (mapping_family==2) + { + if (!validate_ambisonics(channels, &nb_streams, &nb_coupled_streams)) + return 0; + } else + return 0; + size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); + if (channels>2) + { + size += channels*(120*sizeof(opus_val32) + sizeof(opus_val32)); + } + return size; +} + +static int opus_multistream_encoder_init_impl( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + MappingType mapping_type +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + return OPUS_BAD_ARG; + + st->arch = opus_select_arch(); + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + if (mapping_type != MAPPING_TYPE_SURROUND) + st->lfe_stream = -1; + st->bitrate_bps = OPUS_AUTO; + st->application = application; + st->variable_duration = OPUS_FRAMESIZE_ARG; + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + if (mapping_type == MAPPING_TYPE_SURROUND && + !validate_encoder_layout(&st->layout)) + return OPUS_BAD_ARG; + if (mapping_type == MAPPING_TYPE_AMBISONICS && + !validate_ambisonics(st->layout.nb_channels, NULL, NULL)) + return OPUS_BAD_ARG; + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); + if(ret!=OPUS_OK)return ret; + if (i==st->lfe_stream) + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); + if (i==st->lfe_stream) + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + if (mapping_type == MAPPING_TYPE_SURROUND) + { + OPUS_CLEAR(ms_get_preemph_mem(st), channels); + OPUS_CLEAR(ms_get_window_mem(st), channels*120); + } + st->mapping_type = mapping_type; + return OPUS_OK; +} + +int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) +{ + return opus_multistream_encoder_init_impl(st, Fs, channels, streams, + coupled_streams, mapping, + application, MAPPING_TYPE_NONE); +} + +int opus_multistream_surround_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application +) +{ + MappingType mapping_type; + + if ((channels>255) || (channels<1)) + return OPUS_BAD_ARG; + st->lfe_stream = -1; + if (mapping_family==0) + { + if (channels==1) + { + *streams=1; + *coupled_streams=0; + mapping[0]=0; + } else if (channels==2) + { + *streams=1; + *coupled_streams=1; + mapping[0]=0; + mapping[1]=1; + } else + return OPUS_UNIMPLEMENTED; + } else if (mapping_family==1 && channels<=8 && channels>=1) + { + int i; + *streams=vorbis_mappings[channels-1].nb_streams; + *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; + for (i=0;i=6) + st->lfe_stream = *streams-1; + } else if (mapping_family==255) + { + int i; + *streams=channels; + *coupled_streams=0; + for(i=0;i2 && mapping_family==1) { + mapping_type = MAPPING_TYPE_SURROUND; + } else if (mapping_family==2) + { + mapping_type = MAPPING_TYPE_AMBISONICS; + } else + { + mapping_type = MAPPING_TYPE_NONE; + } + return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, + *coupled_streams, mapping, + application, mapping_type); +} + +OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) +{ + int ret; + OpusMSEncoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +OpusMSEncoder *opus_multistream_surround_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application, + int *error +) +{ + int ret; + opus_int32 size; + OpusMSEncoder *st; + if ((channels>255) || (channels<1)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + size = opus_multistream_surround_encoder_get_size(channels, mapping_family); + if (!size) + { + if (error) + *error = OPUS_UNIMPLEMENTED; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(size); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +static void surround_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + opus_int32 channel_rate; + int stream_offset; + int lfe_offset; + int coupled_ratio; /* Q8 */ + int lfe_ratio; /* Q8 */ + int nb_lfe; + int nb_uncoupled; + int nb_coupled; + int nb_normal; + opus_int32 channel_offset; + opus_int32 bitrate; + int total; + + nb_lfe = (st->lfe_stream!=-1); + nb_coupled = st->layout.nb_coupled_streams; + nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe; + nb_normal = 2*nb_coupled + nb_uncoupled; + + /* Give each non-LFE channel enough bits per channel for coding band energy. */ + channel_offset = 40*IMAX(50, Fs/frame_size); + + if (st->bitrate_bps==OPUS_AUTO) + { + bitrate = nb_normal*(channel_offset + Fs + 10000) + 8000*nb_lfe; + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + bitrate = nb_normal*300000 + nb_lfe*128000; + } else { + bitrate = st->bitrate_bps; + } + + /* Give LFE some basic stream_channel allocation but never exceed 1/20 of the + total rate for the non-energy part to avoid problems at really low rate. */ + lfe_offset = IMIN(bitrate/20, 3000) + 15*IMAX(50, Fs/frame_size); + + /* We give each stream (coupled or uncoupled) a starting bitrate. + This models the main saving of coupled channels over uncoupled. */ + stream_offset = (bitrate - channel_offset*nb_normal - lfe_offset*nb_lfe)/nb_normal/2; + stream_offset = IMAX(0, IMIN(20000, stream_offset)); + + /* Coupled streams get twice the mono rate after the offset is allocated. */ + coupled_ratio = 512; + /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */ + lfe_ratio = 32; + + total = (nb_uncoupled<<8) /* mono */ + + coupled_ratio*nb_coupled /* stereo */ + + nb_lfe*lfe_ratio; + channel_rate = 256*(opus_int64)(bitrate - lfe_offset*nb_lfe - stream_offset*(nb_coupled+nb_uncoupled) - channel_offset*nb_normal)/total; + + for (i=0;ilayout.nb_streams;i++) + { + if (ilayout.nb_coupled_streams) + rate[i] = 2*channel_offset + IMAX(0, stream_offset+(channel_rate*coupled_ratio>>8)); + else if (i!=st->lfe_stream) + rate[i] = channel_offset + IMAX(0, stream_offset + channel_rate); + else + rate[i] = IMAX(0, lfe_offset+(channel_rate*lfe_ratio>>8)); + } +} + +static void ambisonics_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + opus_int32 total_rate; + opus_int32 per_stream_rate; + + const int nb_channels = st->layout.nb_streams + st->layout.nb_coupled_streams; + + if (st->bitrate_bps==OPUS_AUTO) + { + total_rate = (st->layout.nb_coupled_streams + st->layout.nb_streams) * + (Fs+60*Fs/frame_size) + st->layout.nb_streams * (opus_int32)15000; + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + total_rate = nb_channels * 320000; + } else + { + total_rate = st->bitrate_bps; + } + + /* Allocate equal number of bits to Ambisonic (uncoupled) and non-diegetic + * (coupled) streams */ + per_stream_rate = total_rate / st->layout.nb_streams; + for (i = 0; i < st->layout.nb_streams; i++) + { + rate[i] = per_stream_rate; + } +} + +static opus_int32 rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size + ) +{ + int i; + opus_int32 rate_sum=0; + opus_int32 Fs; + char *ptr; + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + + if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + ambisonics_rate_allocation(st, rate, frame_size, Fs); + } else + { + surround_rate_allocation(st, rate, frame_size, Fs); + } + + for (i=0;ilayout.nb_streams;i++) + { + rate[i] = IMAX(rate[i], 500); + rate_sum += rate[i]; + } + return rate_sum; +} + +/* Max size in case the encoder decides to return six frames (6 x 20 ms = 120 ms) */ +#define MS_FRAME_TMP (6*1275+12) +int opus_multistream_encode_native +( + OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +) +{ + opus_int32 Fs; + int coupled_size; + int mono_size; + int s; + char *ptr; + int tot_size; + VARDECL(opus_val16, buf); + VARDECL(opus_val16, bandSMR); + unsigned char tmp_data[MS_FRAME_TMP]; + OpusRepacketizer rp; + opus_int32 vbr; + const CELTMode *celt_mode; + opus_int32 bitrates[256]; + opus_val16 bandLogE[42]; + opus_val32 *mem = NULL; + opus_val32 *preemph_mem=NULL; + int frame_size; + opus_int32 rate_sum; + opus_int32 smallest_packet; + ALLOC_STACK; + + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + preemph_mem = ms_get_preemph_mem(st); + mem = ms_get_window_mem(st); + } + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr)); + opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode)); + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Smallest packet the encoder can produce. */ + smallest_packet = st->layout.nb_streams*2-1; + /* 100 ms needs an extra byte per stream for the ToC. */ + if (Fs/frame_size == 10) + smallest_packet += st->layout.nb_streams; + if (max_data_bytes < smallest_packet) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + ALLOC(buf, 2*frame_size, opus_val16); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in, st->arch); + } + + /* Compute bitrate allocation between streams (this could be a lot better) */ + rate_sum = rate_allocation(st, bitrates, frame_size); + + if (!vbr) + { + if (st->bitrate_bps == OPUS_AUTO) + { + max_data_bytes = IMIN(max_data_bytes, 3*rate_sum/(3*8*Fs/frame_size)); + } else if (st->bitrate_bps != OPUS_BITRATE_MAX) + { + max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet, + 3*st->bitrate_bps/(3*8*Fs/frame_size))); + } + } + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s])); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + opus_int32 equiv_rate; + equiv_rate = st->bitrate_bps; + if (frame_size*50 < Fs) + equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels; + if (equiv_rate > 10000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + else if (equiv_rate > 7000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + else if (equiv_rate > 5000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); + else + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + if (s < st->layout.nb_coupled_streams) + { + /* To preserve the spatial image, force stereo CELT on coupled streams */ + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); + } + } + else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + } + } + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + /* Counting ToC */ + tot_size = 0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + int len; + int curr_max; + int c1, c2; + int ret; + + opus_repacketizer_init(&rp); + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + { + int i; + int left, right; + left = get_left_channel(&st->layout, s, -1); + right = get_right_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 2, + pcm, st->layout.nb_channels, left, frame_size, user_data); + (*copy_channel_in)(buf+1, 2, + pcm, st->layout.nb_channels, right, frame_size, user_data); + ptr += align(coupled_size); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + for (i=0;i<21;i++) + { + bandLogE[i] = bandSMR[21*left+i]; + bandLogE[21+i] = bandSMR[21*right+i]; + } + } + c1 = left; + c2 = right; + } else { + int i; + int chan = get_mono_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 1, + pcm, st->layout.nb_channels, chan, frame_size, user_data); + ptr += align(mono_size); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + for (i=0;i<21;i++) + bandLogE[i] = bandSMR[21*chan+i]; + } + c1 = chan; + c2 = -1; + } + if (st->mapping_type == MAPPING_TYPE_SURROUND) + opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE)); + /* number of bytes left (+Toc) */ + curr_max = max_data_bytes - tot_size; + /* Reserve one byte for the last stream and two for the others */ + curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1); + /* For 100 ms, reserve an extra byte per stream for the ToC */ + if (Fs/frame_size == 10) + curr_max -= st->layout.nb_streams-s-1; + curr_max = IMIN(curr_max,MS_FRAME_TMP); + /* Repacketizer will add one or two bytes for self-delimited frames */ + if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1; + if (!vbr && s == st->layout.nb_streams-1) + opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size))); + len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth, + pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix, float_api); + if (len<0) + { + RESTORE_STACK; + return len; + } + /* We need to use the repacketizer to add the self-delimiting lengths + while taking into account the fact that the encoder can now return + more than one frame at a time (e.g. 60 ms CELT-only) */ + ret = opus_repacketizer_cat(&rp, tmp_data, len); + /* If the opus_repacketizer_cat() fails, then something's seriously wrong + with the encoder. */ + if (ret != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), + data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1); + data += len; + tot_size += len; + } + /*printf("\n");*/ + RESTORE_STACK; + return tot_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + const float *float_src; + opus_int32 i; + (void)user_data; + float_src = (const float *)src; + for (i=0;ilayout.nb_channels, IMAX(500*st->layout.nb_channels, value)); + } + st->bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + int s; + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = 0; + for (s=0;slayout.nb_streams;s++) + { + opus_int32 rate; + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, request, &rate); + *value += rate; + } + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + case OPUS_GET_VBR_REQUEST: + case OPUS_GET_APPLICATION_REQUEST: + case OPUS_GET_BANDWIDTH_REQUEST: + case OPUS_GET_COMPLEXITY_REQUEST: + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + case OPUS_GET_DTX_REQUEST: + case OPUS_GET_VOICE_RATIO_REQUEST: + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + case OPUS_GET_SIGNAL_REQUEST: + case OPUS_GET_LOOKAHEAD_REQUEST: + case OPUS_GET_SAMPLE_RATE_REQUEST: + case OPUS_GET_INBAND_FEC_REQUEST: + case OPUS_GET_FORCE_CHANNELS_REQUEST: + case OPUS_GET_PREDICTION_DISABLED_REQUEST: + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + OpusEncoder *enc; + /* For int32* GET params, just query the first stream */ + opus_int32 *value = va_arg(ap, opus_int32*); + enc = (OpusEncoder*)ptr; + ret = opus_encoder_ctl(enc, request, value); + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + int s; + opus_uint32 *value = va_arg(ap, opus_uint32*); + opus_uint32 tmp; + if (!value) + { + goto bad_arg; + } + *value=0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + case OPUS_SET_COMPLEXITY_REQUEST: + case OPUS_SET_VBR_REQUEST: + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + case OPUS_SET_BANDWIDTH_REQUEST: + case OPUS_SET_SIGNAL_REQUEST: + case OPUS_SET_APPLICATION_REQUEST: + case OPUS_SET_INBAND_FEC_REQUEST: + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + case OPUS_SET_DTX_REQUEST: + case OPUS_SET_FORCE_MODE_REQUEST: + case OPUS_SET_FORCE_CHANNELS_REQUEST: + case OPUS_SET_PREDICTION_DISABLED_REQUEST: + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusEncoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + goto bad_arg; + value = va_arg(ap, OpusEncoder**); + if (!value) + { + goto bad_arg; + } + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusEncoder*)ptr; + } + break; + case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->variable_duration = value; + } + break; + case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->variable_duration; + } + break; + case OPUS_RESET_STATE: + { + int s; + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels); + OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120); + } + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + return ret; +bad_arg: + return OPUS_BAD_ARG; +} + +int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) +{ + int ret; + va_list ap; + va_start(ap, request); + ret = opus_multistream_encoder_ctl_va_list(st, request, ap); + va_end(ap); + return ret; +} + +void opus_multistream_encoder_destroy(OpusMSEncoder *st) +{ + opus_free(st); +} diff --git a/native/codec/libraries/opus/src/opus_private.h b/native/codec/libraries/opus/src/opus_private.h new file mode 100644 index 0000000..5e2463f --- /dev/null +++ b/native/codec/libraries/opus/src/opus_private.h @@ -0,0 +1,201 @@ +/* Copyright (c) 2012 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef OPUS_PRIVATE_H +#define OPUS_PRIVATE_H + +#include "arch.h" +#include "opus.h" +#include "celt.h" + +#include /* va_list */ +#include /* offsetof */ + +struct OpusRepacketizer { + unsigned char toc; + int nb_frames; + const unsigned char *frames[48]; + opus_int16 len[48]; + int framesize; +}; + +typedef struct ChannelLayout { + int nb_channels; + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[256]; +} ChannelLayout; + +typedef enum { + MAPPING_TYPE_NONE, + MAPPING_TYPE_SURROUND, + MAPPING_TYPE_AMBISONICS +} MappingType; + +struct OpusMSEncoder { + ChannelLayout layout; + int arch; + int lfe_stream; + int application; + int variable_duration; + MappingType mapping_type; + opus_int32 bitrate_bps; + /* Encoder states go here */ + /* then opus_val32 window_mem[channels*120]; */ + /* then opus_val32 preemph_mem[channels]; */ +}; + +struct OpusMSDecoder { + ChannelLayout layout; + /* Decoder states go here */ +}; + +int opus_multistream_encoder_ctl_va_list(struct OpusMSEncoder *st, int request, + va_list ap); +int opus_multistream_decoder_ctl_va_list(struct OpusMSDecoder *st, int request, + va_list ap); + +int validate_layout(const ChannelLayout *layout); +int get_left_channel(const ChannelLayout *layout, int stream_id, int prev); +int get_right_channel(const ChannelLayout *layout, int stream_id, int prev); +int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev); + +typedef void (*opus_copy_channel_in_func)( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +); + +typedef void (*opus_copy_channel_out_func)( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +); + +#define MODE_SILK_ONLY 1000 +#define MODE_HYBRID 1001 +#define MODE_CELT_ONLY 1002 + +#define OPUS_SET_VOICE_RATIO_REQUEST 11018 +#define OPUS_GET_VOICE_RATIO_REQUEST 11019 + +/** Configures the encoder's expected percentage of voice + * opposed to music or other signals. + * + * @note This interface is currently more aspiration than actuality. It's + * ultimately expected to bias an automatic signal classifier, but it currently + * just shifts the static bitrate to mode mapping around a little bit. + * + * @param[in] x int: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO + * + * @param[out] x int*: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x) + + +#define OPUS_SET_FORCE_MODE_REQUEST 11002 +#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x) + +typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int); +void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth); + +int encode_size(int size, unsigned char *data); + +opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs); + +opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, + const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, + int analysis_channels, downmix_func downmix, int float_api); + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, + opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, + opus_int32 *packet_offset, int soft_clip); + +/* Make sure everything is properly aligned. */ +static OPUS_INLINE int align(int i) +{ + struct foo {char c; union { void* p; opus_int32 i; opus_val32 v; } u;}; + + unsigned int alignment = offsetof(struct foo, u); + + /* Optimizing compilers should optimize div and multiply into and + for all sensible alignment values. */ + return ((i + alignment - 1) / alignment) * alignment; +} + +int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, + int self_delimited, unsigned char *out_toc, + const unsigned char *frames[48], opus_int16 size[48], + int *payload_offset, opus_int32 *packet_offset); + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad); + +int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len); + +int opus_multistream_encode_native +( + struct OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +); + +int opus_multistream_decode_native( + struct OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + void *pcm, + opus_copy_channel_out_func copy_channel_out, + int frame_size, + int decode_fec, + int soft_clip, + void *user_data +); + +#endif /* OPUS_PRIVATE_H */ diff --git a/native/codec/libraries/opus/src/opus_projection_decoder.c b/native/codec/libraries/opus/src/opus_projection_decoder.c new file mode 100644 index 0000000..c2e07d5 --- /dev/null +++ b/native/codec/libraries/opus/src/opus_projection_decoder.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "os_support.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "opus_projection.h" +#include "opus_multistream.h" +#include "mapping_matrix.h" +#include "stack_alloc.h" + +struct OpusProjectionDecoder +{ + opus_int32 demixing_matrix_size_in_bytes; + /* Encoder states go here */ +}; + +#if !defined(DISABLE_FLOAT_API) +static void opus_projection_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data) +{ + float *float_dst; + const MappingMatrix *matrix; + float_dst = (float *)dst; + matrix = (const MappingMatrix *)user_data; + + if (dst_channel == 0) + OPUS_CLEAR(float_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel, + src_stride, float_dst, dst_stride, frame_size); +} +#endif + +static void opus_projection_copy_channel_out_short( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data) +{ + opus_int16 *short_dst; + const MappingMatrix *matrix; + short_dst = (opus_int16 *)dst; + matrix = (const MappingMatrix *)user_data; + if (dst_channel == 0) + OPUS_CLEAR(short_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel, + src_stride, short_dst, dst_stride, frame_size); +} + +static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix*)(void*)((char*)st + + align(sizeof(OpusProjectionDecoder))); +} + +static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (OpusMSDecoder*)(void*)((char*)st + + align(sizeof(OpusProjectionDecoder) + + st->demixing_matrix_size_in_bytes)); +} + +opus_int32 opus_projection_decoder_get_size(int channels, int streams, + int coupled_streams) +{ + opus_int32 matrix_size; + opus_int32 decoder_size; + + matrix_size = + mapping_matrix_get_size(streams + coupled_streams, channels); + if (!matrix_size) + return 0; + + decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams); + if (!decoder_size) + return 0; + + return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size; +} + +int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs, + int channels, int streams, int coupled_streams, + unsigned char *demixing_matrix, opus_int32 demixing_matrix_size) +{ + int nb_input_streams; + opus_int32 expected_matrix_size; + int i, ret; + unsigned char mapping[255]; + VARDECL(opus_int16, buf); + ALLOC_STACK; + + /* Verify supplied matrix size. */ + nb_input_streams = streams + coupled_streams; + expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16); + if (expected_matrix_size != demixing_matrix_size) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Convert demixing matrix input into internal format. */ + ALLOC(buf, nb_input_streams * channels, opus_int16); + for (i = 0; i < nb_input_streams * channels; i++) + { + int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i]; + s = ((s & 0xFFFF) ^ 0x8000) - 0x8000; + buf[i] = (opus_int16)s; + } + + /* Assign demixing matrix. */ + st->demixing_matrix_size_in_bytes = + mapping_matrix_get_size(channels, nb_input_streams); + if (!st->demixing_matrix_size_in_bytes) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0, + buf, demixing_matrix_size); + + /* Set trivial mapping so each input channel pairs with a matrix column. */ + for (i = 0; i < channels; i++) + mapping[i] = i; + + ret = opus_multistream_decoder_init( + get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping); + RESTORE_STACK; + return ret; +} + +OpusProjectionDecoder *opus_projection_decoder_create( + opus_int32 Fs, int channels, int streams, int coupled_streams, + unsigned char *demixing_matrix, opus_int32 demixing_matrix_size, int *error) +{ + int size; + int ret; + OpusProjectionDecoder *st; + + /* Allocate space for the projection decoder. */ + size = opus_projection_decoder_get_size(channels, streams, coupled_streams); + if (!size) { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + st = (OpusProjectionDecoder *)opus_alloc(size); + if (!st) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + + /* Initialize projection decoder with provided settings. */ + ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams, + demixing_matrix, demixing_matrix_size); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +#ifdef FIXED_POINT +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 0, + get_dec_demixing_matrix(st)); +} +#else +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 1, + get_dec_demixing_matrix(st)); +} +#endif + +#ifndef DISABLE_FLOAT_API +int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0, + get_dec_demixing_matrix(st)); +} +#endif + +int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) +{ + va_list ap; + int ret = OPUS_OK; + + va_start(ap, request); + ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st), + request, ap); + va_end(ap); + return ret; +} + +void opus_projection_decoder_destroy(OpusProjectionDecoder *st) +{ + opus_free(st); +} + diff --git a/native/codec/libraries/opus/src/opus_projection_encoder.c b/native/codec/libraries/opus/src/opus_projection_encoder.c new file mode 100644 index 0000000..06fb2d2 --- /dev/null +++ b/native/codec/libraries/opus/src/opus_projection_encoder.c @@ -0,0 +1,468 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "os_support.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "opus_projection.h" +#include "opus_multistream.h" +#include "stack_alloc.h" +#include "mapping_matrix.h" + +struct OpusProjectionEncoder +{ + opus_int32 mixing_matrix_size_in_bytes; + opus_int32 demixing_matrix_size_in_bytes; + /* Encoder states go here */ +}; + +#if !defined(DISABLE_FLOAT_API) +static void opus_projection_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data, + (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} +#endif + +static void opus_projection_copy_channel_in_short( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data, + (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} + +static int get_order_plus_one_from_channels(int channels, int *order_plus_one) +{ + int order_plus_one_; + int acn_channels; + int nondiegetic_channels; + + /* Allowed numbers of channels: + * (1 + n)^2 + 2j, for n = 0...14 and j = 0 or 1. + */ + if (channels < 1 || channels > 227) + return OPUS_BAD_ARG; + + order_plus_one_ = isqrt32(channels); + acn_channels = order_plus_one_ * order_plus_one_; + nondiegetic_channels = channels - acn_channels; + if (nondiegetic_channels != 0 && nondiegetic_channels != 2) + return OPUS_BAD_ARG; + + if (order_plus_one) + *order_plus_one = order_plus_one_; + return OPUS_OK; +} + +static int get_streams_from_channels(int channels, int mapping_family, + int *streams, int *coupled_streams, + int *order_plus_one) +{ + if (mapping_family == 3) + { + if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK) + return OPUS_BAD_ARG; + if (streams) + *streams = (channels + 1) / 2; + if (coupled_streams) + *coupled_streams = channels / 2; + return OPUS_OK; + } + return OPUS_BAD_ARG; +} + +static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder))); +} + +static MappingMatrix *get_enc_demixing_matrix(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder) + + st->mixing_matrix_size_in_bytes)); +} + +static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (OpusMSEncoder *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder) + + st->mixing_matrix_size_in_bytes + + st->demixing_matrix_size_in_bytes)); +} + +opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, + int mapping_family) +{ + int nb_streams; + int nb_coupled_streams; + int order_plus_one; + int mixing_matrix_rows, mixing_matrix_cols; + int demixing_matrix_rows, demixing_matrix_cols; + opus_int32 mixing_matrix_size, demixing_matrix_size; + opus_int32 encoder_size; + int ret; + + ret = get_streams_from_channels(channels, mapping_family, &nb_streams, + &nb_coupled_streams, &order_plus_one); + if (ret != OPUS_OK) + return 0; + + if (order_plus_one == 2) + { + mixing_matrix_rows = mapping_matrix_foa_mixing.rows; + mixing_matrix_cols = mapping_matrix_foa_mixing.cols; + demixing_matrix_rows = mapping_matrix_foa_demixing.rows; + demixing_matrix_cols = mapping_matrix_foa_demixing.cols; + } + else if (order_plus_one == 3) + { + mixing_matrix_rows = mapping_matrix_soa_mixing.rows; + mixing_matrix_cols = mapping_matrix_soa_mixing.cols; + demixing_matrix_rows = mapping_matrix_soa_demixing.rows; + demixing_matrix_cols = mapping_matrix_soa_demixing.cols; + } + else if (order_plus_one == 4) + { + mixing_matrix_rows = mapping_matrix_toa_mixing.rows; + mixing_matrix_cols = mapping_matrix_toa_mixing.cols; + demixing_matrix_rows = mapping_matrix_toa_demixing.rows; + demixing_matrix_cols = mapping_matrix_toa_demixing.cols; + } + else + return 0; + + mixing_matrix_size = + mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols); + if (!mixing_matrix_size) + return 0; + + demixing_matrix_size = + mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols); + if (!demixing_matrix_size) + return 0; + + encoder_size = + opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); + if (!encoder_size) + return 0; + + return align(sizeof(OpusProjectionEncoder)) + + mixing_matrix_size + demixing_matrix_size + encoder_size; +} + +int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs, + int channels, int mapping_family, + int *streams, int *coupled_streams, + int application) +{ + MappingMatrix *mixing_matrix; + MappingMatrix *demixing_matrix; + OpusMSEncoder *ms_encoder; + int i; + int ret; + int order_plus_one; + unsigned char mapping[255]; + + if (streams == NULL || coupled_streams == NULL) { + return OPUS_BAD_ARG; + } + + if (get_streams_from_channels(channels, mapping_family, streams, + coupled_streams, &order_plus_one) != OPUS_OK) + return OPUS_BAD_ARG; + + if (mapping_family == 3) + { + /* Assign mixing matrix based on available pre-computed matrices. */ + mixing_matrix = get_mixing_matrix(st); + if (order_plus_one == 2) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows, + mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain, + mapping_matrix_foa_mixing_data, + sizeof(mapping_matrix_foa_mixing_data)); + } + else if (order_plus_one == 3) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows, + mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain, + mapping_matrix_soa_mixing_data, + sizeof(mapping_matrix_soa_mixing_data)); + } + else if (order_plus_one == 4) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows, + mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain, + mapping_matrix_toa_mixing_data, + sizeof(mapping_matrix_toa_mixing_data)); + } + else + return OPUS_BAD_ARG; + + st->mixing_matrix_size_in_bytes = mapping_matrix_get_size( + mixing_matrix->rows, mixing_matrix->cols); + if (!st->mixing_matrix_size_in_bytes) + return OPUS_BAD_ARG; + + /* Assign demixing matrix based on available pre-computed matrices. */ + demixing_matrix = get_enc_demixing_matrix(st); + if (order_plus_one == 2) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows, + mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain, + mapping_matrix_foa_demixing_data, + sizeof(mapping_matrix_foa_demixing_data)); + } + else if (order_plus_one == 3) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows, + mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain, + mapping_matrix_soa_demixing_data, + sizeof(mapping_matrix_soa_demixing_data)); + } + else if (order_plus_one == 4) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows, + mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain, + mapping_matrix_toa_demixing_data, + sizeof(mapping_matrix_toa_demixing_data)); + } + else + return OPUS_BAD_ARG; + + st->demixing_matrix_size_in_bytes = mapping_matrix_get_size( + demixing_matrix->rows, demixing_matrix->cols); + if (!st->demixing_matrix_size_in_bytes) + return OPUS_BAD_ARG; + } + else + return OPUS_UNIMPLEMENTED; + + /* Ensure matrices are large enough for desired coding scheme. */ + if (*streams + *coupled_streams > mixing_matrix->rows || + channels > mixing_matrix->cols || + channels > demixing_matrix->rows || + *streams + *coupled_streams > demixing_matrix->cols) + return OPUS_BAD_ARG; + + /* Set trivial mapping so each input channel pairs with a matrix column. */ + for (i = 0; i < channels; i++) + mapping[i] = i; + + /* Initialize multistream encoder with provided settings. */ + ms_encoder = get_multistream_encoder(st); + ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams, + *coupled_streams, mapping, application); + return ret; +} + +OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( + opus_int32 Fs, int channels, int mapping_family, int *streams, + int *coupled_streams, int application, int *error) +{ + int size; + int ret; + OpusProjectionEncoder *st; + + /* Allocate space for the projection encoder. */ + size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family); + if (!size) { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + st = (OpusProjectionEncoder *)opus_alloc(size); + if (!st) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + + /* Initialize projection encoder with provided settings. */ + ret = opus_projection_ambisonics_encoder_init(st, Fs, channels, + mapping_family, streams, coupled_streams, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_short, pcm, frame_size, data, + max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st)); +} + +#ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 16, downmix_float, 1, get_mixing_matrix(st)); +} +#else +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 24, downmix_float, 1, get_mixing_matrix(st)); +} +#endif +#endif + +void opus_projection_encoder_destroy(OpusProjectionEncoder *st) +{ + opus_free(st); +} + +int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) +{ + va_list ap; + MappingMatrix *demixing_matrix; + OpusMSEncoder *ms_encoder; + int ret = OPUS_OK; + + ms_encoder = get_multistream_encoder(st); + demixing_matrix = get_enc_demixing_matrix(st); + + va_start(ap, request); + switch(request) + { + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = + ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams + + ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16); + } + break; + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = demixing_matrix->gain; + } + break; + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST: + { + int i, j, k, l; + int nb_input_streams; + int nb_output_streams; + unsigned char *external_char; + opus_int16 *internal_short; + opus_int32 external_size; + opus_int32 internal_size; + + /* (I/O is in relation to the decoder's perspective). */ + nb_input_streams = ms_encoder->layout.nb_streams + + ms_encoder->layout.nb_coupled_streams; + nb_output_streams = ms_encoder->layout.nb_channels; + + external_char = va_arg(ap, unsigned char *); + external_size = va_arg(ap, opus_int32); + if (!external_char) + { + goto bad_arg; + } + internal_short = mapping_matrix_get_data(demixing_matrix); + internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16); + if (external_size != internal_size) + { + goto bad_arg; + } + + /* Copy demixing matrix subset to output destination. */ + l = 0; + for (i = 0; i < nb_input_streams; i++) { + for (j = 0; j < nb_output_streams; j++) { + k = demixing_matrix->rows * i + j; + external_char[2*l] = (unsigned char)internal_short[k]; + external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8); + l++; + } + } + } + break; + default: + { + ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap); + } + break; + } + va_end(ap); + return ret; + +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + diff --git a/native/codec/libraries/opus/src/repacketizer.c b/native/codec/libraries/opus/src/repacketizer.c new file mode 100644 index 0000000..bda44a1 --- /dev/null +++ b/native/codec/libraries/opus/src/repacketizer.c @@ -0,0 +1,349 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus.h" +#include "opus_private.h" +#include "os_support.h" + + +int opus_repacketizer_get_size(void) +{ + return sizeof(OpusRepacketizer); +} + +OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) +{ + rp->nb_frames = 0; + return rp; +} + +OpusRepacketizer *opus_repacketizer_create(void) +{ + OpusRepacketizer *rp; + rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size()); + if(rp==NULL)return NULL; + return opus_repacketizer_init(rp); +} + +void opus_repacketizer_destroy(OpusRepacketizer *rp) +{ + opus_free(rp); +} + +static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited) +{ + unsigned char tmp_toc; + int curr_nb_frames,ret; + /* Set of check ToC */ + if (len<1) return OPUS_INVALID_PACKET; + if (rp->nb_frames == 0) + { + rp->toc = data[0]; + rp->framesize = opus_packet_get_samples_per_frame(data, 8000); + } else if ((rp->toc&0xFC) != (data[0]&0xFC)) + { + /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/ + return OPUS_INVALID_PACKET; + } + curr_nb_frames = opus_packet_get_nb_frames(data, len); + if(curr_nb_frames<1) return OPUS_INVALID_PACKET; + + /* Check the 120 ms maximum packet size */ + if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960) + { + return OPUS_INVALID_PACKET; + } + + ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL); + if(ret<1)return ret; + + rp->nb_frames += curr_nb_frames; + return OPUS_OK; +} + +int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) +{ + return opus_repacketizer_cat_impl(rp, data, len, 0); +} + +int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) +{ + return rp->nb_frames; +} + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad) +{ + int i, count; + opus_int32 tot_size; + opus_int16 *len; + const unsigned char **frames; + unsigned char * ptr; + + if (begin<0 || begin>=end || end>rp->nb_frames) + { + /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ + return OPUS_BAD_ARG; + } + count = end-begin; + + len = rp->len+begin; + frames = rp->frames+begin; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + + ptr = data; + if (count==1) + { + /* Code 0 */ + tot_size += len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = rp->toc&0xFC; + } else if (count==2) + { + if (len[1] == len[0]) + { + /* Code 1 */ + tot_size += 2*len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x1; + } else { + /* Code 2 */ + tot_size += len[0]+len[1]+2+(len[0]>=252); + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x2; + ptr += encode_size(len[0], ptr); + } + } + if (count > 2 || (pad && tot_size < maxlen)) + { + /* Code 3 */ + int vbr; + int pad_amount=0; + + /* Restart the process for the padding case */ + ptr = data; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + vbr = 0; + for (i=1;i=252) + len[i]; + tot_size += len[count-1]; + + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x3; + *ptr++ = count | 0x80; + } else { + tot_size += count*len[0]+2; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x3; + *ptr++ = count; + } + pad_amount = pad ? (maxlen-tot_size) : 0; + if (pad_amount != 0) + { + int nb_255s; + data[1] |= 0x40; + nb_255s = (pad_amount-1)/255; + for (i=0;inb_frames, data, maxlen, 0, 0); +} + +int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) +{ + OpusRepacketizer rp; + opus_int32 ret; + if (len < 1) + return OPUS_BAD_ARG; + if (len==new_len) + return OPUS_OK; + else if (len > new_len) + return OPUS_BAD_ARG; + opus_repacketizer_init(&rp); + /* Moving payload to the end of the packet so we can do in-place padding */ + OPUS_MOVE(data+new_len-len, data, len); + ret = opus_repacketizer_cat(&rp, data+new_len-len, len); + if (ret != OPUS_OK) + return ret; + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1); + if (ret > 0) + return OPUS_OK; + else + return ret; +} + +opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len) +{ + OpusRepacketizer rp; + opus_int32 ret; + if (len < 1) + return OPUS_BAD_ARG; + opus_repacketizer_init(&rp); + ret = opus_repacketizer_cat(&rp, data, len); + if (ret < 0) + return ret; + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0); + celt_assert(ret > 0 && ret <= len); + return ret; +} + +int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams) +{ + int s; + int count; + unsigned char toc; + opus_int16 size[48]; + opus_int32 packet_offset; + opus_int32 amount; + + if (len < 1) + return OPUS_BAD_ARG; + if (len==new_len) + return OPUS_OK; + else if (len > new_len) + return OPUS_BAD_ARG; + amount = new_len - len; + /* Seek to last stream */ + for (s=0;s +#include +#include + +#define MAX_PACKETOUT 32000 + +void usage(char *argv0) +{ + fprintf(stderr, "usage: %s [options] input_file output_file\n", argv0); +} + +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static opus_uint32 char_to_int(unsigned char ch[4]) +{ + return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16) + | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3]; +} + +int main(int argc, char *argv[]) +{ + int i, eof=0; + FILE *fin, *fout; + unsigned char packets[48][1500]; + int len[48]; + int rng[48]; + OpusRepacketizer *rp; + unsigned char output_packet[MAX_PACKETOUT]; + int merge = 1, split=0; + + if (argc < 3) + { + usage(argv[0]); + return EXIT_FAILURE; + } + for (i=1;i48) + { + fprintf(stderr, "-merge parameter must be less than 48.\n"); + return EXIT_FAILURE; + } + i++; + } else if (strcmp(argv[i], "-split")==0) + split = 1; + else + { + fprintf(stderr, "Unknown option: %s\n", argv[i]); + usage(argv[0]); + return EXIT_FAILURE; + } + } + fin = fopen(argv[argc-2], "r"); + if(fin==NULL) + { + fprintf(stderr, "Error opening input file: %s\n", argv[argc-2]); + return EXIT_FAILURE; + } + fout = fopen(argv[argc-1], "w"); + if(fout==NULL) + { + fprintf(stderr, "Error opening output file: %s\n", argv[argc-1]); + fclose(fin); + return EXIT_FAILURE; + } + + rp = opus_repacketizer_create(); + while (!eof) + { + int err; + int nb_packets=merge; + opus_repacketizer_init(rp); + for (i=0;i1500 || len[i]<0) + { + if (feof(fin)) + { + eof = 1; + } else { + fprintf(stderr, "Invalid payload length\n"); + fclose(fin); + fclose(fout); + return EXIT_FAILURE; + } + break; + } + err = fread(ch, 1, 4, fin); + rng[i] = char_to_int(ch); + err = fread(packets[i], 1, len[i], fin); + if (feof(fin)) + { + eof = 1; + break; + } + err = opus_repacketizer_cat(rp, packets[i], len[i]); + if (err!=OPUS_OK) + { + fprintf(stderr, "opus_repacketizer_cat() failed: %s\n", opus_strerror(err)); + break; + } + } + nb_packets = i; + + if (eof) + break; + + if (!split) + { + err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT); + if (err>0) { + unsigned char int_field[4]; + int_to_char(err, int_field); + if(fwrite(int_field, 1, 4, fout)!=4){ + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + int_to_char(rng[nb_packets-1], int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + /*fprintf(stderr, "out len = %d\n", err);*/ + } else { + fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err)); + } + } else { + int nb_frames = opus_repacketizer_get_nb_frames(rp); + for (i=0;i0) { + unsigned char int_field[4]; + int_to_char(err, int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (i==nb_frames-1) + int_to_char(rng[nb_packets-1], int_field); + else + int_to_char(0, int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + /*fprintf(stderr, "out len = %d\n", err);*/ + } else { + fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err)); + } + + } + } + } + + fclose(fin); + fclose(fout); + return EXIT_SUCCESS; +} diff --git a/native/codec/libraries/opus/src/tansig_table.h b/native/codec/libraries/opus/src/tansig_table.h new file mode 100644 index 0000000..c76f844 --- /dev/null +++ b/native/codec/libraries/opus/src/tansig_table.h @@ -0,0 +1,45 @@ +/* This file is auto-generated by gen_tables */ + +static const float tansig_table[201] = { +0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, +0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, +0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f, +0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f, +0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, +0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f, +0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, +0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f, +0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, +0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f, +0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f, +0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, +0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, +0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f, +0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, +0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f, +0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f, +0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, +0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, +0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, +0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, +0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f, +0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, +0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f, +0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, +0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f, +0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, +0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f, +0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f, +0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, +0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f, +0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f, +0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, +0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, +0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, +0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, +0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, +0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, +1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, +1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, +1.000000f, +}; diff --git a/native/codec/libraries/opus/tests/opus_decode_fuzzer.c b/native/codec/libraries/opus/tests/opus_decode_fuzzer.c new file mode 100644 index 0000000..9002622 --- /dev/null +++ b/native/codec/libraries/opus/tests/opus_decode_fuzzer.c @@ -0,0 +1,126 @@ +/* Copyright (c) 2017 Google Inc. */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "opus.h" +#include "opus_types.h" + +#define MAX_FRAME_SAMP 5760 +#define MAX_PACKET 1500 + +/* 4 bytes: packet length, 4 bytes: encoder final range */ +#define SETUP_BYTE_COUNT 8 + +typedef struct { + int fs; + int channels; +} TocInfo; + +static void ParseToc(const uint8_t *toc, TocInfo *const info) { + const int samp_freqs[5] = {8000, 12000, 16000, 24000, 48000}; + const int bandwidth = opus_packet_get_bandwidth(toc); + + info->fs = samp_freqs[bandwidth - OPUS_BANDWIDTH_NARROWBAND]; + info->channels = opus_packet_get_nb_channels(toc); +} + +/* Treats the input data as concatenated packets encoded by opus_demo, + * structured as + * bytes 0..3: packet length + * bytes 4..7: encoder final range + * bytes 8+ : Opus packet, including ToC + */ +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + OpusDecoder *dec; + opus_int16 *pcm; + uint8_t *packet; + TocInfo toc; + int i, err; + + /* Not enough data to setup the decoder (+1 for the ToC) */ + if (size < SETUP_BYTE_COUNT + 1) { + return 0; + } + + /* Create decoder based on info from the first ToC available */ + ParseToc(&data[SETUP_BYTE_COUNT], &toc); + + dec = opus_decoder_create(toc.fs, toc.channels, &err); + if (err != OPUS_OK | dec == NULL) { + return 0; + } + + pcm = (opus_int16*) malloc(sizeof(*pcm) * MAX_FRAME_SAMP * toc.channels); + packet = (uint8_t*) calloc(MAX_PACKET, sizeof(*packet)); + + i = 0; + while (1) { + int len, fec; + + if (i + SETUP_BYTE_COUNT >= size) { + break; + } + + len = (opus_uint32) data[i ] << 24 | + (opus_uint32) data[i + 1] << 16 | + (opus_uint32) data[i + 2] << 8 | + (opus_uint32) data[i + 3]; + if (len > MAX_PACKET || len < 0) { + break; + } + + /* Bytes 4..7 represent encoder final range, but are unused here. + * Instead, byte 4 is repurposed to determine if FEC is used. */ + fec = data[i + 4] & 1; + + /* Lost packet */ + if (len == 0) { + int frame_size; + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&frame_size)); + (void) opus_decode(dec, NULL, size, pcm, frame_size, fec); + } else { + if (i + SETUP_BYTE_COUNT + len > size) { + break; + } + memcpy(pcm, &data[i + SETUP_BYTE_COUNT], len); + (void) opus_decode(dec, data, size, pcm, MAX_FRAME_SAMP, fec); + } + + i += SETUP_BYTE_COUNT + len; + } + + opus_decoder_destroy(dec); + free(pcm); + free(packet); + + return 0; +} diff --git a/native/codec/libraries/opus/tests/opus_decode_fuzzer.options b/native/codec/libraries/opus/tests/opus_decode_fuzzer.options new file mode 100644 index 0000000..e5ae71b --- /dev/null +++ b/native/codec/libraries/opus/tests/opus_decode_fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 1000000 diff --git a/native/codec/libraries/opus/tests/opus_encode_regressions.c b/native/codec/libraries/opus/tests/opus_encode_regressions.c new file mode 100644 index 0000000..2923473 --- /dev/null +++ b/native/codec/libraries/opus/tests/opus_encode_regressions.c @@ -0,0 +1,1035 @@ +/* Copyright (c) 2016 Mark Harris, Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "opus_multistream.h" +#include "opus.h" +#include "test_opus_common.h" + + +static int celt_ec_internal_error(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[2460]; + int streams; + int coupled_streams; + unsigned char mapping[1]; + + enc = opus_multistream_surround_encoder_create(16000, 1, 1, &streams, + &coupled_streams, mapping, OPUS_APPLICATION_VOIP, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(OPUS_AUTO)); + { + static const short pcm[320] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1792, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 0, 25600, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 7, 0, 255, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32767, -1, + 0, 0, 0, 100, 0, 16384, 0, 0, 0, + 0, 0, 0, 4, 0, 0, -256, 255, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,-32768, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 128, 0, 0, 0, 0, + 0, 0, 0, 0, -256, 0, 0, 32, 0, + 0, 0, 0, 0, 0, 0, 4352, 4, 228, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5632, 0, 0, + 0, 0,-32768, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 256, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3944, 10500, 4285, 10459, -6474, 10204, -6539, 11601, -6824, + 13385, -7142, 13872,-11553, 13670, -7725, 13463, -6887, 7874, + -5580, 12600, -4964, 12480, 3254, 11741, -4210, 9741, -3155, + 7558, -5468, 5431, -1073, 3641, -1304, 0, -1, 343, + 26, 0, 0, 150, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1799, 1799, 1799, 1799, 1799, -2553, + 7, 1792, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, -9721 + }; + err = opus_multistream_encode(enc, pcm, 320, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9526, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, 25600, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9494, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9479, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + -256, 255, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 0, 0, 0, 0, + 4352, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 148, 0, 0, 0, 0, + 5632 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(12)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(41)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(21425)); + { + static const short pcm[40] = + { + 10459, -6474, 10204, -6539, 11601, -6824, 13385, -7142, 13872, + -11553, 13670, -7725, 13463, -6887, 12482, -5580, 12600, -4964, + 12480, 3254, 11741, -4210, 9741, -3155, 7558, -5468, 5431, + -1073, 3641, -1304, 0, -1, 343, 26, 0, 0, + 0, 0, -256, 226 + }; + err = opus_multistream_encode(enc, pcm, 40, data, 2460); + assert(err > 0); + /* returns -3 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int mscbr_encode_fail10(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[627300]; + static const unsigned char mapping[255] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, + 102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, + 119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, + 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, + 170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, + 187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203, + 204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, + 221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237, + 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254 + }; + + enc = opus_multistream_encoder_create(8000, 255, 254, 1, mapping, + OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(2)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(14)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(57)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(3642675)); + { + static const short pcm[20*255] = + { + 0 + }; + err = opus_multistream_encode(enc, pcm, 20, data, 627300); + assert(err > 0); + /* returns -1 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int mscbr_encode_fail(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[472320]; + static const unsigned char mapping[192] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, + 102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, + 119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, + 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, + 170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, + 187,188,189,190,191 + }; + + enc = opus_multistream_encoder_create(8000, 192, 189, 3, mapping, + OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(15360)); + { + static const short pcm[20*192] = + { + 0 + }; + err = opus_multistream_encode(enc, pcm, 20, data, 472320); + assert(err > 0); + /* returns -1 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int surround_analysis_uninit(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[7380]; + int streams; + int coupled_streams; + unsigned char mapping[3]; + + enc = opus_multistream_surround_encoder_create(24000, 3, 1, &streams, + &coupled_streams, mapping, OPUS_APPLICATION_AUDIO, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(84315)); + { + static const short pcm[960*3] = + { + -6896, 4901, -6158, 4120, -5164, 3631, -4442, 3153, -4070, + 3349, -4577, 4474, -5541, 5058, -6701, 3881, -7933, 1863, + -8041, 697, -6738,-31464, 14330,-12523, 4096, -6130, 29178, + -250,-21252, 10467, 16907, -3359, -6644, 31965, 14607,-21544, + -32497, 24020, 12557,-26926,-18421, -1842, 24587, 19659, 4878, + 10954, 23060, 8907,-10215,-16179, 31772,-11825,-15590,-23089, + 17173,-25903,-17387, 11733, 4884, 10204,-16476,-14367, 516, + 20453,-16898, 20967,-23813, -20, 22011,-17167, 9459, 32499, + -25855, -523, -3883, -390, -4206, 634, -3767, 2325, -2751, + 3115, -2392, 2746, -2173, 2317, -1147, 2326, 23142, 11314, + -15350,-24529, 3026, 6146, 2150, 2476, 1105, -830, 1775, + -3425, 3674,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + 4293,-14023, 3879,-15553, 3158,-16161, 2629, 18433,-12535, + -6645,-20735,-32763,-13824,-20992, 25859, 13052, -8731, 2292, + -3860, 24049, 10225,-19220, 10478,-22294, 22773, 28137, 13816, + 30953,-25863,-24598, 16888,-14612,-28942, 20974,-27397,-18944, + -18690, 20991,-16638, 5632,-14330, 28911,-25594, 17408, 29958, + -517,-20984, -1800, 11281, 9977,-21221,-14854, 23840, -9477, + 3362,-12805,-22493, 32507, 156, 16384, -1163, 2301, -1874, + 4600, -1748, 6950, 16557, 8192, -7372, -1033, -3278, 2806, + 20275, 3317, -717, 9792, -767, 9099, -613, 8362, 5027, + 7774, 2597, 8549, 5278, 8743, 9343, 6940, 13038, 4826, + 14086, 2964, 13215, 1355, 11596, 455, 9850, -519, 10680, + -2287, 12551, -3736, 13639, -4291, 13790, -2722, 14544, -866, + 15050, -304, 22833, -1196, 13520, -2063, 13051, -2317, 13066, + -2737, 13773, -2664, 14105, -3447, 13854, 24589, 24672, -5280, + 10388, -4933, 7543, -4149, 3654, -1552, 1726, 661, 57, + 2922, -751, 3917, 8419, 3840, -5218, 3435, 5540, -1073, + 4153, -6656, 1649, -769, -7276,-13072, 6380, -7948, 20717, + 18425, 17392, 14335,-18190, -1842, 24587, 19659, 11790, 10954, + 23060, 8907,-10215,-16179, 31772,-11825,-15590,-23101, 17173, + -25903,-17387, 11733, 4884, 10192,-16627,-14367, 516, 20453, + -16898, 20967,-23813, -20, 22011,-17167, 9468, 32499,-25607, + -523, -3883, -390, -4206, 634, -3767, 2325, -2751, 3115, + -2392, 2746, -2161, 2317, -1147, 2326, 23142, 11314,-15350, + -29137, 3026,-15056, -491,-15170, -386,-16015, -641,-16505, + -930,-16206, -717,-16175, -2839,-16374, -4558,-16237, -5207, + -15903, -6421, 6373, -1403, 5431, -1073, 3641, -1304, -4495, + -769, -7276, 2856, -7870, 3314, -8730, 3964,-10183, 4011, + -11135, 3421,-11727, 2966,-12360, 2818,-13472, 3660,-13805, + 5162,-13478, 6434,-12840, 7335,-12420, 6865,-12349, 5541, + -11965, 5530,-10820, 5132, -9197, 3367, -7745, 1223, -6910, + -433, -6211, -1711, -4958, -1025, -3755, -836, -3292, -1666, + -2661,-10755, 31472,-27906, 31471, 18690, 5617, 16649, 11253, + -22516,-17674,-31990, 3575,-31479, 5883, 26121, 12890, -6612, + 12228,-11634, 523, 26136,-21496, 20745,-15868, -4100,-24826, + 23282, 22798, 491, -1774, 15075,-27373,-13094, 6417,-29487, + 14608, 10185, 16143, 22211, -8436, 4288, -8694, 2375, 3023, + 486, 1455, 128, 202, 942, -923, 2068, -1233, -717, + -1042, -2167, 32255, -4632, 310, -4458, -3639, -5258, 2106, + -6857, 2681, -7497, 2765, -6601, 1945, -5219, 19154, -4877, + 619, -5719, -1928, -6208, -121, 593, 188, 1558, -4152, + 1648, 156, 1604, -3664, -6862, -2851, -5112, -3600, -3747, + -5081, -4428, -5592, 20974,-27397,-18944,-18690, 20991,-17406, + 5632,-14330, 28911, 15934, 15934, 15934, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934,-25594, 17408, 29958, + -7173,-16888, 9098, -613, 8362, 675, 7774, 2597, 8549, + 5278, 8743, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24353, + 28648, 6946, -1363, 12485, -1187, 26074,-25055, 10004,-24798, + 7204, -4581, -9678, 1554, 10553, 3102, 12193, 2443, 11955, + 1213, 10689, -1293, 921, -4173, 10709, -6049, 8815, -7128, + 8147, -8308, 6847, -2977, 4920,-11447,-22426,-11794, 3514, + -10220, 3430, -7993, 1926, -7072, 327, -7569, -608, -7605, + 3695, -6271, -1579, -4877, -1419, -3103, -2197, 128, -3904, + 3760, -5401, 4906, -6051, 4250, -6272, 3492, -6343, 3197, + -6397, 4041, -6341, 6255, -6381, 7905, 16504, 0, -6144, + 8062, -5606, 8622, -5555, -9, -1, 7423, 0, 1, + 238, 5148, 1309, 4700, 2218, 4403, 2573, 3568, 28303, + 1758, 3454, -1247, 3434, -4912, 2862, -7844, 1718,-10095, + 369,-12631, 128, -3904, 3632, -5401, 4906, -6051, 4250, + -6272, 3492, -6343, 3197, -6397, 4041, -6341, 6255, -6381, + 7905, 16504, 0, -6144, 8062, -5606, 8622, -5555, 8439, + -3382, 7398, -1170, 6132, 238, 5148, 1309, 4700, 2218, + 4403, 2573, 3568, 2703, 1758, 3454, -1247, 3434, -4912, + 2862, -7844, 1718,-10095, 369,-12631, -259,-14632, 234, + -15056, -521,-15170, -386,-16015, -641,-16505, -930,-16206, + -1209,-16146, -2839,-16374, -4558,-16218, -5207,-15903, -6421, + -15615, -6925,-14871, -6149,-13759, -5233,-12844, 18313, -4357, + -5696, 2804, 12992,-22802, -6720, -9770, -7088, -8998, 14330, + -12523, 14843, -6130, 29178, -250,-27396, 10467, 16907, -3359, + -6644, 31965, 14607,-21544,-32497, 24020, 12557,-26926, -173, + -129, -6401, -130,-25089, -3841, -4916, -3048, 224, -237, + -3969, -189, -3529, -535, -3464,-14863,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14395,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 0, 32512,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907, 9925, -718, 9753, -767, + 9099, -613, 8362, 675, 7774, 2597, 8549, 5278, 8743, + 9375, 6940, 13038, 4826, 14598, 7721,-24308,-29905,-19703, + -17106,-16124, -3287,-26118,-19709, 0, 24353, 28648, 10274, + -11292,-29665,-16417, 24346, 14553, 18707, 26323, -4596,-17711, + 5133, 26328, 13,-31168, 24583, 18404,-28927,-24350, 19453, + 28642, 1019,-10777, -3079, 30188, -7686, 27635,-32521,-16384, + 12528, -6386, 10986, 23827,-25880,-32752,-23321, 14605, 32231, + 780,-13849, 15119, 28647, 4888, -7705, 30750, 64, 0, + 32488, 6687,-20758, 19745, -2070,-13792, -6414, 28188, -2821, + -4585, 7168, 7444, 23557,-21998, 13064, 3345, -4086,-28915, + -8694, 32262, 8461, 27387,-12275, 12012, 23563,-18719,-28410, + 29144,-22271, -562, -9986, -5434, 12288, 5573,-16642, 32448, + 29182, 32705,-30723, 24255,-19716, 18368, -4357, -5696, 2804, + 12992,-22802,-22080, -7701, -5183, 486, -3133, -5660, -1083, + 16871,-28726,-11029,-30259, -1209,-16146, -2839,-16374, -4558, + -16218,-10523, 20697, -9500, -1316, 5431, -1073, 3641, -1304, + 1649, -769, -7276, 2856, -7870, 3314, -8730, 3964,-10183, + 4011,-11135, 3421,-11727, 21398, 32767, -1, 32486, -1, + 6301,-13071, 6380, -7948, -1, 32767, 240, 14081, -5646, + 30973, -3598,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, 32767,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907, 8901, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24361, + 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, 26323, + -4440,-17711, 5133, 26328,-14579,-31008, 24583, 18404, 28417, + -24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, 27635, + -32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752,-23321, + 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705,-15074, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907, 8192,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14897,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -15931,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 26121, 12890, 2604, + 12228,-11634, 12299, 5573,-16642, 32452, 29182, 32705,-30723, + 24255,-19716, 13248,-11779, -5696, 2804, 12992,-27666,-22080, + -7701, -5183, -6682,-31464, 14330,-12523, 14843, -6130, 29178, + -18,-27396, 10467, 16907, -3359, -6644, 31965, 14607,-21544, + -32497, 24020, 12557,-26926,-18421, 706, 24587, 19659, 4878, + 10954, 23060, 8907,-10215,-22579, 31772,-11825,-15590,-23089, + 17173,-25903,-17387, 3285, 4884, 10204,-16627,-14367, 516, + 20453,-16898, 20967,-23815, -20, 22011,-17167, 9468, 32499, + -25607, -523, -3883, -390, -4206, 634, -3767, 2325, -2751, + 3115, -2392, 2746, -2173, 2317, -1147, 2326, 23142, 11314, + -15130,-29137, 3026, 6146, 2150, 2476, 1105, -830, 1775, + -3425, 3674, -5287, 4609, -7175, 4922, -9579, 4556,-12007, + 4236,-14023, 3879,-15553, 3158,-16161, 2576, 18398,-12535, + -6645,-20735,-32763,-13824,-20992, 25859, 5372, 12040, 13307, + -4355,-30213, -9, -6019, 14061,-31487,-13842, 30449, 15083, + 14088, 31205,-18678,-12830, 14090,-26138,-25337,-11541, -3254, + 27628,-22270, 30953,-16136,-30745, 20991,-17406, 5632,-14330, + 28911,-25594, 17408,-20474, 13041, -8731, 2292, -3860, 24049, + 10225,-19220, 10478, -4374, -1199, 148, -330, -74, 593, + 188, 1558, -4152, 15984, 15934, 15934, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934, 1598, 156, 1604, + -1163, 2278,-30018,-25821,-21763,-23776, 24066, 9502, 25866, + -25055, 10004,-24798, 7204, -4581, -9678, 1554, 10553, 3102, + 12193, 2443, 11955, 1213, 10689, -1293, 921, -4173, 8661, + -6049, 8815,-21221,-14854, 23840, -9477, 8549, 5278, 8743, + 9375, 6940, 13038, 4826, 14598, 7721,-24308,-29905,-19703, + -17106,-16124, -3287,-26118,-19709,-10769, 24361, 28648, 10274, + -11292,-29665,-16417, 24346, 14580, 18707, 26323, -4410,-17711, + 5133, 26328,-14579,-31008, 24583, 18404, 28417,-24350, 19453, + 28642,-32513,-10777, -3079, 30188, -7686, 27635,-32521,-16384, + -20240, -6386, 10986, 23827,-25880,-32752,-23321, 14605, 32231, + 780,-13849, 15119, 28647, 4888, -7705, 30750, 64, 0, + 32488, 6687,-20758, 19745, -2070, -1, -1, 28, 256, + -4608, 7168, 7444, 23557,-21998, 13064, 3345, -4086,-28915, + -8594, 32262, 8461, 27387,-12275, 12012, 23563,-18719,-28410, + 29144,-22271,-32562,-16384, 12528, -6386, 10986, 23827,-25880, + -32752,-23321, 14605, 32231, 780,-13849, 15119, 28647, 4888, + -7705, 30750, 64, 0, 32488, 6687,-20758, 19745, -2070, + -13792, -6414, 28188, -2821, -4585, 7168, 7444, 23557,-21998, + 13064, 3345, -4086,-28915, -8694, 32262, 8461, 27387,-12275, + 12012, 23563,-18719,-28410, 29144,-22271, -562, -9986, -5434, + 12288, -2107,-16643, 32452, 29182, 32705,-30723, 24255,-19716, + 18368, -4357, -5696, 2804, 12992,-22802,-22080, -7701, -5183, + 486, -3133, -5660, -1083, 16871,-28726,-11029,-30259, -1209, + -16146, -2839,-16374, -4558,-16218,-10523, 20697, -9500, -1316, + 5431, -1073, 3641, -1304, 1649, -769, -7276, 2856, -7870, + 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, 21398, + 32767, -1, 32486, -1, -99,-13072, 6380, -7948, 4864, + 32767, 17392, 14335, -5646, 30973, -3598,-10299,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14905,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-19771,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-16443,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-15931,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, -1,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 7877, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, -994, -7276, 2856, -7870, + 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, 21398, + 32767, -1, 32486, -1, -99,-13072, 6380, -7948, 4864, + 32767, 17392, 14335, -5646, 30973, -3598,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14905,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 197, 0,-14977,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 12838, 6653, 294, + -29699,-25821,-21763,-23776, 24066, 9502, 25866,-25055, 10004, + -24798, 7204, -4581, -9678, 1554, 10553, 3102, 12193, 2443, + 11955, 1213, 10689, -1293, 921, 179, 8448, -6049, 8815, + -7128, 8147, -8308, 6847, -9889, 4920,-11447, 3174,-11794, + 3514,-10220, 3430, 16384, 1926, -7072, 327, -7537, -608, + -7605, -1169, -6397, -1579, -4877, -1419, -3103, -2197, 128, + -3904, 3632, -5401, 4906, -6051, 4250, -6272, 3492, -6343, + 3197, -6397, 4041, -6341, 6255, -6381, 7905, 16504, 0, + -6144, 8062, -5606, 8622, -5555, 8439, -3382, 7398, -1170, + 6132, 238, 5148, 1309, 4700, 2218, 4403, 2573, 3568, + 2703, 1758, 3454, -1247, 3434, -4912, 2862, -7844, 1718, + -10095, 369,-12631, -259,-14632, 234,-15056, -491,-16194, + -386,-16015, -641,-16505, -930,-16206, -1209,-16146, -2839, + -16374, -4558,-16218, -5207,-15903, -6421,-15615, -6925,-14871, + -6149,-13759, -5233,-12844, 18313, -4357, -5696, 2804, 12992, + -22802, -6720, -9770, -7088, -8998, 14330,-12523, 14843, -6130, + 29178, -250,-27396, 10467, 16907, -3359, -6644, 31965, 14607, + -21544,-32497, 24020, 12557,-26926, -173, -129, -6401, -130, + -25089, -3816, -4916, -3048, -32, -1, -3969, 256, -3529, + -535, -3464,-14863,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -1209,-16146, -2839,-16374, -4558,-16218,-10523, 20697, -9500, + -1316, 5431, -1073, 3641, -1304, 1649, -769, -7276, 2856, + -7870, 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, + 21398, 32767, -1, 32486, -1, 6301,-13071, 6380, -7948, + -1, 32767, 240, 14081, -5646, 30973, -3598,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + 32767,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 8901, 9375, 6940, + 13038, 4826, 14598, 7721,-24308,-29905,-19703,-17106,-16124, + -3287,-26118,-19709,-10769, 24361, 28648, 10274,-11292,-29665, + -16417, 24346, 14580, 18707, 26323, -4440,-17711, 5133, 26328, + -14579,-31008, 24583, 18404, 28417,-24350, 19453, 28642,-32513, + -10777, -3079, 30188, -7686, 27635,-32521,-16384,-20240, -6386, + 10986, 23827,-25880,-32752,-23321, 14605, 32231, 780,-13849, + 15119, 28647, 4888, -7705,-15074,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, 8192, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14897, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-15931,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 26121, 12890, 2604, 12228,-11634, 12299, 5573, + -16642, 32452, 29182, 32705,-30723, 24255,-19716, 13248,-11779, + -5696, 2804, 12992,-27666,-22080, -7701, -5183, -6682,-31464, + 14330,-12523, 14843, -6130, 29178, -18,-27396, 10467, 16907, + -3359, -6644, 31965, 14607,-21544,-32497, 24020, 12557,-26926, + -18421, 706, 24587, 19659, 4878, 10954, 23060, 8907,-10215, + -22579, 31772,-11825,-15590,-23089, 17173,-25903,-17387, 3285, + 4884, 10204,-16627,-14367, 516, 20453,-16898, 20967,-23815, + -20, 22011,-17167, 9468, 32499,-25607, -523, -3883, -390, + -4206, 634, -3767, 2325, -2751, 3115, -2392, 2746, -2173, + 2317, -1147, 2326, 23142, 11314,-15130,-29137, 3026, 6146, + 2150, 2476, 1105, -830, 1775, -3425, 3674, -5287, 4609, + -7175, 4922, -9579, 4556,-12007, 4236,-14023, 3879,-15553, + 3158,-16161, 2576, 18398,-12535, -6645,-20735,-32763,-13824, + -20992, 25859, 5372, 12040, 13307, -4355,-30213, -9, -6019 + }; + err = opus_multistream_encode(enc, pcm, 960, data, 7380); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(6)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(9)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(5)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(775410)); + { + static const short pcm[1440*3] = + { + 30449, 15083, 14088, 31205,-18678,-12830, 14090,-26138,-25337, + -11541, -3254, 27628,-22270, 30953,-16136,-30745, 20991,-17406, + 5632,-14330, 28911,-25594, 17408,-20474, 13041, -8731, 2292, + -3860, 24049, 10225,-19220, 10478, -4374, -1199, 148, -330, + -74, 593, 188, 1558, -4152, 15984, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934, 15934, 15934, 1598, + 156, 1604, -1163, 2278,-30018,-25821,-21763,-23776, 24066, + 9502, 25866,-25055, 10004,-24798, 7204, -4581, -9678, 1554, + 10553, 3102, 12193, 2443, 11955, 1213, 10689, -1293, 921, + -4173, 8661, -6049, 8815,-21221,-14854, 23840, -9477, 8549, + 5278, 8743, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24361, + 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, 26323, + -4410,-17711, 5133, 26328,-14579,-31008, 24583, 18404, 28417, + -24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, 27635, + -32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752,-23321, + 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705, 30750, + 64, 0, 32488, 6687,-20758, 19745, -2070, -1, -1, + 28, 256, -4608, 7168, 7444, 23557,-21998, 13064, 3345, + -4086,-28915, -8594, 32262, 8461, 27387,-12275, 12012, 23563, + -18719,-28410, 29144,-22271,-32562,-16384, 12528, -6386, 10986, + 23827,-25880,-32752,-23321, 14605, 32231, 780,-13849, 15119, + 28647, 4888, -7705, 30750, 64, 0, 32488, 6687,-20758, + 19745, -2070,-13792, -6414, 28188, -2821, -4585, 7168, 7444, + 23557,-21998, 13064, 3345, -4086,-28915, -8694, 32262, 8461, + -14853,-14907,-14907,-14907,-14907, 32767,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14891,-14907,-14907,-14907, + -14907,-14907, 8901, 9375, 6940, 13038, 4826, 14598, 7721, + -24308,-29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, + 24361, 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, + 26323, -4440,-17711, 5133, 26328,-14579,-31008, 24583, 18404, + 28417,-24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, + 27635,-32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752, + -23321, 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705, + -15074,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, 8192,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14897,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-15931,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907, 26121, 12890, + 2604, 12228,-11634, 12299, 5573,-16642, 32452, 29182, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-10811,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14917,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14938,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, -571, -9986, -58, 12542,-18491, + 32507, 12838, 6653, 294, -1, 0,-19968, 18368, -4357, + -5696, 2804, 12998,-22802,-22080, -7701, -5183, 486, -3133, + -5660, -1083, 13799,-28726,-11029, 205,-14848, 32464, -1, + -129,-13072, 6380, -7948, 20717, 18425, 17392, 14335, -5646, + 30973, -3598, 7188, -3867, 3055, -4247, 5597, -4011,-26427, + -11,-30418, 7922, 2614, 237, -5839,-27413,-17624,-29716, + -13539, 239, 20991, 18164, -4082,-16647,-27386, 19458, 20224, + 4619, 19728, -7409,-18186,-25073, 27627,-23539, -7945,-31464, + 14330,-12523,-22021, -7701, -5183, 486, -3133, -5660, -1083, + 13799,-28726,-11029, 205,-14848, 32464, -1, -129,-13072, + 6380, -7948, 20717, 18425, 17392, 14093, -5646, 30973, -3598, + 7188, -3867, 3055, 3689, -5401, 4906, -6051, 4250, -6272, + 3492, -6343, 3197, -6397, 4041, -6341, 6255, -6381, 239, + 20991, 18164, -4082,-16647,-27386, 19458, 20224, 4619, 19728, + -7409,-18186,-25073, 27627,-23539, -7945,-31464, 14330,-12523, + 14843, -6130, 30202, -250,-28420, 10467, 16907, -3359, -6644, + 31965, 3343,-11727, 2966,-12616, 3064,-13472, 6732,-12349, + 5541,-11965, 5530,-10820, -1912, -3637, 32285, -4607, 310, + -32768, 0, -5258, 2106, -6857, 2681, -5449, -3606, -6717, + -5482, -3606, -1853, 4082, -7631, -9808, -1742, -2851, -5112, + 64, -868,-13546,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365, 7883, -2316, + 9086, -3944, 10500, 4285, 10459, -6474, 10204, -6539, 11601, + -6824, 13385, -7142, 13872, -7457, 13670, -7725, 13463, -6887, + 12482, -5580, 12600, -4964, 12480, 3254, 11741, -4210,-24819, + 23282, 22798, 491, -1774, -1073, 3641, -1304, 28928, -250, + -27396, 6657, -8961, 22524, 19987, 10231, 1791, 8947,-32763, + -26385,-31227, -792,-30461, 8926, 4866, 27863, 27756, 27756, + 27756, 27756, 27756, 27756, 27756, 27756, 5630,-11070,-16136, + 20671,-11530, 27328, 8179, 5059,-31503,-24379,-19472, 17863, + -29202, 22986, -23, 8909, 8422, 10450 + }; + err = opus_multistream_encode(enc, pcm, 1440, data, 7380); + /* reads uninitialized data at src/opus_multistream_encoder.c:293 */ + assert(err > 0); + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int ec_enc_shrink_assert(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[2000]; + static const short pcm1[960] = { 5140 }; + static const short pcm2[2880] = + { + -256,-12033, 0, -2817, 6912, 0, -5359, 5200, 3061, + 0, -2903, 5652, -1281,-24656,-14433,-24678, 32,-29793, + 2870, 0, 4096, 5120, 5140, -234,-20230,-24673,-24633, + -24673,-24705, 0,-32768,-25444,-25444, 0,-25444,-25444, + 156,-20480, -7948, -5920, -7968, -7968, 224, 0, 20480, + 11, 20496, 13, 20496, 11,-20480, 2292,-20240, 244, + 20480, 11, 20496, 11,-20480, 244,-20240, 7156, 20456, + -246,-20243, 244, 128, 244, 20480, 11, 20496, 11, + -20480, 244,-20256, 244, 20480, 256, 0, -246, 16609, + -176, 0, 29872, -4096, -2888, 516, 2896, 4096, 2896, + -20480, -3852, -2896, -1025,-31056,-14433, 244, 1792, -256, + -12033, 0, -2817, 0, 0, -5359, 5200, 3061, 16, + -2903, 5652, -1281,-24656,-14433,-24678, 32,-29793, 2870, + 0, 4096, 5120, 5140, -234,-20230,-24673,-24633,-24673, + -24705, 0,-32768,-25444,-25444, 0,-25444,-25444, 156, + -20480, -7973, -5920, -7968, -7968, 224, 0, 20480, 11, + 20496, 11, 20496, 11,-20480, 2292,-20213, 244, 20480, + 11, 20496, 11,-24698, -2873, 0, 7, -1, 208, + -256, 244, 0, 4352, 20715, -2796, 11,-22272, 5364, + -234,-20230,-24673,-25913, 8351,-24832, 13963, 11, 0, + 16, 5140, 5652, -1281,-24656,-14433,-24673, 32671, 159, + 0,-25472,-25444, 156,-25600,-25444,-25444, 0, -2896, + -7968, -7960, -7968, -7968, 0, 0, 2896, 4096, 2896, + 4096, 2896, 0, -2896, -4088, -2896, 0, 2896, 0, + -2896, -4096, -2896, 11, 2640, -4609, -2896,-32768, -3072, + 0, 2896, 4096, 2896, 0, -2896, -4096, -2896, 0, + 80, 1, 2816, 0, 20656, 255,-20480, 116,-18192 + }; + static const short pcm3[2880] = { 0 }; + + enc = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(6)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(6000)); + data_len = opus_encode(enc, pcm1, 960, data, 2000); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(15600)); + data_len = opus_encode(enc, pcm2, 2880, data, 122); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(27000)); + data_len = opus_encode(enc, pcm3, 2880, data, 122); /* assertion failure */ + assert(data_len > 0); + + opus_encoder_destroy(enc); + return 0; +} + +static int ec_enc_shrink_assert2(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[2000]; + + enc = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(6)); + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(26)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(27000)); + { + static const short pcm[960] = { 0 }; + data_len = opus_encode(enc, pcm, 960, data, 2000); + assert(data_len > 0); + } + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + { + static const short pcm[480] = + { + 32767, 32767, 0, 0, 32767, 32767, 0, 0, 32767, 32767, + -32768, -32768, 0, 0, -32768, -32768, 0, 0, -32768, -32768 + }; + data_len = opus_encode(enc, pcm, 480, data, 19); + assert(data_len > 0); + } + opus_encoder_destroy(enc); + return 0; +} + +static int silk_gain_assert(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[1000]; + static const short pcm1[160] = { 0 }; + static const short pcm2[960] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767 + }; + + enc = opus_encoder_create(8000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(3)); + opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(6000)); + data_len = opus_encode(enc, pcm1, 160, data, 1000); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(2867)); + data_len = opus_encode(enc, pcm2, 960, data, 1000); + assert(data_len > 0); + + opus_encoder_destroy(enc); + return 0; +} + +void regression_test(void) +{ + fprintf(stderr, "Running simple tests for bugs that have been fixed previously\n"); + celt_ec_internal_error(); + mscbr_encode_fail10(); + mscbr_encode_fail(); + surround_analysis_uninit(); + ec_enc_shrink_assert(); + ec_enc_shrink_assert2(); + silk_gain_assert(); +} diff --git a/native/codec/libraries/opus/tests/run_vectors.sh b/native/codec/libraries/opus/tests/run_vectors.sh new file mode 100755 index 0000000..dcb76cf --- /dev/null +++ b/native/codec/libraries/opus/tests/run_vectors.sh @@ -0,0 +1,143 @@ +#!/bin/sh + +# Copyright (c) 2011-2012 Jean-Marc Valin +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of Internet Society, IETF or IETF Trust, nor the +# names of specific contributors, may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +rm -f logs_mono.txt logs_mono2.txt +rm -f logs_stereo.txt logs_stereo2.txt + +if [ "$#" -ne "3" ]; then + echo "usage: run_vectors.sh " + exit 1 +fi + +CMD_PATH=$1 +VECTOR_PATH=$2 +RATE=$3 + +: ${OPUS_DEMO:=$CMD_PATH/opus_demo} +: ${OPUS_COMPARE:=$CMD_PATH/opus_compare} + +if [ -d "$VECTOR_PATH" ]; then + echo "Test vectors found in $VECTOR_PATH" +else + echo "No test vectors found" + #Don't make the test fail here because the test vectors + #will be distributed separately + exit 0 +fi + +if [ ! -x "$OPUS_COMPARE" ]; then + echo "ERROR: Compare program not found: $OPUS_COMPARE" + exit 1 +fi + +if [ -x "$OPUS_DEMO" ]; then + echo "Decoding with $OPUS_DEMO" +else + echo "ERROR: Decoder not found: $OPUS_DEMO" + exit 1 +fi + +echo "==============" +echo "Testing mono" +echo "==============" +echo + +for file in 01 02 03 04 05 06 07 08 09 10 11 12 +do + if [ -e "$VECTOR_PATH/testvector$file.bit" ]; then + echo "Testing testvector$file" + else + echo "Bitstream file not found: testvector$file.bit" + fi + if "$OPUS_DEMO" -d "$RATE" 1 "$VECTOR_PATH/testvector$file.bit" tmp.out >> logs_mono.txt 2>&1; then + echo "successfully decoded" + else + echo "ERROR: decoding failed" + exit 1 + fi + "$OPUS_COMPARE" -r "$RATE" "$VECTOR_PATH/testvector${file}.dec" tmp.out >> logs_mono.txt 2>&1 + float_ret=$? + "$OPUS_COMPARE" -r "$RATE" "$VECTOR_PATH/testvector${file}m.dec" tmp.out >> logs_mono2.txt 2>&1 + float_ret2=$? + if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo "output matches reference" + else + echo "ERROR: output does not match reference" + exit 1 + fi + echo +done + +echo "==============" +echo Testing stereo +echo "==============" +echo + +for file in 01 02 03 04 05 06 07 08 09 10 11 12 +do + if [ -e "$VECTOR_PATH/testvector$file.bit" ]; then + echo "Testing testvector$file" + else + echo "Bitstream file not found: testvector$file" + fi + if "$OPUS_DEMO" -d "$RATE" 2 "$VECTOR_PATH/testvector$file.bit" tmp.out >> logs_stereo.txt 2>&1; then + echo "successfully decoded" + else + echo "ERROR: decoding failed" + exit 1 + fi + "$OPUS_COMPARE" -s -r "$RATE" "$VECTOR_PATH/testvector${file}.dec" tmp.out >> logs_stereo.txt 2>&1 + float_ret=$? + "$OPUS_COMPARE" -s -r "$RATE" "$VECTOR_PATH/testvector${file}m.dec" tmp.out >> logs_stereo2.txt 2>&1 + float_ret2=$? + if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo "output matches reference" + else + echo "ERROR: output does not match reference" + exit 1 + fi + echo +done + + + +echo "All tests have passed successfully" +mono1=`grep quality logs_mono.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +mono2=`grep quality logs_mono2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +echo $mono1 $mono2 | awk '{if ($2 > $1) $1 = $2; print "Average mono quality is", $1, "%"}' + +stereo1=`grep quality logs_stereo.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +stereo2=`grep quality logs_stereo2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +echo $stereo1 $stereo2 | awk '{if ($2 > $1) $1 = $2; print "Average stereo quality is", $1, "%"}' diff --git a/native/codec/libraries/opus/tests/test_opus_api.c b/native/codec/libraries/opus/tests/test_opus_api.c new file mode 100644 index 0000000..fb385c6 --- /dev/null +++ b/native/codec/libraries/opus/tests/test_opus_api.c @@ -0,0 +1,1904 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This tests the API presented by the libopus system. + It does not attempt to extensively exercise the codec internals. + The strategy here is to simply the API interface invariants: + That sane options are accepted, insane options are rejected, + and that nothing blows up. In particular we don't actually test + that settings are heeded by the codec (though we do check that + get after set returns a sane value when it should). Other + tests check the actual codec behavior. + In cases where its reasonable to do so we test exhaustively, + but its not reasonable to do so in all cases. + Although these tests are simple they found several library bugs + when they were initially developed. */ + +/* These tests are more sensitive if compiled with -DVALGRIND and + run inside valgrind. Malloc failure testing requires glibc. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "arch.h" +#include "opus_multistream.h" +#include "opus.h" +#include "test_opus_common.h" + +#ifdef VALGRIND +#include +#define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +#define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +#else +#define VG_UNDEF(x,y) +#define VG_CHECK(x,y) +#endif + +#if defined(HAVE___MALLOC_HOOK) +#define MALLOC_FAIL +#include "os_support.h" +#include + +static const opus_int32 opus_apps[3] = {OPUS_APPLICATION_VOIP, + OPUS_APPLICATION_AUDIO,OPUS_APPLICATION_RESTRICTED_LOWDELAY}; + +void *malloc_hook(__attribute__((unused)) size_t size, + __attribute__((unused)) const void *caller) +{ + return 0; +} +#endif + +opus_int32 *null_int_ptr = (opus_int32 *)NULL; +opus_uint32 *null_uint_ptr = (opus_uint32 *)NULL; + +static const opus_int32 opus_rates[5] = {48000,24000,16000,12000,8000}; + +opus_int32 test_dec_api(void) +{ + opus_uint32 dec_final_range; + OpusDecoder *dec; + OpusDecoder *dec2; + opus_int32 i,j,cfgs; + unsigned char packet[1276]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int c,err; + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Decoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(c=0;c<4;c++) + { + i=opus_decoder_get_size(c); + if(((c==1||c==2)&&(i<=2048||i>1<<16))||((c!=1&&c!=2)&&i!=0))test_failed(); + fprintf(stdout," opus_decoder_get_size(%d)=%d ...............%s OK.\n",c,i,i>0?"":"...."); + cfgs++; + } + + /*Test with unsupported sample rates*/ + for(c=0;c<4;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + dec = opus_decoder_create(fs, c, &err); + if(err!=OPUS_BAD_ARG || dec!=NULL)test_failed(); + cfgs++; + dec = opus_decoder_create(fs, c, 0); + if(dec!=NULL)test_failed(); + cfgs++; + dec=malloc(opus_decoder_get_size(2)); + if(dec==NULL)test_failed(); + err = opus_decoder_init(dec,fs,c); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(dec); + } + } + + VG_UNDEF(&err,sizeof(err)); + dec = opus_decoder_create(48000, 2, &err); + if(err!=OPUS_OK || dec==NULL)test_failed(); + VG_CHECK(dec,opus_decoder_get_size(2)); + cfgs++; + + fprintf(stdout," opus_decoder_create() ........................ OK.\n"); + fprintf(stdout," opus_decoder_init() .......................... OK.\n"); + + err=opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(null_uint_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&dec_final_range,sizeof(dec_final_range)); + err=opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + if(err!=OPUS_OK)test_failed(); + VG_CHECK(&dec_final_range,sizeof(dec_final_range)); + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec,OPUS_UNIMPLEMENTED); + if(err!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&i)); + if(err != OPUS_OK || i!=0)test_failed(); + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec, OPUS_GET_SAMPLE_RATE(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_SAMPLE_RATE(&i)); + if(err != OPUS_OK || i!=48000)test_failed(); + fprintf(stdout," OPUS_GET_SAMPLE_RATE ......................... OK.\n"); + cfgs++; + + /*GET_PITCH has different execution paths depending on the previously decoded frame.*/ + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + VG_UNDEF(packet,sizeof(packet)); + packet[0]=63<<2;packet[1]=packet[2]=0; + if(opus_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + packet[0]=1; + if(opus_decode(dec, packet, 1, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_PITCH ............................... OK.\n"); + + err=opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&i)); + if(err != OPUS_OK || i!=960)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_LAST_PACKET_DURATION ................ OK.\n"); + + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=0)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-32769)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(32768)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-15)); + if(err != OPUS_OK)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=-15)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_GAIN ................................ OK.\n"); + fprintf(stdout," OPUS_GET_GAIN ................................ OK.\n"); + + /*Reset the decoder*/ + dec2=malloc(opus_decoder_get_size(2)); + memcpy(dec2,dec,opus_decoder_get_size(2)); + if(opus_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if(memcmp(dec2,dec,opus_decoder_get_size(2))==0)test_failed(); + free(dec2); + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + cfgs++; + + VG_UNDEF(packet,sizeof(packet)); + packet[0]=0; + if(opus_decoder_get_nb_samples(dec,packet,1)!=480)test_failed(); + if(opus_packet_get_nb_samples(packet,1,48000)!=480)test_failed(); + if(opus_packet_get_nb_samples(packet,1,96000)!=960)test_failed(); + if(opus_packet_get_nb_samples(packet,1,32000)!=320)test_failed(); + if(opus_packet_get_nb_samples(packet,1,8000)!=80)test_failed(); + packet[0]=3; + if(opus_packet_get_nb_samples(packet,1,24000)!=OPUS_INVALID_PACKET)test_failed(); + packet[0]=(63<<2)|3; + packet[1]=63; + if(opus_packet_get_nb_samples(packet,0,24000)!=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_nb_samples(packet,2,48000)!=OPUS_INVALID_PACKET)test_failed(); + if(opus_decoder_get_nb_samples(dec,packet,2)!=OPUS_INVALID_PACKET)test_failed(); + fprintf(stdout," opus_{packet,decoder}_get_nb_samples() ....... OK.\n"); + cfgs+=9; + + if(OPUS_BAD_ARG!=opus_packet_get_nb_frames(packet,0))test_failed(); + for(i=0;i<256;i++) { + int l1res[4]={1,2,2,OPUS_INVALID_PACKET}; + packet[0]=i; + if(l1res[packet[0]&3]!=opus_packet_get_nb_frames(packet,1))test_failed(); + cfgs++; + for(j=0;j<256;j++) { + packet[1]=j; + if(((packet[0]&3)!=3?l1res[packet[0]&3]:packet[1]&63)!=opus_packet_get_nb_frames(packet,2))test_failed(); + cfgs++; + } + } + fprintf(stdout," opus_packet_get_nb_frames() .................. OK.\n"); + + for(i=0;i<256;i++) { + int bw; + packet[0]=i; + bw=packet[0]>>4; + bw=OPUS_BANDWIDTH_NARROWBAND+(((((bw&7)*9)&(63-(bw&8)))+2+12*((bw&8)!=0))>>4); + if(bw!=opus_packet_get_bandwidth(packet))test_failed(); + cfgs++; + } + fprintf(stdout," opus_packet_get_bandwidth() .................. OK.\n"); + + for(i=0;i<256;i++) { + int fp3s,rate; + packet[0]=i; + fp3s=packet[0]>>3; + fp3s=((((3-(fp3s&3))*13&119)+9)>>2)*((fp3s>13)*(3-((fp3s&3)==3))+1)*25; + for(rate=0;rate<5;rate++) { + if((opus_rates[rate]*3/fp3s)!=opus_packet_get_samples_per_frame(packet,opus_rates[rate]))test_failed(); + cfgs++; + } + } + fprintf(stdout," opus_packet_get_samples_per_frame() .......... OK.\n"); + + packet[0]=(63<<2)+3; + packet[1]=49; + for(j=2;j<51;j++)packet[j]=0; + VG_UNDEF(sbuf,sizeof(sbuf)); + if(opus_decode(dec, packet, 51, sbuf, 960, 0)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + packet[0]=(63<<2); + packet[1]=packet[2]=0; + if(opus_decode(dec, packet, -1, sbuf, 960, 0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 60, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 480, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_decode() ................................ OK.\n"); +#ifndef DISABLE_FLOAT_API + VG_UNDEF(fbuf,sizeof(fbuf)); + if(opus_decode_float(dec, packet, 3, fbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_decode_float() .......................... OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_decoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decoder_init(0,48000,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decode(0,packet,1,outbuf,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decode_float(0,packet,1,0,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decoder_get_nb_samples(0,packet,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_packet_get_nb_frames(NULL,1) !=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_bandwidth(NULL) !=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_samples_per_frame(NULL,48000)!=OPUS_BAD_ARG)test_failed(); +#endif + opus_decoder_destroy(dec); + cfgs++; + fprintf(stdout," All decoder interface tests passed\n"); + fprintf(stdout," (%6d API invocations)\n",cfgs); + return cfgs; +} + +opus_int32 test_msdec_api(void) +{ + opus_uint32 dec_final_range; + OpusMSDecoder *dec; + OpusDecoder *streamdec; + opus_int32 i,j,cfgs; + unsigned char packet[1276]; + unsigned char mapping[256]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int a,b,c,err; + + mapping[0]=0; + mapping[1]=1; + for(i=2;i<256;i++)VG_UNDEF(&mapping[i],sizeof(unsigned char)); + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Multistream decoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(a=-1;a<4;a++) + { + for(b=-1;b<4;b++) + { + i=opus_multistream_decoder_get_size(a,b); + if(((a>0&&b<=a&&b>=0)&&(i<=2048||i>((1<<16)*a)))||((a<1||b>a||b<0)&&i!=0))test_failed(); + fprintf(stdout," opus_multistream_decoder_get_size(%2d,%2d)=%d %sOK.\n",a,b,i,i>0?"":"... "); + cfgs++; + } + } + + /*Test with unsupported sample rates*/ + for(c=1;c<3;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + dec = opus_multistream_decoder_create(fs, c, 1, c-1, mapping, &err); + if(err!=OPUS_BAD_ARG || dec!=NULL)test_failed(); + cfgs++; + dec = opus_multistream_decoder_create(fs, c, 1, c-1, mapping, 0); + if(dec!=NULL)test_failed(); + cfgs++; + dec=malloc(opus_multistream_decoder_get_size(1,1)); + if(dec==NULL)test_failed(); + err = opus_multistream_decoder_init(dec,fs,c,1,c-1, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(dec); + } + } + + for(c=0;c<2;c++) + { + int *ret_err; + ret_err = c?0:&err; + + mapping[0]=0; + mapping[1]=1; + for(i=2;i<256;i++)VG_UNDEF(&mapping[i],sizeof(unsigned char)); + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=mapping[1]=0; + dec = opus_multistream_decoder_create(48000, 2, 1, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, 4, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + + err = opus_multistream_decoder_init(dec,48000, 1, 0, 0, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + err = opus_multistream_decoder_init(dec,48000, 1, 1, -1, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 255, 255, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, -1, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 0, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, -1, 2, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, -1, -1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 256, 255, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 256, 255, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=255; + mapping[1]=1; + mapping[2]=2; + dec = opus_multistream_decoder_create(48000, 3, 2, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=0; + mapping[1]=0; + mapping[2]=0; + dec = opus_multistream_decoder_create(48000, 3, 2, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=0; + mapping[1]=255; + mapping[2]=1; + mapping[3]=2; + mapping[4]=3; + dec = opus_multistream_decoder_create(48001, 5, 4, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + } + + VG_UNDEF(&err,sizeof(err)); + mapping[0]=0; + mapping[1]=255; + mapping[2]=1; + mapping[3]=2; + dec = opus_multistream_decoder_create(48000, 4, 2, 1, mapping, &err); + VG_CHECK(&err,sizeof(err)); + if(err!=OPUS_OK || dec==NULL)test_failed(); + cfgs++; + + fprintf(stdout," opus_multistream_decoder_create() ............ OK.\n"); + fprintf(stdout," opus_multistream_decoder_init() .............. OK.\n"); + + VG_UNDEF(&dec_final_range,sizeof(dec_final_range)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + if(err!=OPUS_OK)test_failed(); + VG_CHECK(&dec_final_range,sizeof(dec_final_range)); + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + cfgs++; + + streamdec=0; + VG_UNDEF(&streamdec,sizeof(streamdec)); + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(-1,&streamdec)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(1,&streamdec)); + if(err!=OPUS_OK||streamdec==NULL)test_failed(); + VG_CHECK(streamdec,opus_decoder_get_size(1)); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(2,&streamdec)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(0,&streamdec)); + if(err!=OPUS_OK||streamdec==NULL)test_failed(); + VG_CHECK(streamdec,opus_decoder_get_size(1)); + fprintf(stdout," OPUS_MULTISTREAM_GET_DECODER_STATE ........... OK.\n"); + cfgs++; + + for(j=0;j<2;j++) + { + OpusDecoder *od; + err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od)); + if(err != OPUS_OK)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=0)test_failed(); + cfgs++; + } + err=opus_multistream_decoder_ctl(dec,OPUS_SET_GAIN(15)); + if(err!=OPUS_OK)test_failed(); + fprintf(stdout," OPUS_SET_GAIN ................................ OK.\n"); + for(j=0;j<2;j++) + { + OpusDecoder *od; + err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od)); + if(err != OPUS_OK)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=15)test_failed(); + cfgs++; + } + fprintf(stdout," OPUS_GET_GAIN ................................ OK.\n"); + + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&i)); + if(err != OPUS_OK || i!=0)test_failed(); + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + cfgs++; + + err=opus_multistream_decoder_ctl(dec,OPUS_UNIMPLEMENTED); + if(err!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + +#if 0 + /*Currently unimplemented for multistream*/ + /*GET_PITCH has different execution paths depending on the previously decoded frame.*/ + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + VG_UNDEF(packet,sizeof(packet)); + packet[0]=63<<2;packet[1]=packet[2]=0; + if(opus_multistream_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + packet[0]=1; + if(opus_multistream_decode(dec, packet, 1, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_PITCH ............................... OK.\n"); +#endif + + /*Reset the decoder*/ + if(opus_multistream_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + cfgs++; + + opus_multistream_decoder_destroy(dec); + cfgs++; + VG_UNDEF(&err,sizeof(err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, &err); + if(err!=OPUS_OK || dec==NULL)test_failed(); + cfgs++; + + packet[0]=(63<<2)+3; + packet[1]=49; + for(j=2;j<51;j++)packet[j]=0; + VG_UNDEF(sbuf,sizeof(sbuf)); + if(opus_multistream_decode(dec, packet, 51, sbuf, 960, 0)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + packet[0]=(63<<2); + packet[1]=packet[2]=0; + if(opus_multistream_decode(dec, packet, -1, sbuf, 960, 0)!=OPUS_BAD_ARG){printf("%d\n",opus_multistream_decode(dec, packet, -1, sbuf, 960, 0));test_failed();} + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, -960, 0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 60, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 480, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_multistream_decode() .................... OK.\n"); +#ifndef DISABLE_FLOAT_API + VG_UNDEF(fbuf,sizeof(fbuf)); + if(opus_multistream_decode_float(dec, packet, 3, fbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_multistream_decode_float() .............. OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_multistream_decoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decoder_init(0,48000,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decode(0,packet,1,outbuf,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decode_float(0,packet,1,0,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decoder_get_nb_samples(0,packet,1) !=OPUS_INVALID_STATE)test_failed(); +#endif + opus_multistream_decoder_destroy(dec); + cfgs++; + fprintf(stdout," All multistream decoder interface tests passed\n"); + fprintf(stdout," (%6d API invocations)\n",cfgs); + return cfgs; +} + +#ifdef VALGRIND +#define UNDEFINE_FOR_PARSE toc=-1; \ + frames[0]=(unsigned char *)0; \ + frames[1]=(unsigned char *)0; \ + payload_offset=-1; \ + VG_UNDEF(&toc,sizeof(toc)); \ + VG_UNDEF(frames,sizeof(frames));\ + VG_UNDEF(&payload_offset,sizeof(payload_offset)); +#else +#define UNDEFINE_FOR_PARSE toc=-1; \ + frames[0]=(unsigned char *)0; \ + frames[1]=(unsigned char *)0; \ + payload_offset=-1; +#endif + +/* This test exercises the heck out of the libopus parser. + It is much larger than the parser itself in part because + it tries to hit a lot of corner cases that could never + fail with the libopus code, but might be problematic for + other implementations. */ +opus_int32 test_parse(void) +{ + opus_int32 i,j,jj,sz; + unsigned char packet[1276]; + opus_int32 cfgs,cfgs_total; + unsigned char toc; + const unsigned char *frames[48]; + short size[48]; + int payload_offset, ret; + fprintf(stdout,"\n Packet header parsing tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + memset(packet,0,sizeof(char)*1276); + packet[0]=63<<2; + if(opus_packet_parse(packet,1,&toc,frames,0,&payload_offset)!=OPUS_BAD_ARG)test_failed(); + cfgs_total=cfgs=1; + /*code 0*/ + for(i=0;i<64;i++) + { + packet[0]=i<<2; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,4,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=1)test_failed(); + if(size[0]!=3)test_failed(); + if(frames[0]!=packet+1)test_failed(); + } + fprintf(stdout," code 0 (%2d cases) ............................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + /*code 1, two frames of the same size*/ + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+1; + for(jj=0;jj<=1275*2+3;jj++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,jj,&toc,frames,size,&payload_offset); + cfgs++; + if((jj&1)==1 && jj<=2551) + { + /* Must pass if payload length even (packet length odd) and + size<=2551, must fail otherwise. */ + if(ret!=2)test_failed(); + if(size[0]!=size[1] || size[0]!=((jj-1)>>1))test_failed(); + if(frames[0]!=packet+1)test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + fprintf(stdout," code 1 (%6d cases) ........................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + /*code 2, length code overflow*/ + packet[0]=(i<<2)+2; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=252; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + for(j=0;j<1275;j++) + { + if(j<252)packet[1]=j; + else{packet[1]=252+(j&3);packet[2]=(j-252)>>2;} + /*Code 2, one too short*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3)-1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Code 2, one too long*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3)+1276,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Code 2, second zero*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3),&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=2)test_failed(); + if(size[0]!=j||size[1]!=0)test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + /*Code 2, normal*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,(j<<1)+4,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=2)test_failed(); + if(size[0]!=j||size[1]!=(j<<1)+3-j-(j<252?1:2))test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + } + } + fprintf(stdout," code 2 (%6d cases) ........................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*code 3, length code overflow*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + fprintf(stdout," code 3 m-truncation (%2d cases) ............... OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + /*code 3, m is zero or 49-63*/ + packet[0]=(i<<2)+3; + for(jj=49;jj<=64;jj++) + { + packet[1]=0+(jj&63); /*CBR, no padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=128+(jj&63); /*VBR, no padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=64+(jj&63); /*CBR, padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=128+64+(jj&63); /*VBR, padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + fprintf(stdout," code 3 m=0,49-64 (%2d cases) ................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*code 3, m is one, cbr*/ + packet[1]=1; + for(j=0;j<1276;j++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=1)test_failed(); + if(size[0]!=j)test_failed(); + if((toc>>2)!=i)test_failed(); + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1276+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + fprintf(stdout," code 3 m=1 CBR (%2d cases) ................. OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + int frame_samp; + /*code 3, m>1 CBR*/ + packet[0]=(i<<2)+3; + frame_samp=opus_packet_get_samples_per_frame(packet,48000); + for(j=2;j<49;j++) + { + packet[1]=j; + for(sz=2;sz<((j+2)*1275);sz++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,sz,&toc,frames,size,&payload_offset); + cfgs++; + /*Must be <=120ms, must be evenly divisible, can't have frames>1275 bytes*/ + if(frame_samp*j<=5760 && (sz-2)%j==0 && (sz-2)/j<1276) + { + if(ret!=j)test_failed(); + for(jj=1;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + /*Super jumbo packets*/ + packet[1]=5760/frame_samp; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275*packet[1]+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=packet[1])test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+1276,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + for(j=2;j<49;j++) + { + packet[1]=128+j; + /*Length code overflow*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[2]=252; + packet[3]=0; + for(jj=4;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*One byte too short*/ + for(jj=2;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*One byte too short thanks to length coding*/ + packet[2]=252; + packet[3]=0; + for(jj=4;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j+252-1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Most expensive way of coding zeros*/ + for(jj=2;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-1,&toc,frames,size,&payload_offset); + cfgs++; + if(frame_samp*j<=5760){ + if(ret!=j)test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Quasi-CBR use of mode 3*/ + for(sz=0;sz<8;sz++) + { + const int tsz[8]={50,201,403,700,1472,5110,20400,61298}; + int pos=0; + int as=(tsz[sz]+i-j-2)/j; + for(jj=0;jj>2;pos+=2;} + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,tsz[sz]+i,&toc,frames,size,&payload_offset); + cfgs++; + if(frame_samp*j<=5760 && as<1276 && (tsz[sz]+i-2-pos-as*(j-1))<1276){ + if(ret!=j)test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + } + fprintf(stdout," code 3 m=1-48 VBR (%2d cases) ............. OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*Padding*/ + packet[1]=128+1+64; + /*Overflow the length coding*/ + for(jj=2;jj<127;jj++)packet[jj]=255; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,127,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + + for(sz=0;sz<4;sz++) + { + const int tsz[4]={0,72,512,1275}; + for(jj=sz;jj<65025;jj+=11) + { + int pos; + for(pos=0;pos>2)!=i)test_failed(); + } else if (ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + } + fprintf(stdout," code 3 padding (%2d cases) ............... OK.\n",cfgs); + cfgs_total+=cfgs; + fprintf(stdout," opus_packet_parse ............................ OK.\n"); + fprintf(stdout," All packet parsing tests passed\n"); + fprintf(stdout," (%d API invocations)\n",cfgs_total); + return cfgs_total; +} + +/* This is a helper macro for the encoder tests. + The encoder api tests all have a pattern of set-must-fail, set-must-fail, + set-must-pass, get-and-compare, set-must-pass, get-and-compare. */ +#define CHECK_SETGET(setcall,getcall,badv,badv2,goodv,goodv2,sok,gok) \ + i=(badv);\ + if(opus_encoder_ctl(enc,setcall)==OPUS_OK)test_failed();\ + i=(badv2);\ + if(opus_encoder_ctl(enc,setcall)==OPUS_OK)test_failed();\ + j=i=(goodv);\ + if(opus_encoder_ctl(enc,setcall)!=OPUS_OK)test_failed();\ + i=-12345;\ + VG_UNDEF(&i,sizeof(i)); \ + err=opus_encoder_ctl(enc,getcall);\ + if(err!=OPUS_OK || i!=j)test_failed();\ + j=i=(goodv2);\ + if(opus_encoder_ctl(enc,setcall)!=OPUS_OK)test_failed();\ + fprintf(stdout,sok);\ + i=-12345;\ + VG_UNDEF(&i,sizeof(i)); \ + err=opus_encoder_ctl(enc,getcall);\ + if(err!=OPUS_OK || i!=j)test_failed();\ + fprintf(stdout,gok);\ + cfgs+=6; + +opus_int32 test_enc_api(void) +{ + opus_uint32 enc_final_range; + OpusEncoder *enc; + opus_int32 i,j; + unsigned char packet[1276]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int c,err,cfgs; + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Encoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(c=0;c<4;c++) + { + i=opus_encoder_get_size(c); + if(((c==1||c==2)&&(i<=2048||i>1<<17))||((c!=1&&c!=2)&&i!=0))test_failed(); + fprintf(stdout," opus_encoder_get_size(%d)=%d ...............%s OK.\n",c,i,i>0?"":"...."); + cfgs++; + } + + /*Test with unsupported sample rates, channel counts*/ + for(c=0;c<4;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(fs, c, OPUS_APPLICATION_VOIP, &err); + if(err!=OPUS_BAD_ARG || enc!=NULL)test_failed(); + cfgs++; + enc = opus_encoder_create(fs, c, OPUS_APPLICATION_VOIP, 0); + if(enc!=NULL)test_failed(); + cfgs++; + opus_encoder_destroy(enc); + enc=malloc(opus_encoder_get_size(2)); + if(enc==NULL)test_failed(); + err = opus_encoder_init(enc, fs, c, OPUS_APPLICATION_VOIP); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(enc); + } + } + + enc = opus_encoder_create(48000, 2, OPUS_AUTO, NULL); + if(enc!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_AUTO, &err); + if(err!=OPUS_BAD_ARG || enc!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, NULL); + if(enc==NULL)test_failed(); + opus_encoder_destroy(enc); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + cfgs++; + opus_encoder_destroy(enc); + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + opus_encoder_destroy(enc); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + + fprintf(stdout," opus_encoder_create() ........................ OK.\n"); + fprintf(stdout," opus_encoder_init() .......................... OK.\n"); + + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_LOOKAHEAD ........................... OK.\n"); + + err=opus_encoder_ctl(enc,OPUS_GET_SAMPLE_RATE(&i)); + if(err!=OPUS_OK || i!=48000)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_SAMPLE_RATE(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_SAMPLE_RATE ......................... OK.\n"); + + if(opus_encoder_ctl(enc,OPUS_UNIMPLEMENTED)!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + + err=opus_encoder_ctl(enc,OPUS_GET_APPLICATION(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_APPLICATION(i),OPUS_GET_APPLICATION(&i),-1,OPUS_AUTO, + OPUS_APPLICATION_AUDIO,OPUS_APPLICATION_RESTRICTED_LOWDELAY, + " OPUS_SET_APPLICATION ......................... OK.\n", + " OPUS_GET_APPLICATION ......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_BITRATE(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_SET_BITRATE(1073741832))!=OPUS_OK)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + if(opus_encoder_ctl(enc,OPUS_GET_BITRATE(&i))!=OPUS_OK)test_failed(); + if(i>700000||i<256000)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_BITRATE(i),OPUS_GET_BITRATE(&i),-12345,0, + 500,256000, + " OPUS_SET_BITRATE ............................. OK.\n", + " OPUS_GET_BITRATE ............................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_FORCE_CHANNELS(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_FORCE_CHANNELS(i),OPUS_GET_FORCE_CHANNELS(&i),-1,3, + 1,OPUS_AUTO, + " OPUS_SET_FORCE_CHANNELS ...................... OK.\n", + " OPUS_GET_FORCE_CHANNELS ...................... OK.\n") + + i=-2; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND+1; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_NARROWBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_WIDEBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_MEDIUMBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_BANDWIDTH ........................... OK.\n"); + /*We don't test if the bandwidth has actually changed. + because the change may be delayed until the encoder is advanced.*/ + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_BANDWIDTH(&i)); + if(err!=OPUS_OK || (i!=OPUS_BANDWIDTH_NARROWBAND&& + i!=OPUS_BANDWIDTH_MEDIUMBAND&&i!=OPUS_BANDWIDTH_WIDEBAND&& + i!=OPUS_BANDWIDTH_FULLBAND&&i!=OPUS_AUTO))test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(OPUS_AUTO))!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_BANDWIDTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + + i=-2; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND+1; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_NARROWBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_WIDEBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_MEDIUMBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_MAX_BANDWIDTH ....................... OK.\n"); + /*We don't test if the bandwidth has actually changed. + because the change may be delayed until the encoder is advanced.*/ + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_MAX_BANDWIDTH(&i)); + if(err!=OPUS_OK || (i!=OPUS_BANDWIDTH_NARROWBAND&& + i!=OPUS_BANDWIDTH_MEDIUMBAND&&i!=OPUS_BANDWIDTH_WIDEBAND&& + i!=OPUS_BANDWIDTH_FULLBAND))test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_MAX_BANDWIDTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_MAX_BANDWIDTH ....................... OK.\n"); + + err=opus_encoder_ctl(enc,OPUS_GET_DTX(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_DTX(i),OPUS_GET_DTX(&i),-1,2, + 1,0, + " OPUS_SET_DTX ................................. OK.\n", + " OPUS_GET_DTX ................................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_COMPLEXITY(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_COMPLEXITY(i),OPUS_GET_COMPLEXITY(&i),-1,11, + 0,10, + " OPUS_SET_COMPLEXITY .......................... OK.\n", + " OPUS_GET_COMPLEXITY .......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_INBAND_FEC(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_INBAND_FEC(i),OPUS_GET_INBAND_FEC(&i),-1,2, + 1,0, + " OPUS_SET_INBAND_FEC .......................... OK.\n", + " OPUS_GET_INBAND_FEC .......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_PACKET_LOSS_PERC(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_PACKET_LOSS_PERC(i),OPUS_GET_PACKET_LOSS_PERC(&i),-1,101, + 100,0, + " OPUS_SET_PACKET_LOSS_PERC .................... OK.\n", + " OPUS_GET_PACKET_LOSS_PERC .................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_VBR(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VBR(i),OPUS_GET_VBR(&i),-1,2, + 1,0, + " OPUS_SET_VBR ................................. OK.\n", + " OPUS_GET_VBR ................................. OK.\n") + +/* err=opus_encoder_ctl(enc,OPUS_GET_VOICE_RATIO(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VOICE_RATIO(i),OPUS_GET_VOICE_RATIO(&i),-2,101, + 0,50, + " OPUS_SET_VOICE_RATIO ......................... OK.\n", + " OPUS_GET_VOICE_RATIO ......................... OK.\n")*/ + + err=opus_encoder_ctl(enc,OPUS_GET_VBR_CONSTRAINT(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VBR_CONSTRAINT(i),OPUS_GET_VBR_CONSTRAINT(&i),-1,2, + 1,0, + " OPUS_SET_VBR_CONSTRAINT ...................... OK.\n", + " OPUS_GET_VBR_CONSTRAINT ...................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_SIGNAL(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_SIGNAL(i),OPUS_GET_SIGNAL(&i),-12345,0x7FFFFFFF, + OPUS_SIGNAL_MUSIC,OPUS_AUTO, + " OPUS_SET_SIGNAL .............................. OK.\n", + " OPUS_GET_SIGNAL .............................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_LSB_DEPTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_LSB_DEPTH(i),OPUS_GET_LSB_DEPTH(&i),7,25,16,24, + " OPUS_SET_LSB_DEPTH ........................... OK.\n", + " OPUS_GET_LSB_DEPTH ........................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_PREDICTION_DISABLED(&i)); + if(i!=0)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_PREDICTION_DISABLED(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_PREDICTION_DISABLED(i),OPUS_GET_PREDICTION_DISABLED(&i),-1,2,1,0, + " OPUS_SET_PREDICTION_DISABLED ................. OK.\n", + " OPUS_GET_PREDICTION_DISABLED ................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_EXPERT_FRAME_DURATION(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_2_5_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_5_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_10_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_40_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_60_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_80_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_100_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_120_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_EXPERT_FRAME_DURATION(i),OPUS_GET_EXPERT_FRAME_DURATION(&i),0,-1, + OPUS_FRAMESIZE_60_MS,OPUS_FRAMESIZE_ARG, + " OPUS_SET_EXPERT_FRAME_DURATION ............... OK.\n", + " OPUS_GET_EXPERT_FRAME_DURATION ............... OK.\n") + + /*OPUS_SET_FORCE_MODE is not tested here because it's not a public API, however the encoder tests use it*/ + + err=opus_encoder_ctl(enc,OPUS_GET_FINAL_RANGE(null_uint_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + + /*Reset the encoder*/ + if(opus_encoder_ctl(enc, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + + memset(sbuf,0,sizeof(short)*2*960); + VG_UNDEF(packet,sizeof(packet)); + i=opus_encode(enc, sbuf, 960, packet, sizeof(packet)); + if(i<1 || (i>(opus_int32)sizeof(packet)))test_failed(); + VG_CHECK(packet,i); + cfgs++; + fprintf(stdout," opus_encode() ................................ OK.\n"); +#ifndef DISABLE_FLOAT_API + memset(fbuf,0,sizeof(float)*2*960); + VG_UNDEF(packet,sizeof(packet)); + i=opus_encode_float(enc, fbuf, 960, packet, sizeof(packet)); + if(i<1 || (i>(opus_int32)sizeof(packet)))test_failed(); + VG_CHECK(packet,i); + cfgs++; + fprintf(stdout," opus_encode_float() .......................... OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_encoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encoder_init(0,48000,1,OPUS_APPLICATION_VOIP) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encode(0,sbuf,960,packet,sizeof(packet)) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encode_float(0,fbuf,960,packet,sizeof(packet))!=OPUS_INVALID_STATE)test_failed(); +#endif + opus_encoder_destroy(enc); + cfgs++; + fprintf(stdout," All encoder interface tests passed\n"); + fprintf(stdout," (%d API invocations)\n",cfgs); + return cfgs; +} + +#define max_out (1276*48+48*2+2) +int test_repacketizer_api(void) +{ + int ret,cfgs,i,j,k; + OpusRepacketizer *rp; + unsigned char *packet; + unsigned char *po; + cfgs=0; + fprintf(stdout,"\n Repacketizer tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + + packet=malloc(max_out); + if(packet==NULL)test_failed(); + memset(packet,0,max_out); + po=malloc(max_out+256); + if(po==NULL)test_failed(); + + i=opus_repacketizer_get_size(); + if(i<=0)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_get_size()=%d ............. OK.\n",i); + + rp=malloc(i); + rp=opus_repacketizer_init(rp); + if(rp==NULL)test_failed(); + cfgs++; + free(rp); + fprintf(stdout," opus_repacketizer_init ....................... OK.\n"); + + rp=opus_repacketizer_create(); + if(rp==NULL)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_create ..................... OK.\n"); + + if(opus_repacketizer_get_nb_frames(rp)!=0)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_get_nb_frames .............. OK.\n"); + + /*Length overflows*/ + VG_UNDEF(packet,4); + if(opus_repacketizer_cat(rp,packet,0)!=OPUS_INVALID_PACKET)test_failed(); /* Zero len */ + cfgs++; + packet[0]=1; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Odd payload code 1 */ + cfgs++; + packet[0]=2; + if(opus_repacketizer_cat(rp,packet,1)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow one */ + cfgs++; + packet[0]=3; + if(opus_repacketizer_cat(rp,packet,1)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 no count */ + cfgs++; + packet[0]=2; + packet[1]=255; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow two */ + cfgs++; + packet[0]=2; + packet[1]=250; + if(opus_repacketizer_cat(rp,packet,251)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow three */ + cfgs++; + packet[0]=3; + packet[1]=0; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 m=0 */ + cfgs++; + packet[1]=49; + if(opus_repacketizer_cat(rp,packet,100)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 m=49 */ + cfgs++; + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]=1<<2; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_INVALID_PACKET)test_failed(); /* Change in TOC */ + cfgs++; + + /* Code 0,1,3 CBR -> Code 0,1,3 CBR */ + opus_repacketizer_init(rp); + for(j=0;j<32;j++) + { + /* TOC types, test half with stereo */ + int maxi; + packet[0]=((j<<1)+(j&1))<<2; + maxi=960/opus_packet_get_samples_per_frame(packet,8000); + for(i=1;i<=maxi;i++) + { + /* Number of CBR frames in the input packets */ + int maxp; + packet[0]=((j<<1)+(j&1))<<2; + if(i>1)packet[0]+=i==2?1:3; + packet[1]=i>2?i:0; + maxp=960/(i*opus_packet_get_samples_per_frame(packet,8000)); + for(k=0;k<=(1275+75);k+=3) + { + /*Payload size*/ + opus_int32 cnt,rcnt; + if(k%i!=0)continue; /* Only testing CBR here, payload must be a multiple of the count */ + for(cnt=0;cnt0) + { + ret=opus_repacketizer_cat(rp,packet,k+(i>2?2:1)); + if((cnt<=maxp&&k<=(1275*i))?ret!=OPUS_OK:ret!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + } + rcnt=k<=(1275*i)?(cnt0) + { + int len; + len=k*rcnt+((rcnt*i)>2?2:1); + if(ret!=len)test_failed(); + if((rcnt*i)<2&&(po[0]&3)!=0)test_failed(); /* Code 0 */ + if((rcnt*i)==2&&(po[0]&3)!=1)test_failed(); /* Code 1 */ + if((rcnt*i)>2&&(((po[0]&3)!=3)||(po[1]!=rcnt*i)))test_failed(); /* Code 3 CBR */ + cfgs++; + if(opus_repacketizer_out(rp,po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_pad(po,len,len+1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,len+1,len+256)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len+256)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len,1)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len,len+1,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len+1,len+256,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len+256,1)!=len)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len-1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(len>1) + { + if(opus_repacketizer_out(rp,po,1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + if(opus_repacketizer_out(rp,po,0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } else if (ret!=OPUS_BAD_ARG)test_failed(); /* M must not be 0 */ + } + opus_repacketizer_init(rp); + } + } + } + + /*Change in input count code, CBR out*/ + opus_repacketizer_init(rp); + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,5)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]+=1; + if(opus_repacketizer_cat(rp,packet,9)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(4+8+2))||((po[0]&3)!=3)||((po[1]&63)!=3)||((po[1]>>7)!=0))test_failed(); + cfgs++; + i=opus_repacketizer_out_range(rp,0,1,po,max_out); + if(i!=5||(po[0]&3)!=0)test_failed(); + cfgs++; + i=opus_repacketizer_out_range(rp,1,2,po,max_out); + if(i!=5||(po[0]&3)!=0)test_failed(); + cfgs++; + + /*Change in input count code, VBR out*/ + opus_repacketizer_init(rp); + packet[0]=1; + if(opus_repacketizer_cat(rp,packet,9)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+8+2+2))||((po[0]&3)!=3)||((po[1]&63)!=3)||((po[1]>>7)!=1))test_failed(); + cfgs++; + + /*VBR in, VBR out*/ + opus_repacketizer_init(rp); + packet[0]=2; + packet[1]=4; + if(opus_repacketizer_cat(rp,packet,8)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_repacketizer_cat(rp,packet,8)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+1+1+1+4+2+4+2))||((po[0]&3)!=3)||((po[1]&63)!=4)||((po[1]>>7)!=1))test_failed(); + cfgs++; + + /*VBR in, CBR out*/ + opus_repacketizer_init(rp); + packet[0]=2; + packet[1]=4; + if(opus_repacketizer_cat(rp,packet,10)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_repacketizer_cat(rp,packet,10)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+4+4+4+4))||((po[0]&3)!=3)||((po[1]&63)!=4)||((po[1]>>7)!=0))test_failed(); + cfgs++; + + /*Count 0 in, VBR out*/ + for(j=0;j<32;j++) + { + /* TOC types, test half with stereo */ + int maxi,sum,rcnt; + packet[0]=((j<<1)+(j&1))<<2; + maxi=960/opus_packet_get_samples_per_frame(packet,8000); + sum=0; + rcnt=0; + opus_repacketizer_init(rp); + for(i=1;i<=maxi+2;i++) + { + int len; + ret=opus_repacketizer_cat(rp,packet,i); + if(rcnt2&&(po[1]&63)!=rcnt)test_failed(); + if(rcnt==2&&(po[0]&3)!=2)test_failed(); + if(rcnt==1&&(po[0]&3)!=0)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_pad(po,len,len+1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,len+1,len+256)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len+256)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len,1)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len,len+1,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len+1,len+256,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len+256,1)!=len)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len-1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(len>1) + { + if(opus_repacketizer_out(rp,po,1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + if(opus_repacketizer_out(rp,po,0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + } + + po[0]='O'; + po[1]='p'; + if(opus_packet_pad(po,4,4)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,4,4,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,4,5)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,4,5,1)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_packet_pad(po,0,5)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,0,5,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_packet_unpad(po,0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,0,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_packet_unpad(po,4)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,4,1)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + po[0]=0; + po[1]=0; + po[2]=0; + if(opus_packet_pad(po,5,4)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,5,4,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + fprintf(stdout," opus_repacketizer_cat ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_out ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_out_range .................. OK.\n"); + fprintf(stdout," opus_packet_pad .............................. OK.\n"); + fprintf(stdout," opus_packet_unpad ............................ OK.\n"); + fprintf(stdout," opus_multistream_packet_pad .................. OK.\n"); + fprintf(stdout," opus_multistream_packet_unpad ................ OK.\n"); + + opus_repacketizer_destroy(rp); + cfgs++; + free(packet); + free(po); + fprintf(stdout," All repacketizer tests passed\n"); + fprintf(stdout," (%7d API invocations)\n",cfgs); + + return cfgs; +} + +#ifdef MALLOC_FAIL +/* GLIBC 2.14 declares __malloc_hook as deprecated, generating a warning + * under GCC. However, this is the cleanest way to test malloc failure + * handling in our codebase, and the lack of thread safety isn't an + * issue here. We therefore disable the warning for this function. + */ +#if OPUS_GNUC_PREREQ(4,6) +/* Save the current warning settings */ +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +typedef void *(*mhook)(size_t __size, __const void *); +#endif + +int test_malloc_fail(void) +{ +#ifdef MALLOC_FAIL + OpusDecoder *dec; + OpusEncoder *enc; + OpusRepacketizer *rp; + unsigned char mapping[256] = {0,1}; + OpusMSDecoder *msdec; + OpusMSEncoder *msenc; + int rate,c,app,cfgs,err,useerr; + int *ep; + mhook orig_malloc; + cfgs=0; +#endif + fprintf(stdout,"\n malloc() failure tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); +#ifdef MALLOC_FAIL + orig_malloc=__malloc_hook; + __malloc_hook=malloc_hook; + ep=(int *)opus_alloc(sizeof(int)); + if(ep!=NULL) + { + if(ep)free(ep); + __malloc_hook=orig_malloc; +#endif + fprintf(stdout," opus_decoder_create() ................... SKIPPED.\n"); + fprintf(stdout," opus_encoder_create() ................... SKIPPED.\n"); + fprintf(stdout," opus_repacketizer_create() .............. SKIPPED.\n"); + fprintf(stdout," opus_multistream_decoder_create() ....... SKIPPED.\n"); + fprintf(stdout," opus_multistream_encoder_create() ....... SKIPPED.\n"); + fprintf(stdout,"(Test only supported with GLIBC and without valgrind)\n"); + return 0; +#ifdef MALLOC_FAIL + } + for(useerr=0;useerr<2;useerr++) + { + ep=useerr?&err:0; + for(rate=0;rate<5;rate++) + { + for(c=1;c<3;c++) + { + err=1; + if(useerr) + { + VG_UNDEF(&err,sizeof(err)); + } + dec=opus_decoder_create(opus_rates[rate], c, ep); + if(dec!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + msdec=opus_multistream_decoder_create(opus_rates[rate], c, 1, c-1, mapping, ep); + if(msdec!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + for(app=0;app<3;app++) + { + if(useerr) + { + VG_UNDEF(&err,sizeof(err)); + } + enc=opus_encoder_create(opus_rates[rate], c, opus_apps[app],ep); + if(enc!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + msenc=opus_multistream_encoder_create(opus_rates[rate], c, 1, c-1, mapping, opus_apps[app],ep); + if(msenc!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + } + } + } + } + rp=opus_repacketizer_create(); + if(rp!=NULL) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + __malloc_hook=orig_malloc; + fprintf(stdout," opus_decoder_create() ........................ OK.\n"); + fprintf(stdout," opus_encoder_create() ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_create() ................... OK.\n"); + fprintf(stdout," opus_multistream_decoder_create() ............ OK.\n"); + fprintf(stdout," opus_multistream_encoder_create() ............ OK.\n"); + fprintf(stdout," All malloc failure tests passed\n"); + fprintf(stdout," (%2d API invocations)\n",cfgs); + return cfgs; +#endif +} + +#ifdef MALLOC_FAIL +#if __GNUC_PREREQ(4,6) +#pragma GCC diagnostic pop /* restore -Wdeprecated-declarations */ +#endif +#endif + +int main(int _argc, char **_argv) +{ + opus_int32 total; + const char * oversion; + if(_argc>1) + { + fprintf(stderr,"Usage: %s\n",_argv[0]); + return 1; + } + iseed=0; + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing the %s API deterministically\n", oversion); + if(opus_strerror(-32768)==NULL)test_failed(); + if(opus_strerror(32767)==NULL)test_failed(); + if(strlen(opus_strerror(0))<1)test_failed(); + total=4; + + total+=test_dec_api(); + total+=test_msdec_api(); + total+=test_parse(); + total+=test_enc_api(); + total+=test_repacketizer_api(); + total+=test_malloc_fail(); + + fprintf(stderr,"\nAll API tests passed.\nThe libopus API was invoked %d times.\n",total); + + return 0; +} diff --git a/native/codec/libraries/opus/tests/test_opus_common.h b/native/codec/libraries/opus/tests/test_opus_common.h new file mode 100644 index 0000000..235cf1c --- /dev/null +++ b/native/codec/libraries/opus/tests/test_opus_common.h @@ -0,0 +1,82 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +static OPUS_INLINE void deb2_impl(unsigned char *_t,unsigned char **_p,int _k,int _x,int _y) +{ + int i; + if(_x>2){ + if(_y<3)for(i=0;i<_y;i++)*(--*_p)=_t[i+1]; + }else{ + _t[_x]=_t[_x-_y]; + deb2_impl(_t,_p,_k,_x+1,_y); + for(i=_t[_x-_y]+1;i<_k;i++){ + _t[_x]=i; + deb2_impl(_t,_p,_k,_x+1,_x); + } + } +} + +/*Generates a De Bruijn sequence (k,2) with length k^2*/ +static OPUS_INLINE void debruijn2(int _k, unsigned char *_res) +{ + unsigned char *p; + unsigned char *t; + t=malloc(sizeof(unsigned char)*_k*2); + memset(t,0,sizeof(unsigned char)*_k*2); + p=&_res[_k*_k]; + deb2_impl(t,&p,_k,1,1); + free(t); +} + +/*MWC RNG of George Marsaglia*/ +static opus_uint32 Rz, Rw; +static OPUS_INLINE opus_uint32 fast_rand(void) +{ + Rz=36969*(Rz&65535)+(Rz>>16); + Rw=18000*(Rw&65535)+(Rw>>16); + return (Rz<<16)+Rw; +} +static opus_uint32 iseed; + +#ifdef __GNUC__ +__attribute__((noreturn)) +#elif defined(_MSC_VER) +__declspec(noreturn) +#endif +static OPUS_INLINE void _test_failed(const char *file, int line) +{ + fprintf(stderr,"\n ***************************************************\n"); + fprintf(stderr," *** A fatal error was detected. ***\n"); + fprintf(stderr," ***************************************************\n"); + fprintf(stderr,"Please report this failure and include\n"); + fprintf(stderr,"'make check SEED=%u fails %s at line %d for %s'\n",iseed,file,line,opus_get_version_string()); + fprintf(stderr,"and any relevant details about your system.\n\n"); + abort(); +} +#define test_failed() _test_failed(__FILE__, __LINE__); + +void regression_test(void); diff --git a/native/codec/libraries/opus/tests/test_opus_decode.c b/native/codec/libraries/opus/tests/test_opus_decode.c new file mode 100644 index 0000000..5197fa1 --- /dev/null +++ b/native/codec/libraries/opus/tests/test_opus_decode.c @@ -0,0 +1,463 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__) +#include +#else +#include +#define getpid _getpid +#endif +#include "opus.h" +#include "test_opus_common.h" + +#define MAX_PACKET (1500) +#define MAX_FRAME_SAMP (5760) + +int test_decoder_code0(int no_fuzz) +{ + static const opus_int32 fsv[5]={48000,24000,16000,12000,8000}; + int err,skip,plen; + int out_samples,fec; + int t; + opus_int32 i; + OpusDecoder *dec[5*2]; + opus_int32 decsize; + OpusDecoder *decbak; + opus_uint32 dec_final_range1,dec_final_range2,dec_final_acc; + unsigned char *packet; + unsigned char modes[4096]; + short *outbuf_int; + short *outbuf; + + dec_final_range1=dec_final_range2=2; + + packet=malloc(sizeof(unsigned char)*MAX_PACKET); + if(packet==NULL)test_failed(); + + outbuf_int=malloc(sizeof(short)*(MAX_FRAME_SAMP+16)*2); + for(i=0;i<(MAX_FRAME_SAMP+16)*2;i++)outbuf_int[i]=32749; + outbuf=&outbuf_int[8*2]; + + fprintf(stdout," Starting %d decoders...\n",5*2); + for(t=0;t<5*2;t++) + { + int fs=fsv[t>>1]; + int c=(t&1)+1; + err=OPUS_INTERNAL_ERROR; + dec[t] = opus_decoder_create(fs, c, &err); + if(err!=OPUS_OK || dec[t]==NULL)test_failed(); + fprintf(stdout," opus_decoder_create(%5d,%d) OK. Copy ",fs,c); + { + OpusDecoder *dec2; + /*The opus state structures contain no pointers and can be freely copied*/ + dec2=(OpusDecoder *)malloc(opus_decoder_get_size(c)); + if(dec2==NULL)test_failed(); + memcpy(dec2,dec[t],opus_decoder_get_size(c)); + memset(dec[t],255,opus_decoder_get_size(c)); + opus_decoder_destroy(dec[t]); + printf("OK.\n"); + dec[t]=dec2; + } + } + + decsize=opus_decoder_get_size(1); + decbak=(OpusDecoder *)malloc(decsize); + if(decbak==NULL)test_failed(); + + for(t=0;t<5*2;t++) + { + int factor=48000/fsv[t>>1]; + for(fec=0;fec<2;fec++) + { + opus_int32 dur; + /*Test PLC on a fresh decoder*/ + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=120/factor)test_failed(); + + /*Test on a size which isn't a multiple of 2.5ms*/ + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor+2, fec); + if(out_samples!=OPUS_BAD_ARG)test_failed(); + + /*Test null pointer input*/ + out_samples = opus_decode(dec[t], 0, -1, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, 1, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, 10, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, fast_rand(), outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=120/factor)test_failed(); + + /*Zero lengths*/ + out_samples = opus_decode(dec[t], packet, 0, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + + /*Zero buffer*/ + outbuf[0]=32749; + out_samples = opus_decode(dec[t], packet, 0, outbuf, 0, fec); + if(out_samples>0)test_failed(); +#if !defined(OPUS_BUILD) && (OPUS_GNUC_PREREQ(4, 6) || (defined(__clang_major__) && __clang_major__ >= 3)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" +#endif + out_samples = opus_decode(dec[t], packet, 0, 0, 0, fec); +#if !defined(OPUS_BUILD) && (OPUS_GNUC_PREREQ(4, 6) || (defined(__clang_major__) && __clang_major__ >= 3)) +#pragma GCC diagnostic pop +#endif + if(out_samples>0)test_failed(); + if(outbuf[0]!=32749)test_failed(); + + /*Invalid lengths*/ + out_samples = opus_decode(dec[t], packet, -1, outbuf, MAX_FRAME_SAMP, fec); + if(out_samples>=0)test_failed(); + out_samples = opus_decode(dec[t], packet, INT_MIN, outbuf, MAX_FRAME_SAMP, fec); + if(out_samples>=0)test_failed(); + out_samples = opus_decode(dec[t], packet, -1, outbuf, -1, fec); + if(out_samples>=0)test_failed(); + + /*Crazy FEC values*/ + out_samples = opus_decode(dec[t], packet, 1, outbuf, MAX_FRAME_SAMP, fec?-1:2); + if(out_samples>=0)test_failed(); + + /*Reset the decoder*/ + if(opus_decoder_ctl(dec[t], OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + } + fprintf(stdout," dec[all] initial frame PLC OK.\n"); + + /*Count code 0 tests*/ + for(i=0;i<64;i++) + { + opus_int32 dur; + int j,expected[5*2]; + packet[0]=i<<2; + packet[1]=255; + packet[2]=255; + err=opus_packet_get_nb_channels(packet); + if(err!=(i&1)+1)test_failed(); + + for(t=0;t<5*2;t++){ + expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1); + if(expected[t]>2880)test_failed(); + } + + for(j=0;j<256;j++) + { + packet[1]=j; + for(t=0;t<5*2;t++) + { + out_samples = opus_decode(dec[t], packet, 3, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=expected[t])test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + if(t==0)dec_final_range2=dec_final_range1; + else if(dec_final_range1!=dec_final_range2)test_failed(); + } + } + + for(t=0;t<5*2;t++){ + int factor=48000/fsv[t>>1]; + /* The PLC is run for 6 frames in order to get better PLC coverage. */ + for(j=0;j<6;j++) + { + out_samples = opus_decode(dec[t], 0, 0, outbuf, expected[t], 0); + if(out_samples!=expected[t])test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + } + /* Run the PLC once at 2.5ms, as a simulation of someone trying to + do small drift corrections. */ + if(expected[t]!=120/factor) + { + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, 0); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + } + out_samples = opus_decode(dec[t], packet, 2, outbuf, expected[t]-1, 0); + if(out_samples>0)test_failed(); + } + } + fprintf(stdout," dec[all] all 2-byte prefix for length 3 and PLC, all modes (64) OK.\n"); + + if(no_fuzz) + { + fprintf(stdout," Skipping many tests which fuzz the decoder as requested.\n"); + free(decbak); + for(t=0;t<5*2;t++)opus_decoder_destroy(dec[t]); + printf(" Decoders stopped.\n"); + + err=0; + for(i=0;i<8*2;i++)err|=outbuf_int[i]!=32749; + for(i=MAX_FRAME_SAMP*2;i<(MAX_FRAME_SAMP+8)*2;i++)err|=outbuf[i]!=32749; + if(err)test_failed(); + + free(outbuf_int); + free(packet); + return 0; + } + + { + /*We only test a subset of the modes here simply because the longer + durations end up taking a long time.*/ + static const int cmodes[4]={16,20,24,28}; + static const opus_uint32 cres[4]={116290185,2172123586u,2172123586u,2172123586u}; + static const opus_uint32 lres[3]={3285687739u,1481572662,694350475}; + static const int lmodes[3]={0,4,8}; + int mode=fast_rand()%4; + + packet[0]=cmodes[mode]<<3; + dec_final_acc=0; + t=fast_rand()%10; + + for(i=0;i<65536;i++) + { + int factor=48000/fsv[t>>1]; + packet[1]=i>>8; + packet[2]=i&255; + packet[3]=255; + out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=120/factor)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + dec_final_acc+=dec_final_range1; + } + if(dec_final_acc!=cres[mode])test_failed(); + fprintf(stdout," dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,cmodes[mode]); + + mode=fast_rand()%3; + packet[0]=lmodes[mode]<<3; + dec_final_acc=0; + t=fast_rand()%10; + for(i=0;i<65536;i++) + { + int factor=48000/fsv[t>>1]; + packet[1]=i>>8; + packet[2]=i&255; + packet[3]=255; + out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=480/factor)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + dec_final_acc+=dec_final_range1; + } + if(dec_final_acc!=lres[mode])test_failed(); + fprintf(stdout," dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,lmodes[mode]); + } + + skip=fast_rand()%7; + for(i=0;i<64;i++) + { + int j,expected[5*2]; + packet[0]=i<<2; + for(t=0;t<5*2;t++)expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1); + for(j=2+skip;j<1275;j+=4) + { + int jj; + for(jj=0;jj1.f)test_failed(); + if(x[j]<-1.f)test_failed(); + } + } + for(i=1;i<9;i++) + { + for (j=0;j<1024;j++) + { + x[j]=(j&255)*(1/32.f)-4.f; + } + opus_pcm_soft_clip(x,1024/i,i,s); + for (j=0;j<(1024/i)*i;j++) + { + if(x[j]>1.f)test_failed(); + if(x[j]<-1.f)test_failed(); + } + } + opus_pcm_soft_clip(x,0,1,s); + opus_pcm_soft_clip(x,1,0,s); + opus_pcm_soft_clip(x,1,1,0); + opus_pcm_soft_clip(x,1,-1,s); + opus_pcm_soft_clip(x,-1,1,s); + opus_pcm_soft_clip(0,1,1,s); + printf("OK.\n"); +} +#endif + +int main(int _argc, char **_argv) +{ + const char * oversion; + const char * env_seed; + int env_used; + + if(_argc>2) + { + fprintf(stderr,"Usage: %s []\n",_argv[0]); + return 1; + } + + env_used=0; + env_seed=getenv("SEED"); + if(_argc>1)iseed=atoi(_argv[1]); + else if(env_seed) + { + iseed=atoi(env_seed); + env_used=1; + } + else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16); + Rw=Rz=iseed; + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing %s decoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535); + if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed); + + /*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data + into the decoders. This is helpful because garbage data + may cause the decoders to clip, which angers CLANG IOC.*/ + test_decoder_code0(getenv("TEST_OPUS_NOFUZZ")!=NULL); +#ifndef DISABLE_FLOAT_API + test_soft_clip(); +#endif + + return 0; +} diff --git a/native/codec/libraries/opus/tests/test_opus_encode.c b/native/codec/libraries/opus/tests/test_opus_encode.c new file mode 100644 index 0000000..00795a1 --- /dev/null +++ b/native/codec/libraries/opus/tests/test_opus_encode.c @@ -0,0 +1,703 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__) +#include +#else +#include +#define getpid _getpid +#endif +#include "opus_multistream.h" +#include "opus.h" +#include "../src/opus_private.h" +#include "test_opus_common.h" + +#define MAX_PACKET (1500) +#define SAMPLES (48000*30) +#define SSAMPLES (SAMPLES/3) +#define MAX_FRAME_SAMP (5760) +#define PI (3.141592653589793238462643f) +#define RAND_SAMPLE(a) (a[fast_rand() % sizeof(a)/sizeof(a[0])]) + +void generate_music(short *buf, opus_int32 len) +{ + opus_int32 a1,b1,a2,b2; + opus_int32 c1,c2,d1,d2; + opus_int32 i,j; + a1=b1=a2=b2=0; + c1=c2=d1=d2=0; + j=0; + /*60ms silence*/ + for(i=0;i<2880;i++)buf[i*2]=buf[i*2+1]=0; + for(i=2880;i>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15; + r=fast_rand();v1+=r&65535;v1-=r>>16; + r=fast_rand();v2+=r&65535;v2-=r>>16; + b1=v1-a1+((b1*61+32)>>6);a1=v1; + b2=v2-a2+((b2*61+32)>>6);a2=v2; + c1=(30*(c1+b1+d1)+32)>>6;d1=b1; + c2=(30*(c2+b2+d2)+32)>>6;d2=b2; + v1=(c1+128)>>8; + v2=(c2+128)>>8; + buf[i*2]=v1>32767?32767:(v1<-32768?-32768:v1); + buf[i*2+1]=v2>32767?32767:(v2<-32768?-32768:v2); + if(i%6==0)j++; + } +} + +#if 0 +static int save_ctr = 0; +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static OPUS_INLINE void save_packet(unsigned char* p, int len, opus_uint32 rng) +{ + FILE *fout; + unsigned char int_field[4]; + char name[256]; + snprintf(name,255,"test_opus_encode.%llu.%d.bit",(unsigned long long)iseed,save_ctr); + fprintf(stdout,"writing %d byte packet to %s\n",len,name); + fout=fopen(name, "wb+"); + if(fout==NULL)test_failed(); + int_to_char(len, int_field); + fwrite(int_field, 1, 4, fout); + int_to_char(rng, int_field); + fwrite(int_field, 1, 4, fout); + fwrite(p, 1, len, fout); + fclose(fout); + save_ctr++; +} +#endif + +int get_frame_size_enum(int frame_size, int sampling_rate) +{ + int frame_size_enum; + + if(frame_size==sampling_rate/400) + frame_size_enum = OPUS_FRAMESIZE_2_5_MS; + else if(frame_size==sampling_rate/200) + frame_size_enum = OPUS_FRAMESIZE_5_MS; + else if(frame_size==sampling_rate/100) + frame_size_enum = OPUS_FRAMESIZE_10_MS; + else if(frame_size==sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_20_MS; + else if(frame_size==sampling_rate/25) + frame_size_enum = OPUS_FRAMESIZE_40_MS; + else if(frame_size==3*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_60_MS; + else if(frame_size==4*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_80_MS; + else if(frame_size==5*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_100_MS; + else if(frame_size==6*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_120_MS; + else + test_failed(); + + return frame_size_enum; +} + +int test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *dec) +{ + int samp_count = 0; + opus_int16 *inbuf; + unsigned char packet[MAX_PACKET+257]; + int len; + opus_int16 *outbuf; + int out_samples; + int ret = 0; + + /* Generate input data */ + inbuf = (opus_int16*)malloc(sizeof(*inbuf)*SSAMPLES); + generate_music(inbuf, SSAMPLES/2); + + /* Allocate memory for output data */ + outbuf = (opus_int16*)malloc(sizeof(*outbuf)*MAX_FRAME_SAMP*3); + + /* Encode data, then decode for sanity check */ + do { + len = opus_encode(enc, &inbuf[samp_count*channels], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET) { + fprintf(stderr,"opus_encode() returned %d\n",len); + ret = -1; + break; + } + + out_samples = opus_decode(dec, packet, len, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size) { + fprintf(stderr,"opus_decode() returned %d\n",out_samples); + ret = -1; + break; + } + + samp_count += frame_size; + } while (samp_count < ((SSAMPLES/2)-MAX_FRAME_SAMP)); + + /* Clean up */ + free(inbuf); + free(outbuf); + return ret; +} + +void fuzz_encoder_settings(const int num_encoders, const int num_setting_changes) +{ + OpusEncoder *enc; + OpusDecoder *dec; + int i,j,err; + + /* Parameters to fuzz. Some values are duplicated to increase their probability of being tested. */ + int sampling_rates[5] = {8000, 12000, 16000, 24000, 48000}; + int channels[2] = {1, 2}; + int applications[3] = {OPUS_APPLICATION_AUDIO, OPUS_APPLICATION_VOIP, OPUS_APPLICATION_RESTRICTED_LOWDELAY}; + int bitrates[11] = {6000, 12000, 16000, 24000, 32000, 48000, 64000, 96000, 510000, OPUS_AUTO, OPUS_BITRATE_MAX}; + int force_channels[4] = {OPUS_AUTO, OPUS_AUTO, 1, 2}; + int use_vbr[3] = {0, 1, 1}; + int vbr_constraints[3] = {0, 1, 1}; + int complexities[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int max_bandwidths[6] = {OPUS_BANDWIDTH_NARROWBAND, OPUS_BANDWIDTH_MEDIUMBAND, + OPUS_BANDWIDTH_WIDEBAND, OPUS_BANDWIDTH_SUPERWIDEBAND, + OPUS_BANDWIDTH_FULLBAND, OPUS_BANDWIDTH_FULLBAND}; + int signals[4] = {OPUS_AUTO, OPUS_AUTO, OPUS_SIGNAL_VOICE, OPUS_SIGNAL_MUSIC}; + int inband_fecs[3] = {0, 0, 1}; + int packet_loss_perc[4] = {0, 1, 2, 5}; + int lsb_depths[2] = {8, 24}; + int prediction_disabled[3] = {0, 0, 1}; + int use_dtx[2] = {0, 1}; + int frame_sizes_ms_x2[9] = {5, 10, 20, 40, 80, 120, 160, 200, 240}; /* x2 to avoid 2.5 ms */ + + for (i=0; i=64000?2:1)))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed(); + bw=modes[j]==0?OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%3): + modes[j]==1?OPUS_BANDWIDTH_SUPERWIDEBAND+(fast_rand()&1): + OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%5); + if(modes[j]==2&&bw==OPUS_BANDWIDTH_MEDIUMBAND)bw+=3; + if(opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bw))!=OPUS_OK)test_failed(); + len = opus_encode(enc, &inbuf[i<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + if(opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + if((fast_rand()&3)==0) + { + if(opus_packet_pad(packet,len,len+1)!=OPUS_OK)test_failed(); + len++; + } + if((fast_rand()&7)==0) + { + if(opus_packet_pad(packet,len,len+256)!=OPUS_OK)test_failed(); + len+=256; + } + if((fast_rand()&3)==0) + { + len=opus_packet_unpad(packet,len); + if(len<1)test_failed(); + } + out_samples = opus_decode(dec, packet, len, &outbuf[i<<1], MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size)test_failed(); + if(opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed(); + if(enc_final_range!=dec_final_range)test_failed(); + /*LBRR decode*/ + out_samples = opus_decode(dec_err[0], packet, len, out2buf, frame_size, (fast_rand()&3)!=0); + if(out_samples!=frame_size)test_failed(); + out_samples = opus_decode(dec_err[1], packet, (fast_rand()&3)==0?0:len, out2buf, MAX_FRAME_SAMP, (fast_rand()&7)!=0); + if(out_samples<120)test_failed(); + i+=frame_size; + count++; + }while(i<(SSAMPLES-MAX_FRAME_SAMP)); + fprintf(stdout," Mode %s FB encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate); + } + } + + if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(OPUS_AUTO))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_DTX(0))!=OPUS_OK)test_failed(); + + for(rc=0;rc<3;rc++) + { + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR(rc<2))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed(); + for(j=0;j<16;j++) + { + int rate; + int modes[16]={0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2}; + int rates[16]={4000,12000,32000,8000,16000,32000,48000,88000,4000,12000,32000,8000,16000,32000,48000,88000}; + int frame[16]={160*1,160,80,160,160,80,40,20,160*1,160,80,160,160,80,40,20}; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0&&j==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_FORCE_MODE(MODE_SILK_ONLY+modes[j]))!=OPUS_OK)test_failed(); + rate=rates[j]+fast_rand()%rates[j]; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_DTX(fast_rand()&1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_BITRATE(rate))!=OPUS_OK)test_failed(); + count=i=0; + do { + int len,out_samples,frame_size,loss; + opus_int32 pred; + if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_PREDICTION_DISABLED(&pred))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PREDICTION_DISABLED((int)(fast_rand()&15)<(pred?11:4)))!=OPUS_OK)test_failed(); + frame_size=frame[j]; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed(); + if((fast_rand()&255)==0) + { + if(opus_multistream_encoder_ctl(MSenc, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if(opus_multistream_decoder_ctl(MSdec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if((fast_rand()&3)!=0) + { + if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + } + if((fast_rand()&255)==0) + { + if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + len = opus_multistream_encode(MSenc, &inbuf[i<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + if((fast_rand()&3)==0) + { + if(opus_multistream_packet_pad(packet,len,len+1,2)!=OPUS_OK)test_failed(); + len++; + } + if((fast_rand()&7)==0) + { + if(opus_multistream_packet_pad(packet,len,len+256,2)!=OPUS_OK)test_failed(); + len+=256; + } + if((fast_rand()&3)==0) + { + len=opus_multistream_packet_unpad(packet,len,2); + if(len<1)test_failed(); + } + out_samples = opus_multistream_decode(MSdec, packet, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size*6)test_failed(); + if(opus_multistream_decoder_ctl(MSdec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed(); + if(enc_final_range!=dec_final_range)test_failed(); + /*LBRR decode*/ + loss=(fast_rand()&63)==0; + out_samples = opus_multistream_decode(MSdec_err, packet, loss?0:len, out2buf, frame_size*6, (fast_rand()&3)!=0); + if(out_samples!=(frame_size*6))test_failed(); + i+=frame_size; + count++; + }while(i<(SSAMPLES/12-MAX_FRAME_SAMP)); + fprintf(stdout," Mode %s NB dual-mono MS encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate); + } + } + + bitrate_bps=512000; + fsize=fast_rand()%31; + fswitch=100; + + debruijn2(6,db62); + count=i=0; + do { + unsigned char toc; + const unsigned char *frames[48]; + short size[48]; + int payload_offset; + opus_uint32 dec_final_range2; + int jj,dec2; + int len,out_samples; + int frame_size=fsizes[db62[fsize]]; + opus_int32 offset=i%(SAMPLES-MAX_FRAME_SAMP); + + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + + len = opus_encode(enc, &inbuf[offset<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + count++; + + opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range)); + + out_samples = opus_decode(dec, packet, len, &outbuf[offset<<1], MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size)test_failed(); + + opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + + /* compare final range encoder rng values of encoder and decoder */ + if(dec_final_range!=enc_final_range)test_failed(); + + /* We fuzz the packet, but take care not to only corrupt the payload + Corrupted headers are tested elsewhere and we need to actually run + the decoders in order to compare them. */ + if(opus_packet_parse(packet,len,&toc,frames,size,&payload_offset)<=0)test_failed(); + if((fast_rand()&1023)==0)len=0; + for(j=(opus_int32)(frames[0]-packet);j0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); + if((len>0&&out_samples!=frame_size))test_failed(); /*FIXME use lastframe*/ + + opus_decoder_ctl(dec_err[0], OPUS_GET_FINAL_RANGE(&dec_final_range)); + + /*randomly select one of the decoders to compare with*/ + dec2=fast_rand()%9+1; + out_samples = opus_decode(dec_err[dec2], len>0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); /*FIXME, use factor, lastframe for loss*/ + + opus_decoder_ctl(dec_err[dec2], OPUS_GET_FINAL_RANGE(&dec_final_range2)); + if(len>0&&dec_final_range!=dec_final_range2)test_failed(); + + fswitch--; + if(fswitch<1) + { + int new_size; + fsize=(fsize+1)%36; + new_size=fsizes[db62[fsize]]; + if(new_size==960||new_size==480)fswitch=2880/new_size*(fast_rand()%19+1); + else fswitch=(fast_rand()%(2880/new_size))+1; + } + bitrate_bps=((fast_rand()%508000+4000)+bitrate_bps)>>1; + i+=frame_size; + }while(i] [-fuzz ]\n",_argv[0]); +} + +int main(int _argc, char **_argv) +{ + int args=1; + char * strtol_str=NULL; + const char * oversion; + const char * env_seed; + int env_used; + int num_encoders_to_fuzz=5; + int num_setting_changes=40; + + env_used=0; + env_seed=getenv("SEED"); + if(_argc>1) + iseed=strtol(_argv[1], &strtol_str, 10); /* the first input argument might be the seed */ + if(strtol_str!=NULL && strtol_str[0]=='\0') /* iseed is a valid number */ + args++; + else if(env_seed) { + iseed=atoi(env_seed); + env_used=1; + } + else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16); + Rw=Rz=iseed; + + while(args<_argc) + { + if(strcmp(_argv[args], "-fuzz")==0 && _argc==(args+3)) { + num_encoders_to_fuzz=strtol(_argv[args+1], &strtol_str, 10); + if(strtol_str[0]!='\0' || num_encoders_to_fuzz<=0) { + print_usage(_argv); + return EXIT_FAILURE; + } + num_setting_changes=strtol(_argv[args+2], &strtol_str, 10); + if(strtol_str[0]!='\0' || num_setting_changes<=0) { + print_usage(_argv); + return EXIT_FAILURE; + } + args+=3; + } + else { + print_usage(_argv); + return EXIT_FAILURE; + } + } + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing %s encoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535); + if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed); + + regression_test(); + + /*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data + into the decoders. This is helpful because garbage data + may cause the decoders to clip, which angers CLANG IOC.*/ + run_test1(getenv("TEST_OPUS_NOFUZZ")!=NULL); + + /* Fuzz encoder settings online */ + if(getenv("TEST_OPUS_NOFUZZ")==NULL) { + fprintf(stderr,"Running fuzz_encoder_settings with %d encoder(s) and %d setting change(s) each.\n", + num_encoders_to_fuzz, num_setting_changes); + fuzz_encoder_settings(num_encoders_to_fuzz, num_setting_changes); + } + + fprintf(stderr,"Tests completed successfully.\n"); + + return 0; +} diff --git a/native/codec/libraries/opus/tests/test_opus_padding.c b/native/codec/libraries/opus/tests/test_opus_padding.c new file mode 100644 index 0000000..c22e8f0 --- /dev/null +++ b/native/codec/libraries/opus/tests/test_opus_padding.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2012 Xiph.Org Foundation + Written by Jüri Aedla and Ralph Giles */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Check for overflow in reading the padding length. + * http://lists.xiph.org/pipermail/opus/2012-November/001834.html + */ + +#include +#include +#include +#include "opus.h" +#include "test_opus_common.h" + +#define PACKETSIZE 16909318 +#define CHANNELS 2 +#define FRAMESIZE 5760 + +int test_overflow(void) +{ + OpusDecoder *decoder; + int result; + int error; + + unsigned char *in = malloc(PACKETSIZE); + opus_int16 *out = malloc(FRAMESIZE*CHANNELS*sizeof(*out)); + + fprintf(stderr, " Checking for padding overflow... "); + if (!in || !out) { + fprintf(stderr, "FAIL (out of memory)\n"); + return -1; + } + in[0] = 0xff; + in[1] = 0x41; + memset(in + 2, 0xff, PACKETSIZE - 3); + in[PACKETSIZE-1] = 0x0b; + + decoder = opus_decoder_create(48000, CHANNELS, &error); + result = opus_decode(decoder, in, PACKETSIZE, out, FRAMESIZE, 0); + opus_decoder_destroy(decoder); + + free(in); + free(out); + + if (result != OPUS_INVALID_PACKET) { + fprintf(stderr, "FAIL!\n"); + test_failed(); + } + + fprintf(stderr, "OK.\n"); + + return 1; +} + +int main(void) +{ + const char *oversion; + int tests = 0;; + + iseed = 0; + oversion = opus_get_version_string(); + if (!oversion) test_failed(); + fprintf(stderr, "Testing %s padding.\n", oversion); + + tests += test_overflow(); + + fprintf(stderr, "All padding tests passed.\n"); + + return 0; +} diff --git a/native/codec/libraries/opus/tests/test_opus_projection.c b/native/codec/libraries/opus/tests/test_opus_projection.c new file mode 100644 index 0000000..5f0d672 --- /dev/null +++ b/native/codec/libraries/opus/tests/test_opus_projection.c @@ -0,0 +1,394 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include "float_cast.h" +#include "opus.h" +#include "test_opus_common.h" +#include "opus_projection.h" +#include "mathops.h" +#include "../src/mapping_matrix.h" +#include "mathops.h" + +#define BUFFER_SIZE 960 +#define MAX_DATA_BYTES 32768 +#define MAX_FRAME_SAMPLES 5760 +#define ERROR_TOLERANCE 1 + +#define SIMPLE_MATRIX_SIZE 12 +#define SIMPLE_MATRIX_FRAME_SIZE 10 +#define SIMPLE_MATRIX_INPUT_SIZE 30 +#define SIMPLE_MATRIX_OUTPUT_SIZE 40 + +int assert_is_equal( + const opus_val16 *a, const opus_int16 *b, int size, opus_int16 tolerance) +{ + int i; + for (i = 0; i < size; i++) + { +#ifdef FIXED_POINT + opus_int16 val = a[i]; +#else + opus_int16 val = FLOAT2INT16(a[i]); +#endif + if (abs(val - b[i]) > tolerance) + return 1; + } + return 0; +} + +int assert_is_equal_short( + const opus_int16 *a, const opus_int16 *b, int size, opus_int16 tolerance) +{ + int i; + for (i = 0; i < size; i++) + if (abs(a[i] - b[i]) > tolerance) + return 1; + return 0; +} + +void test_simple_matrix(void) +{ + const MappingMatrix simple_matrix_params = {4, 3, 0}; + const opus_int16 simple_matrix_data[SIMPLE_MATRIX_SIZE] = {0, 32767, 0, 0, 32767, 0, 0, 0, 0, 0, 0, 32767}; + const opus_int16 input_int16[SIMPLE_MATRIX_INPUT_SIZE] = { + 32767, 0, -32768, 29491, -3277, -29491, 26214, -6554, -26214, 22938, -9830, + -22938, 19661, -13107, -19661, 16384, -16384, -16384, 13107, -19661, -13107, + 9830, -22938, -9830, 6554, -26214, -6554, 3277, -29491, -3277}; + const opus_int16 expected_output_int16[SIMPLE_MATRIX_OUTPUT_SIZE] = { + 0, 32767, 0, -32768, -3277, 29491, 0, -29491, -6554, 26214, 0, -26214, + -9830, 22938, 0, -22938, -13107, 19661, 0, -19661, -16384, 16384, 0, -16384, + -19661, 13107, 0, -13107, -22938, 9830, 0, -9830, -26214, 6554, 0, -6554, + -29491, 3277, 0, -3277}; + + int i, ret; + opus_int32 simple_matrix_size; + opus_val16 *input_val16; + opus_val16 *output_val16; + opus_int16 *output_int16; + MappingMatrix *simple_matrix; + + /* Allocate input/output buffers. */ + input_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_INPUT_SIZE); + output_int16 = (opus_int16 *)opus_alloc(sizeof(opus_int16) * SIMPLE_MATRIX_OUTPUT_SIZE); + output_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_OUTPUT_SIZE); + + /* Initialize matrix */ + simple_matrix_size = mapping_matrix_get_size(simple_matrix_params.rows, + simple_matrix_params.cols); + if (!simple_matrix_size) + test_failed(); + + simple_matrix = (MappingMatrix *)opus_alloc(simple_matrix_size); + mapping_matrix_init(simple_matrix, simple_matrix_params.rows, + simple_matrix_params.cols, simple_matrix_params.gain, simple_matrix_data, + sizeof(simple_matrix_data)); + + /* Copy inputs. */ + for (i = 0; i < SIMPLE_MATRIX_INPUT_SIZE; i++) + { +#ifdef FIXED_POINT + input_val16[i] = input_int16[i]; +#else + input_val16[i] = (1/32768.f)*input_int16[i]; +#endif + } + + /* _in_short */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->rows; i++) + { + mapping_matrix_multiply_channel_in_short(simple_matrix, + input_int16, simple_matrix->cols, &output_val16[i], i, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + + /* _out_short */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_int16[i] = 0; + for (i = 0; i < simple_matrix->cols; i++) + { + mapping_matrix_multiply_channel_out_short(simple_matrix, + &input_val16[i], i, simple_matrix->cols, output_int16, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal_short(output_int16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + +#if !defined(DISABLE_FLOAT_API) && !defined(FIXED_POINT) + /* _in_float */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->rows; i++) + { + mapping_matrix_multiply_channel_in_float(simple_matrix, + input_val16, simple_matrix->cols, &output_val16[i], i, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + + /* _out_float */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->cols; i++) + { + mapping_matrix_multiply_channel_out_float(simple_matrix, + &input_val16[i], i, simple_matrix->cols, output_val16, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); +#endif + + opus_free(input_val16); + opus_free(output_int16); + opus_free(output_val16); + opus_free(simple_matrix); +} + +void test_creation_arguments(const int channels, const int mapping_family) +{ + int streams; + int coupled_streams; + int enc_error; + int dec_error; + int ret; + OpusProjectionEncoder *st_enc = NULL; + OpusProjectionDecoder *st_dec = NULL; + + const opus_int32 Fs = 48000; + const int application = OPUS_APPLICATION_AUDIO; + + int order_plus_one = (int)floor(sqrt((float)channels)); + int nondiegetic_channels = channels - order_plus_one * order_plus_one; + + int is_channels_valid = 0; + int is_projection_valid = 0; + + st_enc = opus_projection_ambisonics_encoder_create(Fs, channels, + mapping_family, &streams, &coupled_streams, application, &enc_error); + if (st_enc != NULL) + { + opus_int32 matrix_size; + unsigned char *matrix; + + ret = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size); + if (ret != OPUS_OK || !matrix_size) + test_failed(); + + matrix = (unsigned char *)opus_alloc(matrix_size); + ret = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size); + + opus_projection_encoder_destroy(st_enc); + + st_dec = opus_projection_decoder_create(Fs, channels, streams, + coupled_streams, matrix, matrix_size, &dec_error); + if (st_dec != NULL) + { + opus_projection_decoder_destroy(st_dec); + } + opus_free(matrix); + } + + is_channels_valid = (order_plus_one >= 2 && order_plus_one <= 4) && + (nondiegetic_channels == 0 || nondiegetic_channels == 2); + is_projection_valid = (enc_error == OPUS_OK && dec_error == OPUS_OK); + if (is_channels_valid ^ is_projection_valid) + { + fprintf(stderr, "Channels: %d, Family: %d\n", channels, mapping_family); + fprintf(stderr, "Order+1: %d, Non-diegetic Channels: %d\n", + order_plus_one, nondiegetic_channels); + fprintf(stderr, "Streams: %d, Coupled Streams: %d\n", + streams, coupled_streams); + test_failed(); + } +} + +void generate_music(short *buf, opus_int32 len, opus_int32 channels) +{ + opus_int32 i,j,k; + opus_int32 *a,*b,*c,*d; + a = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + b = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + c = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + d = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + memset(a, 0, sizeof(opus_int32) * channels); + memset(b, 0, sizeof(opus_int32) * channels); + memset(c, 0, sizeof(opus_int32) * channels); + memset(d, 0, sizeof(opus_int32) * channels); + j=0; + + for(i=0;i>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15; + r=fast_rand();v+=r&65535;v-=r>>16; + b[k]=v-a[k]+((b[k]*61+32)>>6);a[k]=v; + c[k]=(30*(c[k]+b[k]+d[k])+32)>>6;d[k]=b[k]; + v=(c[k]+128)>>8; + buf[i*channels+k]=v>32767?32767:(v<-32768?-32768:v); + if(i%6==0)j++; + } + } + + free(a); + free(b); + free(c); + free(d); +} + +void test_encode_decode(opus_int32 bitrate, opus_int32 channels, + const int mapping_family) +{ + const opus_int32 Fs = 48000; + const int application = OPUS_APPLICATION_AUDIO; + + OpusProjectionEncoder *st_enc; + OpusProjectionDecoder *st_dec; + int streams; + int coupled; + int error; + short *buffer_in; + short *buffer_out; + unsigned char data[MAX_DATA_BYTES] = { 0 }; + int len; + int out_samples; + opus_int32 matrix_size = 0; + unsigned char *matrix = NULL; + + buffer_in = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels); + buffer_out = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels); + + st_enc = opus_projection_ambisonics_encoder_create(Fs, channels, + mapping_family, &streams, &coupled, application, &error); + if (error != OPUS_OK) { + fprintf(stderr, + "Couldn\'t create encoder with %d channels and mapping family %d.\n", + channels, mapping_family); + free(buffer_in); + free(buffer_out); + test_failed(); + } + + error = opus_projection_encoder_ctl(st_enc, + OPUS_SET_BITRATE(bitrate * 1000 * (streams + coupled))); + if (error != OPUS_OK) + { + goto bad_cleanup; + } + + error = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size); + if (error != OPUS_OK || !matrix_size) + { + goto bad_cleanup; + } + + matrix = (unsigned char *)opus_alloc(matrix_size); + error = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size); + + st_dec = opus_projection_decoder_create(Fs, channels, streams, coupled, + matrix, matrix_size, &error); + opus_free(matrix); + + if (error != OPUS_OK) { + fprintf(stderr, + "Couldn\'t create decoder with %d channels, %d streams " + "and %d coupled streams.\n", channels, streams, coupled); + goto bad_cleanup; + } + + generate_music(buffer_in, BUFFER_SIZE, channels); + + len = opus_projection_encode( + st_enc, buffer_in, BUFFER_SIZE, data, MAX_DATA_BYTES); + if(len<0 || len>MAX_DATA_BYTES) { + fprintf(stderr,"opus_encode() returned %d\n", len); + goto bad_cleanup; + } + + out_samples = opus_projection_decode( + st_dec, data, len, buffer_out, MAX_FRAME_SAMPLES, 0); + if(out_samples!=BUFFER_SIZE) { + fprintf(stderr,"opus_decode() returned %d\n", out_samples); + goto bad_cleanup; + } + + opus_projection_decoder_destroy(st_dec); + opus_projection_encoder_destroy(st_enc); + free(buffer_in); + free(buffer_out); + return; +bad_cleanup: + free(buffer_in); + free(buffer_out); + test_failed(); +} + +int main(int _argc, char **_argv) +{ + unsigned int i; + + (void)_argc; + (void)_argv; + + /* Test simple matrix multiplication routines. */ + test_simple_matrix(); + + /* Test full range of channels in creation arguments. */ + for (i = 0; i < 255; i++) + test_creation_arguments(i, 3); + + /* Test encode/decode pipeline. */ + test_encode_decode(64 * 18, 18, 3); + + fprintf(stderr, "All projection tests passed.\n"); + return 0; +} + diff --git a/native/codec/libraries/opus/training/rnn_dump.py b/native/codec/libraries/opus/training/rnn_dump.py new file mode 100755 index 0000000..c312088 --- /dev/null +++ b/native/codec/libraries/opus/training/rnn_dump.py @@ -0,0 +1,66 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.models import load_model +from keras import backend as K +import sys + +import numpy as np + +def printVector(f, vector, name): + v = np.reshape(vector, (-1)); + #print('static const float ', name, '[', len(v), '] = \n', file=f) + f.write('static const opus_int8 {}[{}] = {{\n '.format(name, len(v))) + for i in range(0, len(v)): + f.write('{}'.format(max(-128,min(127,int(round(128*v[i])))))) + if (i!=len(v)-1): + f.write(',') + else: + break; + if (i%8==7): + f.write("\n ") + else: + f.write(" ") + #print(v, file=f) + f.write('\n};\n\n') + return; + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + + +#model = load_model(sys.argv[1], custom_objects={'binary_crossentrop2': binary_crossentrop2}) +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(32, activation='tanh')(main_input) +x = GRU(24, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x) +x = Dense(2, activation='sigmoid')(x) +model = Model(inputs=main_input, outputs=x) +model.load_weights(sys.argv[1]) + +weights = model.get_weights() + +f = open(sys.argv[2], 'w') + +f.write('/*This file is automatically generated from a Keras model*/\n\n') +f.write('#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n#include "mlp.h"\n\n') + +printVector(f, weights[0], 'layer0_weights') +printVector(f, weights[1], 'layer0_bias') +printVector(f, weights[2], 'layer1_weights') +printVector(f, weights[3], 'layer1_recur_weights') +printVector(f, weights[4], 'layer1_bias') +printVector(f, weights[5], 'layer2_weights') +printVector(f, weights[6], 'layer2_bias') + +f.write('const DenseLayer layer0 = {\n layer0_bias,\n layer0_weights,\n 25, 32, 0\n};\n\n') +f.write('const GRULayer layer1 = {\n layer1_bias,\n layer1_weights,\n layer1_recur_weights,\n 32, 24\n};\n\n') +f.write('const DenseLayer layer2 = {\n layer2_bias,\n layer2_weights,\n 24, 2, 1\n};\n\n') + +f.close() diff --git a/native/codec/libraries/opus/training/rnn_train.py b/native/codec/libraries/opus/training/rnn_train.py new file mode 100755 index 0000000..29bcb03 --- /dev/null +++ b/native/codec/libraries/opus/training/rnn_train.py @@ -0,0 +1,177 @@ +#!/usr/bin/python3 + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.layers import CuDNNGRU +from keras.layers import SimpleRNN +from keras.layers import Dropout +from keras import losses +import h5py +from keras.optimizers import Adam + +from keras.constraints import Constraint +from keras import backend as K +import numpy as np + +import tensorflow as tf +from keras.backend.tensorflow_backend import set_session +config = tf.ConfigProto() +config.gpu_options.per_process_gpu_memory_fraction = 0.44 +set_session(tf.Session(config=config)) + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_true, y_pred), axis=-1) + +def binary_accuracy2(y_true, y_pred): + return K.mean(K.cast(K.equal(y_true, K.round(y_pred)), 'float32') + K.cast(K.equal(y_true, 0.5), 'float32'), axis=-1) + +def quant_model(model): + weights = model.get_weights() + for k in range(len(weights)): + weights[k] = np.maximum(-128, np.minimum(127, np.round(128*weights[k])*0.0078125)) + model.set_weights(weights) + +class WeightClip(Constraint): + '''Clips the weights incident to each hidden unit to be inside a range + ''' + def __init__(self, c=2): + self.c = c + + def __call__(self, p): + return K.clip(p, -self.c, self.c) + + def get_config(self): + return {'name': self.__class__.__name__, + 'c': self.c} + +reg = 0.000001 +constraint = WeightClip(.998) + +print('Build model...') + +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(32, activation='tanh', kernel_constraint=constraint, bias_constraint=constraint)(main_input) +#x = CuDNNGRU(24, return_sequences=True, kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(x) +x = GRU(24, recurrent_activation='sigmoid', activation='tanh', return_sequences=True, kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(x) +x = Dense(2, activation='sigmoid', kernel_constraint=constraint, bias_constraint=constraint)(x) +model = Model(inputs=main_input, outputs=x) + +batch_size = 2048 + +print('Loading data...') +with h5py.File('features10b.h5', 'r') as hf: + all_data = hf['data'][:] +print('done.') + +window_size = 1500 + +nb_sequences = len(all_data)//window_size +print(nb_sequences, ' sequences') +x_train = all_data[:nb_sequences*window_size, :-2] +x_train = np.reshape(x_train, (nb_sequences, window_size, 25)) + +y_train = np.copy(all_data[:nb_sequences*window_size, -2:]) +y_train = np.reshape(y_train, (nb_sequences, window_size, 2)) + +print("Marking ignores") +for s in y_train: + for e in s: + if (e[1] >= 1): + break + e[0] = 0.5 + +all_data = 0; +x_train = x_train.astype('float32') +y_train = y_train.astype('float32') + +print(len(x_train), 'train sequences. x shape =', x_train.shape, 'y shape = ', y_train.shape) + +model.load_weights('newweights10a1b_ep206.hdf5') + +#weights = model.get_weights() +#for k in range(len(weights)): +# weights[k] = np.round(128*weights[k])*0.0078125 +#model.set_weights(weights) + +# try using different optimizers and different optimizer configs +model.compile(loss=binary_crossentrop2, + optimizer=Adam(0.0001), + metrics=[binary_accuracy2]) + +print('Train...') +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=10, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep10.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=50, initial_epoch=10) +model.save("newweights10a1c_ep50.hdf5") + +model.compile(loss=binary_crossentrop2, + optimizer=Adam(0.0001), + metrics=[binary_accuracy2]) + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=100, initial_epoch=50) +model.save("newweights10a1c_ep100.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=150, initial_epoch=100) +model.save("newweights10a1c_ep150.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=200, initial_epoch=150) +model.save("newweights10a1c_ep200.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=201, initial_epoch=200) +model.save("newweights10a1c_ep201.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=202, initial_epoch=201, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep202.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=203, initial_epoch=202, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep203.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=204, initial_epoch=203, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep204.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=205, initial_epoch=204, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep205.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=206, initial_epoch=205, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep206.hdf5") + diff --git a/native/codec/libraries/opus/training/txt2hdf5.py b/native/codec/libraries/opus/training/txt2hdf5.py new file mode 100755 index 0000000..9c60287 --- /dev/null +++ b/native/codec/libraries/opus/training/txt2hdf5.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +from __future__ import print_function + +import numpy as np +import h5py +import sys + +data = np.loadtxt(sys.argv[1], dtype='float32') +h5f = h5py.File(sys.argv[2], 'w'); +h5f.create_dataset('data', data=data) +h5f.close() diff --git a/native/codec/libraries/opus/update_version b/native/codec/libraries/opus/update_version new file mode 100755 index 0000000..a999991 --- /dev/null +++ b/native/codec/libraries/opus/update_version @@ -0,0 +1,65 @@ +#!/bin/bash + +# Creates and updates the package_version information used by configure.ac +# (or other makefiles). When run inside a git repository it will use the +# version information that can be queried from it unless AUTO_UPDATE is set +# to 'no'. If no version is currently known it will be set to 'unknown'. +# +# If called with the argument 'release', the PACKAGE_VERSION will be updated +# even if AUTO_UPDATE=no, but the value of AUTO_UPDATE shall be preserved. +# This is used to force a version update whenever `make dist` is run. +# +# The exit status is 1 if package_version is not modified, else 0 is returned. +# +# This script should NOT be included in distributed tarballs, because if a +# parent directory contains a git repository we do not want to accidentally +# retrieve the version information from it instead. Tarballs should ship +# with only the package_version file. +# +# Ron , 2012. + +SRCDIR=$(dirname $0) + +if [ -e "$SRCDIR/package_version" ]; then + . "$SRCDIR/package_version" +fi + +if [ "$AUTO_UPDATE" = no ]; then + [ "$1" = release ] || exit 1 +else + AUTO_UPDATE=yes +fi + +# We run `git status` before describe here to ensure that we don't get a false +# -dirty from files that have been touched but are not actually altered in the +# working dir. +GIT_VERSION=$(cd "$SRCDIR" && git status > /dev/null 2>&1 \ + && git describe --tags --match 'v*' --dirty 2> /dev/null) +GIT_VERSION=${GIT_VERSION#v} + +if [ -n "$GIT_VERSION" ]; then + + [ "$GIT_VERSION" != "$PACKAGE_VERSION" ] || exit 1 + PACKAGE_VERSION="$GIT_VERSION" + +elif [ -z "$PACKAGE_VERSION" ]; then + # No current package_version and no git ... + # We really shouldn't ever get here, because this script should only be + # included in the git repository, and should usually be export-ignored. + PACKAGE_VERSION="unknown" +else + exit 1 +fi + +cat > "$SRCDIR/package_version" <<-EOF + # Automatically generated by update_version. + # This file may be sourced into a shell script or makefile. + + # Set this to 'no' if you do not wish the version information + # to be checked and updated for every build. Most people will + # never want to change this, it is an option for developers + # making frequent changes that they know will not be released. + AUTO_UPDATE=$AUTO_UPDATE + + PACKAGE_VERSION="$PACKAGE_VERSION" +EOF diff --git a/native/codec/libraries/opus/win32/.gitignore b/native/codec/libraries/opus/win32/.gitignore new file mode 100644 index 0000000..c17feab --- /dev/null +++ b/native/codec/libraries/opus/win32/.gitignore @@ -0,0 +1,26 @@ +# Visual Studio ignores +[Dd]ebug/ +[Dd]ebugDLL/ +[Dd]ebugDLL_fixed/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleaseDLL/ +[Rr]eleaseDLL_fixed/ +[Rr]eleases/ +*.manifest +*.lastbuildstate +*.lib +*.log +*.idb +*.ipdb +*.ilk +*.iobj +*.obj +*.opensdf +*.pdb +*.sdf +*.suo +*.tlog +*.vcxproj.user +*.vc.db +*.vc.opendb diff --git a/native/codec/libraries/opus/win32/VS2015/common.props b/native/codec/libraries/opus/win32/VS2015/common.props new file mode 100644 index 0000000..6c757d8 --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/common.props @@ -0,0 +1,82 @@ + + + + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + Unicode + + + true + true + false + + + false + false + true + + + + Level3 + false + false + ..\..;..\..\include;..\..\silk;..\..\celt;..\..\win32;%(AdditionalIncludeDirectories) + HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + false + + + Console + + + true + Console + + + + + Guard + ProgramDatabase + NoExtensions + false + true + false + Disabled + false + false + Disabled + MultiThreadedDebug + MultiThreadedDebugDLL + true + false + + + true + + + + + false + None + true + true + false + Speed + Fast + Precise + true + true + true + MaxSpeed + MultiThreaded + MultiThreadedDLL + 16Bytes + + + false + + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/VS2015/opus.sln b/native/codec/libraries/opus/win32/VS2015/opus.sln new file mode 100644 index 0000000..7b678e7 --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/opus.sln @@ -0,0 +1,168 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus", "opus.vcxproj", "{219EC965-228A-1824-174D-96449D05F88A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus_demo", "opus_demo.vcxproj", "{016C739D-6389-43BF-8D88-24B2BF6F620F}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_api", "test_opus_api.vcxproj", "{1D257A17-D254-42E5-82D6-1C87A6EC775A}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_decode", "test_opus_decode.vcxproj", "{8578322A-1883-486B-B6FA-E0094B65C9F2}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_encode", "test_opus_encode.vcxproj", "{84DAA768-1A38-4312-BB61-4C78BB59E5B8}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + DebugDLL_fixed|Win32 = DebugDLL_fixed|Win32 + DebugDLL_fixed|x64 = DebugDLL_fixed|x64 + DebugDLL|Win32 = DebugDLL|Win32 + DebugDLL|x64 = DebugDLL|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseDLL_fixed|Win32 = ReleaseDLL_fixed|Win32 + ReleaseDLL_fixed|x64 = ReleaseDLL_fixed|x64 + ReleaseDLL|Win32 = ReleaseDLL|Win32 + ReleaseDLL|x64 = ReleaseDLL|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {219EC965-228A-1824-174D-96449D05F88A}.Debug|Win32.ActiveCfg = Debug|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|Win32.Build.0 = Debug|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|x64.ActiveCfg = Debug|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|x64.Build.0 = Debug|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Release|Win32.ActiveCfg = Release|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Release|Win32.Build.0 = Release|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Release|x64.ActiveCfg = Release|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Release|x64.Build.0 = Release|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|Win32.ActiveCfg = Debug|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|Win32.Build.0 = Debug|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|x64.ActiveCfg = Debug|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|x64.Build.0 = Debug|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|Win32.ActiveCfg = Release|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|Win32.Build.0 = Release|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|x64.ActiveCfg = Release|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|x64.Build.0 = Release|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|Win32.ActiveCfg = Debug|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|Win32.Build.0 = Debug|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|x64.ActiveCfg = Debug|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|x64.Build.0 = Debug|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|Win32.ActiveCfg = Release|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|Win32.Build.0 = Release|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|x64.ActiveCfg = Release|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|x64.Build.0 = Release|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|Win32.ActiveCfg = Debug|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|Win32.Build.0 = Debug|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|x64.ActiveCfg = Debug|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|x64.Build.0 = Debug|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|Win32.ActiveCfg = Release|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|Win32.Build.0 = Release|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|x64.ActiveCfg = Release|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|x64.Build.0 = Release|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|Win32.ActiveCfg = Debug|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|Win32.Build.0 = Debug|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|x64.ActiveCfg = Debug|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|x64.Build.0 = Debug|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|Win32.ActiveCfg = Release|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|Win32.Build.0 = Release|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|x64.ActiveCfg = Release|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|x64.Build.0 = Release|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native/codec/libraries/opus/win32/VS2015/opus.vcxproj b/native/codec/libraries/opus/win32/VS2015/opus.vcxproj new file mode 100644 index 0000000..34b1233 --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/opus.vcxproj @@ -0,0 +1,399 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + Win32Proj + opus + {219EC965-228A-1824-174D-96449D05F88A} + + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\silk\fixed;..\..\silk\float;%(AdditionalIncludeDirectories) + DLL_EXPORT;%(PreprocessorDefinitions) + FIXED_POINT;%(PreprocessorDefinitions) + /arch:IA32 %(AdditionalOptions) + + + /ignore:4221 %(AdditionalOptions) + + + "$(ProjectDir)..\..\win32\genversion.bat" "$(ProjectDir)..\..\win32\version.h" PACKAGE_VERSION + Generating version.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4244;%(DisableSpecificWarnings) + + + + + + + + + + + + + + + false + + + false + + + true + + + + + + + true + + + true + + + false + + + + + + + + diff --git a/native/codec/libraries/opus/win32/VS2015/opus.vcxproj.filters b/native/codec/libraries/opus/win32/VS2015/opus.vcxproj.filters new file mode 100644 index 0000000..8c61d6a --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/opus.vcxproj.filters @@ -0,0 +1,585 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + diff --git a/native/codec/libraries/opus/win32/VS2015/opus_demo.vcxproj b/native/codec/libraries/opus/win32/VS2015/opus_demo.vcxproj new file mode 100644 index 0000000..f4344e5 --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/opus_demo.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + + + + {016C739D-6389-43BF-8D88-24B2BF6F620F} + Win32Proj + opus_demo + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/VS2015/opus_demo.vcxproj.filters b/native/codec/libraries/opus/win32/VS2015/opus_demo.vcxproj.filters new file mode 100644 index 0000000..2eb113a --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/opus_demo.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/VS2015/test_opus_api.vcxproj b/native/codec/libraries/opus/win32/VS2015/test_opus_api.vcxproj new file mode 100644 index 0000000..7cae131 --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/test_opus_api.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {1D257A17-D254-42E5-82D6-1C87A6EC775A} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/VS2015/test_opus_api.vcxproj.filters b/native/codec/libraries/opus/win32/VS2015/test_opus_api.vcxproj.filters new file mode 100644 index 0000000..383d19f --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/test_opus_api.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/VS2015/test_opus_decode.vcxproj b/native/codec/libraries/opus/win32/VS2015/test_opus_decode.vcxproj new file mode 100644 index 0000000..df01dca --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/test_opus_decode.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {8578322A-1883-486B-B6FA-E0094B65C9F2} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/VS2015/test_opus_decode.vcxproj.filters b/native/codec/libraries/opus/win32/VS2015/test_opus_decode.vcxproj.filters new file mode 100644 index 0000000..3036a4e --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/test_opus_decode.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4a0dd677-931f-4728-afe5-b761149fc7eb} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/VS2015/test_opus_encode.vcxproj b/native/codec/libraries/opus/win32/VS2015/test_opus_encode.vcxproj new file mode 100644 index 0000000..405efee --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/test_opus_encode.vcxproj @@ -0,0 +1,172 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {84DAA768-1A38-4312-BB61-4C78BB59E5B8} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/VS2015/test_opus_encode.vcxproj.filters b/native/codec/libraries/opus/win32/VS2015/test_opus_encode.vcxproj.filters new file mode 100644 index 0000000..4ed3bb9 --- /dev/null +++ b/native/codec/libraries/opus/win32/VS2015/test_opus_encode.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {546c8d9a-103e-4f78-972b-b44e8d3c8aba} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/native/codec/libraries/opus/win32/genversion.bat b/native/codec/libraries/opus/win32/genversion.bat new file mode 100644 index 0000000..1def746 --- /dev/null +++ b/native/codec/libraries/opus/win32/genversion.bat @@ -0,0 +1,37 @@ +@echo off + +setlocal enableextensions enabledelayedexpansion + +for /f %%v in ('cd "%~dp0.." ^&^& git status ^>NUL 2^>NUL ^&^& git describe --tags --match "v*" --dirty 2^>NUL') do set version=%%v + +if not "%version%"=="" set version=!version:~1! && goto :gotversion + +if exist "%~dp0..\package_version" goto :getversion + +echo Git cannot be found, nor can package_version. Generating unknown version. + +set version=unknown + +goto :gotversion + +:getversion + +for /f "delims== tokens=2" %%v in (%~dps0..\package_version) do set version=%%v +set version=!version:"=! + +:gotversion + +set version=!version: =! +set version_out=#define %~2 "%version%" + +echo %version_out%> "%~1_temp" + +echo n | comp "%~1_temp" "%~1" > NUL 2> NUL + +if not errorlevel 1 goto exit + +copy /y "%~1_temp" "%~1" + +:exit + +del "%~1_temp" diff --git a/native/codec/libraries/speex/.cvsignore b/native/codec/libraries/speex/.cvsignore new file mode 100644 index 0000000..0c6bca2 --- /dev/null +++ b/native/codec/libraries/speex/.cvsignore @@ -0,0 +1,17 @@ +Makefile +Makefile.in +Speex.spec +aclocal.m4 +autom4te.cache +config.guess +config.log +config.status +config.sub +configure +depcomp +install-sh +libtool +ltconfig +ltmain.sh +missing +mkinstalldirs diff --git a/native/codec/libraries/speex/.gitignore b/native/codec/libraries/speex/.gitignore new file mode 100644 index 0000000..7c30999 --- /dev/null +++ b/native/codec/libraries/speex/.gitignore @@ -0,0 +1,45 @@ +*.o +*.lo +Makefile.in +*~ +*.orig +fixed +float +Speex.kdevelop.pcs +Speex.kdevses +aclocal.m4 +autom4te.cache +compile +config.guess +config.h.in +config.sub +configure +depcomp +install-sh +ltmain.sh +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +missing +Makefile +.deps +.libs +*.la +work +Speex.spec +config.h +config.log +config.status +include/speex/speex_config_types.h +*.sw[lmnop] +testenc +testenc_uwb +testenc_wb +libtool +speex.pc +src/speexdec +src/speexenc +stamp-* +patches diff --git a/native/codec/libraries/speex/.travis.yml b/native/codec/libraries/speex/.travis.yml new file mode 100644 index 0000000..ff85bc3 --- /dev/null +++ b/native/codec/libraries/speex/.travis.yml @@ -0,0 +1,21 @@ +language: c + +env: + - CONFIG="" + - CONFIG="--enable-fixed-point" + - CONFIG="--enable-fixed-point --disable-float-api" + - CONFIG="--enable-vorbis-psy" + - CONFIG="--disable-binaries" + +os: + - linux + - osx + +compiler: + - gcc + - clang + +script: + - ./autogen.sh + - ./configure $CONFIG + - make distcheck diff --git a/native/codec/libraries/speex/AUTHORS b/native/codec/libraries/speex/AUTHORS new file mode 100644 index 0000000..395c3fe --- /dev/null +++ b/native/codec/libraries/speex/AUTHORS @@ -0,0 +1,18 @@ +Jean-Marc Valin + All the code except the following + +David Rowe + lsp.c lsp.h + Also ideas and feedback + +John Francis Edwards + wave_out.[ch], some #ifdefs for windows port and MSVC project files + +Segher Boessenkool + Misc. optimizations (for QMF in particular) + +Atsuhiko Yamanaka : + Patch to speexenc.c to add Vorbis comment format + +Radim Kolar : + Patch to speexenc.c for supporting more input formats diff --git a/native/codec/libraries/speex/COPYING b/native/codec/libraries/speex/COPYING new file mode 100644 index 0000000..de6fbe2 --- /dev/null +++ b/native/codec/libraries/speex/COPYING @@ -0,0 +1,35 @@ +Copyright 2002-2008 Xiph.org Foundation +Copyright 2002-2008 Jean-Marc Valin +Copyright 2005-2007 Analog Devices Inc. +Copyright 2005-2008 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) +Copyright 1993, 2002, 2006 David Rowe +Copyright 2003 EpicGames +Copyright 1992-1994 Jutta Degener, Carsten Bormann + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/native/codec/libraries/speex/ChangeLog b/native/codec/libraries/speex/ChangeLog new file mode 100644 index 0000000..9a6cd8a --- /dev/null +++ b/native/codec/libraries/speex/ChangeLog @@ -0,0 +1,21 @@ +2005-09-07 Thomas Vander Stichele + + * libspeex/cb_search.c: (split_cb_search_shape_sign_N1): + add declaration for n, seems like an obvious build fix, slap + me down if it's not + +2004-02-18 Jean-Marc Valin + Patch for compiling with mingw32 sent by j@thing.net + +2004-02-18 Jean-Marc Valin + Integrated IRIX patch (getopt stuff) from Michael Pruett + +2004-02-18 Jean-Marc Valin + Changed the Makefile.am so that KDevelop can parse SUBDIRS correctly + +2002/03/27 Jean-Marc Valin: +Working encoder and decoder for both narrowband and wideband. + +2002/02/27 Jean-Marc Valin: +Got the basic encoder working as a demo with quantization only on some +parameters. diff --git a/native/codec/libraries/speex/Doxyfile b/native/codec/libraries/speex/Doxyfile new file mode 100644 index 0000000..772934f --- /dev/null +++ b/native/codec/libraries/speex/Doxyfile @@ -0,0 +1,225 @@ +# Doxyfile 1.5.1-KDevelop + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = Speex +PROJECT_NUMBER = 1.2-beta2 +OUTPUT_DIRECTORY = doc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = include/speex +FILE_PATTERNS = +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = speex_config_types.h +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = gif +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/native/codec/libraries/speex/IDEAS b/native/codec/libraries/speex/IDEAS new file mode 100644 index 0000000..73fe26e --- /dev/null +++ b/native/codec/libraries/speex/IDEAS @@ -0,0 +1,4 @@ +- Non-linear adaptive codebook (use exc[n]*|exc[n]| to reduce noise + component in adaptive codebook excitation) + +- Include time-domain masking for VBR diff --git a/native/codec/libraries/speex/INSTALL b/native/codec/libraries/speex/INSTALL new file mode 100644 index 0000000..ca9d5d1 --- /dev/null +++ b/native/codec/libraries/speex/INSTALL @@ -0,0 +1,8 @@ +Installing Speex is as easy as: + +% ./configure [--prefix=] +% make +% make install + +Note that if you are using the code from Git, you will need to run "autogen.sh" +and then "configure". diff --git a/native/codec/libraries/speex/Makefile.am b/native/codec/libraries/speex/Makefile.am new file mode 100644 index 0000000..dc90415 --- /dev/null +++ b/native/codec/libraries/speex/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# To disable automatic dependency tracking if using other tools than +# gcc and gmake, add the option 'no-dependencies' +AUTOMAKE_OPTIONS = 1.8 +ACLOCAL_AMFLAGS = -I m4 + +m4datadir = $(datadir)/aclocal +m4data_DATA = speex.m4 + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = speex.pc + +EXTRA_DIST = Speex.spec Speex.spec.in Speex.kdevelop speex.m4 speex.pc.in README.blackfin README.symbian README.TI-DSP + +#Fools KDevelop into including all files +SUBDIRS = libspeex include doc win32 symbian ti + +if BUILD_BINARIES +SUBDIRS += src +endif + +DIST_SUBDIRS = libspeex include src doc win32 symbian ti + +rpm: dist + rpmbuild -ta ${PACKAGE}-${VERSION}.tar.gz diff --git a/native/codec/libraries/speex/NEWS b/native/codec/libraries/speex/NEWS new file mode 100644 index 0000000..9a99529 --- /dev/null +++ b/native/codec/libraries/speex/NEWS @@ -0,0 +1 @@ +2002/02/13: Creation of the "Speex" project diff --git a/native/codec/libraries/speex/OPTIMIZE b/native/codec/libraries/speex/OPTIMIZE new file mode 100644 index 0000000..d36f5f7 --- /dev/null +++ b/native/codec/libraries/speex/OPTIMIZE @@ -0,0 +1,10 @@ +Narrowband: + +- pitch_gain_search_3tap calls syn_filt_zero more times than it should (we're +computing some things twice) + +Wideband + +- All narrowband optimizations apply +- Lots of time spent in the codebook search. We could speed that up by using + a hierarchical codebook diff --git a/native/codec/libraries/speex/README b/native/codec/libraries/speex/README new file mode 100644 index 0000000..84fe74a --- /dev/null +++ b/native/codec/libraries/speex/README @@ -0,0 +1,9 @@ +See INSTALL file for instruction on how to install Speex. + +The Speex is a patent-free, Open Source/Free Software voice codec. Unlike other codecs like MP3 and Ogg Vorbis, Speex is designed to compress voice at bitrates in the 2-45 kbps range. Possible applications include VoIP, internet audio streaming, archiving of speech data (e.g. voice mail), and audio books. In some sense, it is meant to be complementary to the Ogg Vorbis codec. + +To use the Speex command line tools: + +% speexenc [options] input_file.wav compressed_file.spx + +% speexdec [options] compressed_file.spx output_file.wav diff --git a/native/codec/libraries/speex/README.TI-DSP b/native/codec/libraries/speex/README.TI-DSP new file mode 100644 index 0000000..c3b7576 --- /dev/null +++ b/native/codec/libraries/speex/README.TI-DSP @@ -0,0 +1,56 @@ +These are all of the changes and additions necessary to build a loopback application for the +TI C6415, C5509A, or C5416 simulators using the TI Code Composer Studio (CCS) development system. +A trial version of the tools can be downloaded from the TI website. + +This build runs 8kbps narrowband, with minimum complexity. + +Several changes are introduced in Speex 1.1.11 which are used in these applications: + +arch.h: Added switch for compilers not supporting "long long" (C55x does, C54x, CCS 2.x C64x does not) +bits.c: Allow external definition for max buffer size, changed MAX_BYTES_PER_FRAME + to MAX_CHARS_PER_FRAME for consistency +misc.c: Added override switches to alloc routines, conditional include of user file "user_misc.h". + These changes allow manual memory allocation rather than using heap + +The arch.h change allows operation with 2.x versions of Code Composer Studio. +The bits.c change reduces the data memory usage. +The misc.c change allows private memory allocation, for cases where it is not +desirable to use the normal heap. + +Added files: + +testenc-TI-C5x.c (For C54x and C55x builds, derived from testenc.c, + manual alloc, byte packing/unpacking added) +testenc-TI-C64x.c (For C64x builds, derived from testenc.c, manual alloc, byte packing/unpacking added) + +config.h (not automatically generated, sets memory sizes, enables/disables manual alloc) +user_misc.h (contains the manual memory alloc routines, with debug code to display mem usage) +speex\speex_config_types.h (match Speex types to compiler types, not generated from types.in) + +speex_c54_test\speex_c54_test.cmd (C5416 linker command file) +speex_c54_test\speex_c54_test.pjt (Code Composer Studio Project File ) +speex_c55_test\speex_c55_test.cmd (C5509A linker command file) +speex_c55_test\speex_c55_test.pjt (Code Composer Studio Project File ) +speex_c64_test\speex_c64_test.cmd (C6415 linker command file) +speex_c64_test\speex_c64_test.pjt (Code Composer Studio Project File ) + +samples\male.snd + +Usage: +1. Create a Speex 1.1.11 (or later) source tree. +2. Edit the files testenc-TI-C5x.c and/or testenc-TI-C64x.c to change the hard-coded path + for the test audio and data files. + This build uses the file e:\speextrunktest\samples\male.snd. + Note: This is a headerless 16-bit stereo audio file derived from the male.wav test file + http://www.speex.org/samples/male.wav +3. Edit the .pjt file with a text editor and change projdir or projectdir to the correct path + (one place near the top of the file). +4. Edit config.h if desired, to change the memory allocation method (calloc or manual), + and to enable/disable debug prints for the memory allocation + (this makes it easier to determine the required size). +5. Run Code Composer Studio, and open the project for the desired target (e.g. speex_c55_test). + Note that the correct simulator must be selected (in CCS Setup) before starting CCS. +6. Build and run the simulation. + +Note that assembly optimizations will be required to run C54x in real time. +There are no assembly optimizations in any of these builds. diff --git a/native/codec/libraries/speex/README.Trimedia b/native/codec/libraries/speex/README.Trimedia new file mode 100644 index 0000000..8adc80e --- /dev/null +++ b/native/codec/libraries/speex/README.Trimedia @@ -0,0 +1,191 @@ +################# REMOVE warnings on trimedia compiler ############################## +################# Not critical to compilation ############################## + +1. Change the following statements to remove warning for constant expression +(i) mdf.c [if(0) --> #if 0] +(ii) ltp.c [if(1) --> #if 1] +(iii) preprocess.c [if(1) --> #if 1] +(iv) sb_celp.c [if (SPEEX_SET_VBR_MAX_BITRATE<1) --> #if (SPEEX_SET_VBR_MAX_BITRATE<1)] + +2. add REMARK_ON macro to remove warning on not reference variable +-- uses (void) to remove warning on not referenced variable +-- #define REMARK_ON +-- (void) +-- #endif +-- search for REMARK_ON on the following files +(i) jitter.c +(ii) lsp.c +(iii) ltp.c +(iv) mdf.c +(v) filters.c +(vi) filterbank.c +(vii) cb_search.c +(viii) vq.c +(ix) vbr.c +(x) stereo.c +(xi) speex_callbacks.c +(xii) preprocess.c + +3. commented out the following in pseudofloat.h for unused variable +//static const spx_float_t FLOAT_HALF = {16384,-15}; + +4. commented out unused variable in nb_celp.c +//spx_word16_t *sp; ***unused variable*** +//sp=out+offset; ***unused variable*** +//int submode; ***unused variable*** +// ***unused variable*** +// advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); +advance = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); +// ***unused variable*** +//advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); +advance = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); +// spx_word16_t *exc; ***unused variable*** +// exc=st->exc+offset; ***unused variable*** + +5. commented out unused variable in vbr.c +//int va; ***unused variable*** +//va = 0; ***unused variable*** +//va = 1; ***unused variable*** + +6. added HAVE_CONFIG into medfilter.c + +################# Patches for trimedia compiler ############################## +################# Critical to compilation ############################## +-- change the following in modes.c and speex.h as compiler does not support const * const... +(i) modes.c +#ifdef __TCS__ +const SpeexMode * speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; +#else +const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; +#endif + +(ii) speex.h +#ifdef __TCS__ +extern const SpeexMode * speex_mode_list[SPEEX_NB_MODES]; +#else +extern const SpeexMode * const speex_mode_list[SPEEX_NB_MODES]; +#endif + +-- added the #elif defined (TM_ASM) to the following files for optimized codes +(1) arch.h +(2) cb_search.c +(3) fftwrap.c +(4) filterbank.c +(5) filters.c +(6) kiss_fft.c +(7) kiss_fftr.c +(8) lpc.c +(9) lsp.c +(10) ltp.c +(11) mdf.c +(12) misc.c +(13) preprocess.c +(14) quant_lsp.c +(15) vq.c + +-- reorder macro definations in quant_lsp.c +#ifdef FIXED_POINT + +#define LSP_LINEAR(i) (SHL16(i+1,11)) +#define LSP_LINEAR_HIGH(i) (ADD16(MULT16_16_16(i,2560),6144)) +#define LSP_DIV_256(x) (SHL16((spx_word16_t)x, 5)) +#define LSP_DIV_512(x) (SHL16((spx_word16_t)x, 4)) +#define LSP_DIV_1024(x) (SHL16((spx_word16_t)x, 3)) +#define LSP_PI 25736 + +#else + +#define LSP_LINEAR(i) (.25*(i)+.25) +#define LSP_LINEAR_HIGH(i) (.3125*(i)+.75) +#define LSP_SCALE 256. +#define LSP_DIV_256(x) (0.0039062*(x)) +#define LSP_DIV_512(x) (0.0019531*(x)) +#define LSP_DIV_1024(x) (0.00097656*(x)) +#define LSP_PI M_PI + +#endif + +#ifdef BFIN_ASM +#include "quant_lsp_bfin.h" +#elif defined (TM_ASM) +#include "quant_lsp_tm.h" +#endif + +-- added macro PREPROCESS_MDF_FLOAT to allow using of floating point +-- in mdf and preprocess while keeping fixed point in encoder/decoder +-- This is due to the fact that preprocess/mdf run faster on floating +-- point on trimedia +-- added the following 3 lines to the files below +#ifdef PREPROCESS_MDF_FLOAT +#undef FIXED_POINT +#endif +(1) mdf.c +(2) preprocess.c +(3) filterbank.c +(4) fftwrap.c +(5) kiss_fft.c +(6) kiss_fftr.c + +-- created a new USE_COMPACT_KISS_FFT for fftwrap.c and shifted defination +-- to config file so that user configure the usage of fft on config.h +-- TOEXPLORE:is it possible to share table between mdf/preprocess? +-- Introducing this macro made the following changes in C code +-- New macro to facilitate integration +(grouping real/complex for dc and nyquist frequency seems to require a large +amount of memory for mdf, therefore did not made the changes for that) +(1) modify preprocess.c on init and destroy +(2) modify mdf.c on init and destroy +(3) shifted power_spectrum to fftwrap.c to share optimised code between + preprocess.c and mdf.c + +################# NOTES ############################## +(1) fixed point encoding/decoding is tested on narrowband + - some of the QX fractions are packed together to + (frac1 * a + frac2 * a) >> X (should be more accurate in rounding) + instead of + ((frac1 * a) >> X) + ((frac2 * a) >> X) + will cause some different between optimized and unoptimized code. + tried decoding/encoding optimized code on some audio files retains + the clearity of the word + + - wideband/ultrawideband is not heavily tested yet + +(2) optimized fixed point code requires memory alignment + - used config to debug on functions where memory is not align + +(3) floating point optimization for preprocess/mdf is tested + fixed point is not tested yet (except fft/filterbank) + Note (1) also applies to sround in fft for fixed point + some optimization is provided for fixed point as it requires lesser + memory compared to floating point. + +(4) unroll configurations provided to reduce code size if required + +(5) use profile options only if compiler profiling fails to work + +(6) can't include the makefile as it is close proprietary + +################# TODO:For Trimedia ############################## +(1) Possible add TSSA wrapper for codec but don't think this can be open source. +(2) Optimizations for fixed point in mdf/preprocess + +################# Added Files ############################## +- _kiss_fft_guts_tm.h +- cb_search_tm.h +- fftwrap_tm.h +- filterbank_tm.h +- filters_tm.h +- fixed_tm.h +- kiss_fft_tm.h +- kiss_fftr_tm.h +- lpc_tm.h +- lsp_tm.h +- ltp_tm.h +- mdf_tm.h +- misc_tm.h +- preprocess_tm.h +- profile_tm.h +- quant_lsp_tm.h +- vq_tm.h +- config.h +- speex_config_types.h diff --git a/native/codec/libraries/speex/README.blackfin b/native/codec/libraries/speex/README.blackfin new file mode 100644 index 0000000..5923e86 --- /dev/null +++ b/native/codec/libraries/speex/README.blackfin @@ -0,0 +1,21 @@ +Speex has been ported to the Blackfin DSP, for the STAMP development board. + +This port has been tested on the STAMP development board and requires the +toolchain available at http://blackfin.uclinux.org/ + +1/ In order to cross-compile for uClinux from the Speex tarball: + + ./configure --enable-blackfin-asm --enable-fixed-point --host=bfin-uclinux + cd libspeex + make + +The --enable-blackfin-asm option is not required, but it speeds up Speex by +approximately a factor of two. + +2/ In order to cross-compile for uClinux from the Speex Git: + + git clone git://git.xiph.org/speex.git + cd speex + ./autogen.sh --enable-blackfin-asm --enable-fixed-point --host=bfin-uclinux + cd libspeex + make diff --git a/native/codec/libraries/speex/README.symbian b/native/codec/libraries/speex/README.symbian new file mode 100644 index 0000000..a4f8d95 --- /dev/null +++ b/native/codec/libraries/speex/README.symbian @@ -0,0 +1,43 @@ +Using Speex on Symbian OS +Conrad Parker and Colin Ward, CSIRO Australia, July 2004 + + +Introduction +------------ + +The symbian/ directory contains the following files for Symbian's abuild tool: + + bld.inf Component definition file + speex.mmp Project specification file + config.h Configuration options for both emulator and device builds + + +Developing applications for libspeex for Symbian OS +--------------------------------------------------- + + Any references to the statically defined SpeexMode structures must be + replaced by a call to a speex_lib_get_mode () for that mode. + + * References to the statically defined array speex_mode_list[modeID] + must be replaced by a call to speex_lib_get_mode (modeID): + +- mode = speex_mode_list[modeID]; ++ mode = speex_lib_get_mode (modeID); + + * References to the statically defined mode structures must be replaced: + + SpeexMode * mode1, * mode2, * mode3; + +- mode1 = &speex_nb_mode; ++ mode1 = speex_lib_get_mode (SPEEX_MODEID_NB); + +- mode2 = &speex_wb_mode; ++ mode2 = speex_lib_get_mode (SPEEX_MODEID_WB); + +- mode3 = &speex_uwb_mode; ++ mode3 = speex_lib_get_mode (SPEEX_MODEID_UWB); + + Note that the constants SPEEX_MODEID_NB, SPEEX_MODEID_WB and + SPEEX_MODEID_UWB were introduced in libspeex 1.1.6, and are + defined in . speex_lib_get_mode() was introduced + in libspeex 1.1.7 and is declared in . diff --git a/native/codec/libraries/speex/README.win32 b/native/codec/libraries/speex/README.win32 new file mode 100644 index 0000000..51426b8 --- /dev/null +++ b/native/codec/libraries/speex/README.win32 @@ -0,0 +1,11 @@ +Win32 Specific options + +In order to enable the following options within Speex, you will need to manually edit the project options for the appropriate VC configuration. These macros can be specified by adding them as "Preprocessor Definitions" under the appropriate Configuration's project options. If you don't know how to do this, please check your Visual C documentation. + +Feature: + +Intel Streaming SIMD Extensions - SSE - macro: USE_SSE +Fixed point - macro: FIXED_POINT +Epic 48 - macro: EPIC_48K + +Note: USE_SSE and FIXED_POINT are mutually exclusive. diff --git a/native/codec/libraries/speex/Speex.kdevelop b/native/codec/libraries/speex/Speex.kdevelop new file mode 100644 index 0000000..1b3d683 --- /dev/null +++ b/native/codec/libraries/speex/Speex.kdevelop @@ -0,0 +1,201 @@ + + + + Jean-Marc Valin + jean-marc.valin@usherbrooke.ca + $VERSION$ + KDevAutoProject + C + + . + false + + + kdevsubversion + + Speex + + + + libspeex/libspeex.la + float + + + src/Speex + executable + / + + false + true + + false + false + + + + float + kdevgccoptions + kdevgppoptions + kdevpgf77options + -O2 -g -Wall + + --disable-shared + + + + + + + + + + + --enable-fixed-point --disable-shared + fixed + kdevgccoptions + kdevgppoptions + kdevpgf77options + -O2 -g -Wall + + + + + + + + + + + + + + + + + + + + false + 4 + false + + true + 0 + + + + + libtool + + + + + + true + false + false + + + false + true + 10 + + + + + + + + + + + + + true + true + true + false + true + true + true + 350 + 400 + 250 + false + 0 + true + true + false + std=_GLIBCXX_STD;__gnu_cxx=std + true + true + false + false + true + true + true + true + .; + false + false + + + false + 3 + /usr/share/qt3 + 3 + EmbeddedKDevDesigner + /usr/share/qt3/bin/qmake + /usr/bin/designer-qt3 + + + + + set + m_,_ + theValue + true + true + + + true + true + Horizontal + + + + + false + false + + + *.o,*.lo,CVS + true + false + + + + + html/ + html/ + + + + + + + + + + .h + .cpp + + + + + + + + + + diff --git a/native/codec/libraries/speex/Speex.spec.in b/native/codec/libraries/speex/Speex.spec.in new file mode 100644 index 0000000..bccfc23 --- /dev/null +++ b/native/codec/libraries/speex/Speex.spec.in @@ -0,0 +1,71 @@ +%define name @PACKAGE@ +%define ver @VERSION@ +%define rel 1 + +Summary: An open-source, patent-free speech codec +Name: %name +Version: %ver +Release: %rel +License: BSD +Group: Application/Devel +Source: http://www.speex.org/download/%{name}-%{ver}.tar.gz +URL: http://www.speex.org/ +Vendor: Speex +Packager: Jean-Marc Valin (jean-marc.valin@usherbrooke.ca) +BuildRoot: /var/tmp/%{name}-build-root +Docdir: /usr/share/doc + +%description +Speex is a patent-free audio codec designed especially for voice (unlike +Vorbis which targets general audio) signals and providing good narrowband +and wideband quality. This project aims to be complementary to the Vorbis +codec. + +%package devel +Summary: Speex development files +Group: Development/Libraries +Requires: %{name} = %{version} + +%description devel +Speex development files. + +%changelog +* Thu Oct 03 2002 Jean-Marc Valin +- Added devel package inspired from PLD spec file + +* Tue Jul 30 2002 Fredrik Rambris 0.5.2 +- Added buildroot and docdir and ldconfig. Makes it builadble by non-roots + and also doesn't write to actual library paths when building. + +%prep +%setup + +%build +export CFLAGS='-O3' +./configure --prefix=/usr --enable-shared --enable-static +make + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%defattr(644,root,root,755) +%doc COPYING AUTHORS ChangeLog NEWS README +%doc doc/manual.pdf +/usr/share/man/man1/speexenc.1* +/usr/share/man/man1/speexdec.1* +%attr(755,root,root) %{_bindir}/speex* +%attr(755,root,root) %{_libdir}/libspeex*.so* + +%files devel +%defattr(644,root,root,755) +%attr(755,root,root) %{_libdir}/libspeex*.la +%{_includedir}/speex/speex*.h +/usr/share/aclocal/speex.m4 +%{_libdir}/pkgconfig/speex.pc +%{_libdir}/pkgconfig/speexdsp.pc +%{_libdir}/libspeex*.a diff --git a/native/codec/libraries/speex/TODO b/native/codec/libraries/speex/TODO new file mode 100644 index 0000000..47be3f6 --- /dev/null +++ b/native/codec/libraries/speex/TODO @@ -0,0 +1,38 @@ +For 1.2: +Major points: +- Make documentation match the actual code +- Stabilise all APIs (need feedback) +- NaN checks? +- Better error reporting +- Make kiss-fft 32-bit safe + +Minor issues: +- Fix last frame of speexenc + + +Post 1.2: +improve float<->int conversion +split encoder and decoder? +Merge TriMedia stuff +packet dump +Do VAD properly + +Optimisations +- Add restrict in a few places? +- enable 4x4 version of pitch_xcorr() at least on some archs? +- use __builtin_expect() (likely()/unlikely()) + +Would be nice: +Implement wideband split as IIR instead of QMF? + +Allocator override (speex_lib_ctl?) +Fixed-point: + - VBR + +Standards +-Complete Speex RTP profile +-MIME type registration + +ideas: +Peelable stream (double codebook, higher bands, stereo) +LPC from spectral domain diff --git a/native/codec/libraries/speex/autogen.sh b/native/codec/libraries/speex/autogen.sh new file mode 100755 index 0000000..dc6f711 --- /dev/null +++ b/native/codec/libraries/speex/autogen.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Run this to set up the build system: configure, makefiles, etc. +set -e + +srcdir=`dirname $0` +test -n "$srcdir" && cd "$srcdir" + +echo "Updating build configuration files, please wait...." + +autoreconf -if + diff --git a/native/codec/libraries/speex/configure.ac b/native/codec/libraries/speex/configure.ac new file mode 100644 index 0000000..6188163 --- /dev/null +++ b/native/codec/libraries/speex/configure.ac @@ -0,0 +1,357 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- + +AC_INIT([speex],[1.2.0],[speex-dev@xiph.org]) + +AC_CONFIG_SRCDIR([libspeex/speex.c]) +AC_CONFIG_MACRO_DIR([m4]) + +dnl enable silent rules on automake 1.11 and later +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + + +SPEEX_MAJOR_VERSION=1 +SPEEX_MINOR_VERSION=1 +SPEEX_MICRO_VERSION=16 +SPEEX_EXTRA_VERSION= + +SPEEX_LT_CURRENT=6 +SPEEX_LT_REVISION=1 +SPEEX_LT_AGE=5 + + +AC_SUBST(SPEEX_LT_CURRENT) +AC_SUBST(SPEEX_LT_REVISION) +AC_SUBST(SPEEX_LT_AGE) + +AM_INIT_AUTOMAKE([foreign no-define]) +AM_MAINTAINER_MODE([enable]) + +AC_CANONICAL_HOST +AC_LIBTOOL_WIN32_DLL +AM_PROG_LIBTOOL + +AC_C_BIGENDIAN +AC_C_CONST +AC_C_INLINE +AC_C_RESTRICT + + +AC_MSG_CHECKING(for C99 variable-size arrays) +AC_TRY_COMPILE( , [ +int foo; +foo = 10; +int array[foo]; +], +[has_var_arrays=yes;AC_DEFINE([VAR_ARRAYS], [], [Use C99 variable-size arrays]) +], +has_var_arrays=no +) +AC_MSG_RESULT($has_var_arrays) + +AC_CHECK_HEADERS([alloca.h getopt.h]) +AC_MSG_CHECKING(for alloca) +AC_TRY_COMPILE( [ +#ifdef HAVE_ALLOCA_H +# include +#endif +#include +], [ +int foo=10; +int *array = alloca(foo); +], +[ +has_alloca=yes; +if test x$has_var_arrays = "xno" ; then +AC_DEFINE([USE_ALLOCA], [], [Make use of alloca]) +fi +], +has_alloca=no +) +AC_MSG_RESULT($has_alloca) + +AC_MSG_CHECKING(for SSE in current arch/CFLAGS) +AC_LINK_IFELSE([ +AC_LANG_PROGRAM([[ +#include +__m128 testfunc(float *a, float *b) { + return _mm_add_ps(_mm_loadu_ps(a), _mm_loadu_ps(b)); +} +]])], +[ +has_sse=yes +], +[ +has_sse=no +] +) +AC_MSG_RESULT($has_sse) + +SAVE_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING(for ELF visibility) +AC_COMPILE_IFELSE([ +AC_LANG_PROGRAM([[ +#pragma GCC visibility push(hidden) +__attribute__((visibility("default"))) +int var=10; +]])], +[ +has_visibility=yes +AC_DEFINE([EXPORT], [__attribute__((visibility("default")))], [Symbol visibility prefix]) +], +[ +has_visibility=no +AC_DEFINE([EXPORT], [], [Symbol visibility prefix]) +CFLAGS="$SAVE_CFLAGS" +] +) +AC_MSG_RESULT($has_visibility) + +AC_CHECK_HEADERS(sys/soundcard.h sys/audioio.h) + +LT_LIB_M + +# Check for getopt_long; if not found, use included source. +AC_CHECK_FUNCS([getopt_long],, +[# FreeBSD has a gnugetopt library. + AC_CHECK_LIB([gnugetopt],[getopt_long], +[AC_DEFINE([HAVE_GETOPT_LONG])], +[# Use the GNU replacement. +AC_LIBOBJ(getopt) +AC_LIBOBJ(getopt1)])]) + +SPEEX_VERSION=$PACKAGE_VERSION + +AC_SUBST(SPEEX_VERSION) + +AC_DEFINE_UNQUOTED(SPEEX_VERSION, "${PACKAGE_VERSION}", [Complete version string]) +AC_DEFINE_UNQUOTED(SPEEX_MAJOR_VERSION, ${SPEEX_MAJOR_VERSION}, [Version major]) +AC_DEFINE_UNQUOTED(SPEEX_MINOR_VERSION, ${SPEEX_MINOR_VERSION}, [Version minor]) +AC_DEFINE_UNQUOTED(SPEEX_MICRO_VERSION, ${SPEEX_MICRO_VERSION}, [Version micro]) +AC_DEFINE_UNQUOTED(SPEEX_EXTRA_VERSION, "${SPEEX_EXTRA_VERSION}", [Version extra]) + +AC_ARG_ENABLE(valgrind, [ --enable-valgrind Enable valgrind extra checks], +[if test "$enableval" = yes; then + AC_DEFINE([ENABLE_VALGRIND], , [Enable valgrind extra checks]) +fi]) + +AC_ARG_ENABLE(sse, [ --enable-sse Enable SSE support], [ +if test "x$enableval" != xno; then +has_sse=yes +CFLAGS="$CFLAGS -O3 -msse" +else +has_sse=no +fi +]) + + +FFT=smallft + +AC_ARG_ENABLE(fixed-point, [ --enable-fixed-point Compile as fixed-point], +[if test "$enableval" = yes; then + FFT=kiss + has_sse=no + AC_DEFINE([FIXED_POINT], , [Compile as fixed-point]) +else + AC_DEFINE([FLOATING_POINT], , [Compile as floating-point]) +fi], +AC_DEFINE([FLOATING_POINT], , [Compile as floating-point])) + +if test "$has_sse" = yes; then + AC_DEFINE([_USE_SSE], , [Enable SSE support]) +fi + +AC_ARG_ENABLE(float-api, [ --disable-float-api Disable the floating-point API], +[if test "$enableval" = no; then + AC_DEFINE([DISABLE_FLOAT_API], , [Disable all parts of the API that are using floats]) +fi]) + +AC_ARG_ENABLE(binaries, [ --disable-binaries Do not build the encoder and decoder programs, only the library]) +AS_IF([test "x$enable_binaries" != "xno"], [ + PKG_CHECK_MODULES([OGG], [ogg], + AM_CONDITIONAL([BUILD_BINARIES], true), + [AC_MSG_WARN([Ogg not found, not building example programs]) + AM_CONDITIONAL([BUILD_BINARIES], false)])], + [AM_CONDITIONAL([BUILD_BINARIES], false)]) + +AC_ARG_ENABLE(vbr, [ --disable-vbr Disable VBR and VAD from the codec], +[if test "$enableval" = no; then + AC_DEFINE([DISABLE_VBR], , [Disable VBR and VAD from the codec]) +fi]) + +AC_ARG_ENABLE(arm4-asm, [ --enable-arm4-asm Make use of ARM4 assembly optimizations], +[if test "$enableval" = yes; then + AC_DEFINE([ARM4_ASM], , [Make use of ARM4 assembly optimizations]) +fi]) + +AC_ARG_ENABLE(arm5e-asm, [ --enable-arm5e-asm Make use of ARM5E assembly optimizations], +[if test "$enableval" = yes; then + AC_DEFINE([ARM5E_ASM], , [Make use of ARM5E assembly optimizations]) +fi]) + +AC_ARG_ENABLE(blackfin-asm, [ --enable-blackfin-asm Make use of Blackfin assembly optimizations], +[if test "$enableval" = yes; then + AC_DEFINE([BFIN_ASM], , [Make use of Blackfin assembly optimizations]) +fi]) +WINMM_LIBS="" +case $host_os in + uclinux) LDFLAGS="-Wl,-elf2flt=-s100000 $LDFLAGS";; + *mingw*) WINMM_LIBS="-lwinmm";; +esac +AC_SUBST(WINMM_LIBS) + +AC_ARG_ENABLE(fixed-point-debug, [ --enable-fixed-point-debug Debug fixed-point implementation], +[if test "$enableval" = yes; then + AC_DEFINE([FIXED_DEBUG], , [Debug fixed-point implementation]) +fi]) + +AC_ARG_ENABLE(ti-c55x, [ --enable-ti-c55x Enable support for TI C55X DSP], +[if test "$enableval" = yes; then + has_char16=yes; + AC_DEFINE([TI_C55X], , [Enable support for TI C55X DSP]) +fi]) + +AC_ARG_ENABLE(vorbis-psy, [ --enable-vorbis-psy Enable the Vorbis psy model], +[if test "$enableval" = yes; then + vorbis_psy=yes; + AC_DEFINE([VORBIS_PSYCHO], , [Enable support for the Vorbis psy model]) +fi]) + +AC_ARG_WITH([fft], [AS_HELP_STRING([--with-fft=choice],[use an alternate FFT implementation. The available choices are +kiss (default fixed point), smallft (default floating point), gpl-fftw3 and proprietary-intel-mkl])], +[FFT=$withval] +) + +FFT_PKGCONFIG= +AS_CASE([$FFT], + [kiss], [ + AC_DEFINE([USE_KISS_FFT], [], [Use KISS Fast Fourier Transform]) + ], + [smallft], [ + AC_DEFINE([USE_SMALLFT], [], [Use FFT from OggVorbis]) + ], + [gpl-fftw3], [ + AC_DEFINE([USE_GPL_FFTW3], [], [Use FFTW3 for FFT]) + PKG_CHECK_MODULES([FFT], [fftw3f]) + ], + [proprietary-intel-mkl], [ + AC_DEFINE([USE_INTEL_MKL], [], [Use Intel Math Kernel Library for FFT]) + AC_MSG_CHECKING(for valid MKL) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#include +void func() { + DFTI_DESCRIPTOR_HANDLE h; + MKL_LONG result=DftiCreateDescriptor(&h, DFTI_SINGLE, DFTI_REAL, 0); +}]])], + [AC_MSG_RESULT(yes)], + [AC_MSG_FAILURE([Failed to compile MKL test program. Make sure you set CFLAGS to include the include directory and set LDFLAGS to include the library directory and all necesarry libraries.])] + ) + ], + [AC_MSG_FAILURE([Unknown FFT $FFT specified for --with-fft])] +) +AM_CONDITIONAL(BUILD_KISS_FFT, [test "$FFT" = "kiss"]) +AM_CONDITIONAL(BUILD_SMALLFT, [test "$FFT" = "smallft"]) +AC_SUBST(FFT_PKGCONFIG) + +AM_CONDITIONAL(BUILD_VORBIS_PSY, [test "x$vorbis_psy" = "xyes"]) + +PKG_CHECK_MODULES([SPEEXDSP], [speexdsp], [AC_DEFINE([USE_SPEEXDSP], [], [Use SpeexDSP library])], [speexdsp_failed=yes]) + + +AC_CHECK_SIZEOF([int16_t]) +AC_CHECK_SIZEOF([uint16_t]) +AC_CHECK_SIZEOF([u_int16_t]) +AC_CHECK_SIZEOF([int32_t]) +AC_CHECK_SIZEOF([uint32_t]) +AC_CHECK_SIZEOF([u_int32_t]) +AC_CHECK_SIZEOF([short]) +AC_CHECK_SIZEOF([int]) +AC_CHECK_SIZEOF([long]) + +AS_IF([test "$has_char16" = "yes"], + [ + SIZEOF16=1 + SIZEOF32=2 + ],[ + SIZEOF16=2 + SIZEOF32=4 + ]) + +case $SIZEOF16 in + $ac_cv_sizeof_int16_t) SIZE16="int16_t";; + $ac_cv_sizeof_short) SIZE16="short";; + $ac_cv_sizeof_int) SIZE16="int";; +esac + +case $SIZEOF16 in + $ac_cv_sizeof_uint16_t) USIZE16="uint16_t";; + $ac_cv_sizeof_u_int16_t) USIZE16="u_int16_t";; + $ac_cv_sizeof_short) USIZE16="unsigned short";; + $ac_cv_sizeof_int) USIZE16="unsigned int";; +esac + +case $SIZEOF32 in + $ac_cv_sizeof_int32_t) SIZE32="int32_t";; + $ac_cv_sizeof_int) SIZE32="int";; + $ac_cv_sizeof_long) SIZE32="long";; + $ac_cv_sizeof_short) SIZE32="short";; +esac + +case $SIZEOF32 in + $ac_cv_sizeof_uint32_t) USIZE32="uint32_t";; + $ac_cv_sizeof_u_int32_t) USIZE32="u_int32_t";; + $ac_cv_sizeof_short) USIZE32="unsigned short";; + $ac_cv_sizeof_int) USIZE32="unsigned int";; + $ac_cv_sizeof_long) USIZE32="unsigned long";; +esac + +XIPH_ADD_CFLAGS([-Wall]) + +AS_IF([test -z "$SIZE16"],[AC_MSG_ERROR([No 16 bit type found on this platform!])]) +AS_IF([test -z "$SIZE32"],[AC_MSG_ERROR([No 32 bit type found on this platform!])]) +AS_IF([test -z "$USIZE16"],[AC_MSG_ERROR([No unsigned 16 bit type found on this platform!])]) +AS_IF([test -z "$USIZE32"],[AC_MSG_ERROR([No unsigned 32 bit type found on this platform!])]) + +AC_SUBST([SIZE16]) +AC_SUBST([USIZE16]) +AC_SUBST([SIZE32]) +AC_SUBST([USIZE32]) + +AS_IF([test "$ac_cv_header_stdint_h" = "yes"], [INCLUDE_STDINT="#include "], + [test "$ac_cv_header_inttypes_h" = "yes"], [INCLUDE_STDINT="#include "], + [test "$ac_cv_header_sys_types_h" = "yes"], [INCLUDE_STDINT="#include "]) + +AC_SUBST([INCLUDE_STDINT]) + + +AC_CONFIG_FILES([ + Makefile libspeex/Makefile src/Makefile doc/Makefile Speex.spec + include/Makefile include/speex/Makefile speex.pc + win32/Makefile win32/libspeex/Makefile win32/speexenc/Makefile + win32/speexdec/Makefile symbian/Makefile + win32/VS2003/Makefile + win32/VS2003/tests/Makefile + win32/VS2003/libspeex/Makefile + win32/VS2003/speexdec/Makefile + win32/VS2003/speexenc/Makefile + win32/VS2005/Makefile + win32/VS2005/libspeex/Makefile + win32/VS2005/speexdec/Makefile + win32/VS2005/speexenc/Makefile + win32/VS2005/tests/Makefile + win32/VS2008/Makefile + win32/VS2008/speexdec/Makefile + win32/VS2008/tests/Makefile + win32/VS2008/libspeex/Makefile + win32/VS2008/speexenc/Makefile + include/speex/speex_config_types.h ti/Makefile + ti/speex_C54_test/Makefile ti/speex_C55_test/Makefile + ti/speex_C64_test/Makefile +]) + +AC_CONFIG_HEADERS([config.h]) + +AC_OUTPUT + +echo "Type \"make; make install\" to compile and install Speex"; diff --git a/native/codec/libraries/speex/doc/.cvsignore b/native/codec/libraries/speex/doc/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/native/codec/libraries/speex/doc/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/native/codec/libraries/speex/doc/Makefile.am b/native/codec/libraries/speex/doc/Makefile.am new file mode 100644 index 0000000..d2896ef --- /dev/null +++ b/native/codec/libraries/speex/doc/Makefile.am @@ -0,0 +1,3 @@ +doc_DATA = manual.pdf + +EXTRA_DIST = $(doc_DATA) diff --git a/native/codec/libraries/speex/doc/celp_decoder.eps b/native/codec/libraries/speex/doc/celp_decoder.eps new file mode 100644 index 0000000..87f0704 --- /dev/null +++ b/native/codec/libraries/speex/doc/celp_decoder.eps @@ -0,0 +1,688 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 0 0 442 315 +%%Pages: 0 +%%Creator: Sun Microsystems, Inc. +%%Title: none +%%CreationDate: none +%%LanguageLevel: 2 +%%EndComments +%%BeginProlog +%%BeginResource: SDRes +/b4_inc_state save def +/dict_count countdictstack def +/op_count count 1 sub def +userdict begin +0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath +/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if +/bdef {bind def} bind def +/c {setgray} bdef +/l {neg lineto} bdef +/rl {neg rlineto} bdef +/lc {setlinecap} bdef +/lj {setlinejoin} bdef +/lw {setlinewidth} bdef +/ml {setmiterlimit} bdef +/ld {setdash} bdef +/m {neg moveto} bdef +/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef +/r {rotate} bdef +/t {neg translate} bdef +/s {scale} bdef +/sw {show} bdef +/gs {gsave} bdef +/gr {grestore} bdef +/f {findfont dup length dict begin +{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def +currentdict end /NFont exch definefont pop /NFont findfont} bdef +/p {closepath} bdef +/sf {scalefont setfont} bdef +/ef {eofill}bdef +/pc {closepath stroke}bdef +/ps {stroke}bdef +/pum {matrix currentmatrix}bdef +/pom {setmatrix}bdef +/bs {/aString exch def /nXOfs exch def /nWidth exch def currentpoint nXOfs 0 rmoveto pum nWidth aString stringwidth pop div 1 scale aString show pom moveto} bdef +%%EndResource +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%EndPageSetup +pum +0.02836 0.02834 s +0 -11113 t +/tm matrix currentmatrix def +tm setmatrix +-5152 -9418 t +1 1 s +0 lw 1 lj 0.000 c 6935 14318 m 5435 14318 l 5435 10318 l 8435 10318 l +8435 14318 l 6935 14318 l pc +11436 12317 m 10934 12818 l 10936 11817 l 11436 12317 l pc +5831 11966 m 8109 11966 l ps +6425 11966 m 6425 11636 l ps +6123 11966 m 6123 12366 l ps +6727 11966 m 6727 11707 l ps +7719 11966 m 7719 11872 l ps +7070 11966 m 7070 12248 l ps +7439 11966 m 7439 11636 l ps +5830 10920 m 8108 10920 l ps +6163 10920 m 6163 10590 l ps +6470 10920 m 6470 11320 l ps +6726 10920 m 6726 10661 l ps +7109 10920 m 7109 10826 l ps +7417 10920 m 7417 11202 l ps +7699 10920 m 7699 10590 l ps +5831 10921 m 8109 10921 l ps +6164 10921 m 6164 10591 l ps +6471 10921 m 6471 11321 l ps +6727 10921 m 6727 10662 l ps +7110 10921 m 7110 10827 l ps +7418 10921 m 7418 11203 l ps +7700 10921 m 7700 10591 l ps +5857 12918 m 8135 12918 l ps +6190 12918 m 6188 12729 l ps +6497 12918 m 6497 13318 l ps +6753 12918 m 6751 13247 l ps +7136 12918 m 7136 12824 l ps +7444 12918 m 7442 12611 l ps +7796 12919 m 7794 13248 l ps +6935 17818 m 5435 17818 l 5435 15818 l 8435 15818 l 8435 17818 l 6935 17818 l +pc +gs +pum +6263 17039 t +219 -104 m 214 -66 184 -39 147 -39 ct 120 -39 99 -51 85 -74 ct 74 -92 71 -110 69 -147 ct +268 -147 l 266 -213 260 -244 245 -277 ct 224 -321 193 -341 149 -341 ct 71 -341 20 -271 20 -160 ct +20 -55 68 9 146 9 ct 208 9 252 -32 264 -104 ct 219 -104 l p +69 -192 m 72 -252 104 -292 147 -292 ct 171 -292 191 -280 203 -260 ct 214 -243 218 -226 220 -192 ct +69 -192 l p ef +362 -412 m 418 -412 l 418 -458 l 321 -458 l 321 124 l 418 124 l 418 78 l +362 78 l 362 -412 l p ef +508 -332 m 465 -332 l 465 0 l 511 0 l 511 -180 l 511 -250 539 -292 586 -292 ct +625 -292 642 -265 642 -204 ct 642 0 l 687 0 l 687 -226 l 687 -299 653 -341 595 -341 ct +558 -341 532 -324 508 -283 ct 508 -332 l p ef +870 -204 m 742 -204 l 742 -147 l 870 -147 l 870 -204 l p ef +899 -400 m 1026 -400 l 1026 0 l 1077 0 l 1077 -400 l 1204 -400 l +1204 -455 l 899 -455 l 899 -400 l p ef +1281 78 m 1225 78 l 1225 124 l 1322 124 l 1322 -458 l 1225 -458 l +1225 -412 l 1281 -412 l 1281 78 l p ef +pom +gr +10410 12492 m 10410 12142 l 10935 12317 l 10410 12492 l p ef +1 lw 0 lj 8435 12318 m 9685 12318 l 9685 12317 l 10515 12317 l ps +0 lw 1 lj 11434 16817 m 10932 17318 l 10934 16317 l 11434 16817 l pc +10483 16967 m 10483 16667 l 10933 16817 l 10483 16967 l p ef +1 lw 0 lj 8435 16818 m 9684 16818 l 9684 16817 l 10573 16817 l ps +0 lw 1 lj 13085 14818 m 12947 14818 12835 14706 12835 14568 ct 12835 14430 12947 14318 13085 14318 ct +13223 14318 13335 14430 13335 14568 ct 13335 14706 13223 14818 13085 14818 ct +pc +gs +pum +12931 14791 t +133 -183 m 20 -183 l 20 -137 l 133 -137 l 133 0 l 171 0 l 171 -137 l +283 -137 l 283 -183 l 171 -183 l 171 -320 l 133 -320 l 133 -183 l +p ef +pom +gr +13234 15268 m 12934 15268 l 13084 14818 l 13234 15268 l p ef +1 lw 0 lj 11435 16817 m 13084 16817 l 13084 15178 l ps +12934 13868 m 13234 13868 l 13084 14318 l 12934 13868 l p ef +11437 12317 m 13084 12317 l 13084 13958 l ps +0 lw 1 lj 17835 15318 m 16335 15318 l 16335 13818 l 19335 13818 l 19335 15318 l +17835 15318 l pc +16668 15023 m 16778 14801 16891 14569 16925 14316 ct 16997 13766 17307 14273 17221 14551 ct +17165 14731 17523 15058 17694 14622 ct 17856 14213 18050 14912 18286 15000 ct +18489 15075 18680 14999 18878 15000 ct 18878 15000 18878 15000 19076 15047 ct +19076 15047 19076 15047 19135 15118 ct ps +15885 14718 m 15885 14418 l 16335 14568 l 15885 14718 l p ef +1 lw 0 lj 13335 14567 m 14935 14567 l 14935 14568 l 15975 14568 l ps +gs +pum +17085 13052 t +208 -214 m 206 -241 203 -254 195 -269 ct 180 -296 151 -311 114 -311 ct 84 -311 61 -302 46 -283 ct +33 -266 25 -243 25 -219 ct 25 -180 43 -156 78 -146 ct 129 -131 l 170 -120 182 -108 182 -79 ct +182 -46 158 -27 118 -27 ct 90 -27 69 -37 58 -56 ct 51 -68 49 -78 48 -98 ct 16 -98 l +17 -65 22 -48 35 -30 ct 54 -3 78 8 116 8 ct 177 8 214 -26 214 -83 ct 214 -126 195 -154 158 -164 ct +87 -184 l 67 -190 57 -202 57 -224 ct 57 -257 78 -276 114 -276 ct 137 -276 156 -267 166 -250 ct +172 -240 175 -231 176 -214 ct 208 -214 l p ef +319 -39 m 271 -221 l 236 -221 l 304 5 l 300 16 297 25 296 28 ct 289 51 284 57 271 57 ct +265 57 259 55 253 53 ct 253 87 l 255 87 l 261 90 263 90 268 90 ct 304 90 309 83 337 -4 ct +402 -221 l 368 -221 l 319 -39 l p ef +457 -221 m 428 -221 l 428 0 l 458 0 l 458 -120 l 458 -166 477 -194 508 -194 ct +534 -194 546 -176 546 -136 ct 546 0 l 576 0 l 576 -150 l 576 -199 553 -227 515 -227 ct +490 -227 472 -216 457 -188 ct 457 -221 l p ef +690 -190 m 690 -221 l 660 -221 l 660 -282 l 630 -282 l 630 -221 l +605 -221 l 605 -190 l 630 -190 l 630 -44 l 630 -12 641 2 665 2 ct 667 2 669 2 676 1 ct +678 1 683 0 689 0 ct 689 -29 l 679 -29 l 665 -29 660 -34 660 -46 ct 660 -190 l +690 -190 l p ef +751 -303 m 721 -303 l 721 0 l 751 0 l 751 -120 l 751 -167 770 -194 803 -194 ct +828 -194 839 -179 839 -144 ct 839 0 l 869 0 l 869 -150 l 869 -199 846 -227 808 -227 ct +784 -227 769 -218 751 -190 ct 751 -303 l p ef +1038 -69 m 1035 -44 1015 -26 991 -26 ct 973 -26 958 -34 950 -49 ct 942 -61 940 -73 939 -98 ct +1071 -98 l 1070 -142 1066 -162 1056 -184 ct 1042 -214 1022 -227 992 -227 ct +940 -227 906 -180 906 -106 ct 906 -36 938 6 990 6 ct 1032 6 1061 -21 1069 -69 ct +1038 -69 l p +939 -128 m 941 -167 962 -194 991 -194 ct 1007 -194 1020 -186 1028 -173 ct 1035 -162 1038 -151 1040 -128 ct +939 -128 l p ef +1242 -158 m 1240 -202 1215 -227 1174 -227 ct 1132 -227 1104 -200 1104 -157 ct +1104 -129 1118 -111 1146 -103 ct 1182 -92 l 1210 -84 1218 -77 1218 -60 ct 1218 -39 1202 -26 1175 -26 ct +1144 -26 1130 -39 1128 -71 ct 1099 -71 l 1100 -49 1102 -38 1108 -27 ct 1120 -5 1143 6 1173 6 ct +1219 6 1248 -22 1248 -66 ct 1248 -97 1234 -113 1197 -125 ct 1167 -134 l 1140 -142 1134 -148 1134 -163 ct +1134 -183 1148 -195 1172 -195 ct 1198 -195 1211 -183 1213 -158 ct 1242 -158 l +p ef +1315 -221 m 1285 -221 l 1285 0 l 1315 0 l 1315 -221 l p +1315 -261 m 1315 -303 l 1285 -303 l 1285 -261 l 1315 -261 l p ef +1492 -158 m 1490 -202 1465 -227 1424 -227 ct 1382 -227 1354 -200 1354 -157 ct +1354 -129 1368 -111 1396 -103 ct 1432 -92 l 1460 -84 1468 -77 1468 -60 ct 1468 -39 1452 -26 1425 -26 ct +1394 -26 1380 -39 1378 -71 ct 1349 -71 l 1350 -49 1352 -38 1358 -27 ct 1370 -5 1393 6 1423 6 ct +1469 6 1498 -22 1498 -66 ct 1498 -97 1484 -113 1447 -125 ct 1417 -134 l 1390 -142 1384 -148 1384 -163 ct +1384 -183 1398 -195 1422 -195 ct 1448 -195 1461 -183 1463 -158 ct 1492 -158 l +p ef +pom +pum +17085 13581 t +90 -190 m 90 -221 l 60 -221 l 60 -248 l 60 -266 65 -274 78 -274 ct 81 -274 85 -274 90 -273 ct +90 -307 l 81 -307 79 -307 76 -307 ct 46 -307 30 -291 30 -259 ct 30 -221 l 4 -221 l +4 -190 l 30 -190 l 30 0 l 60 0 l 60 -190 l 90 -190 l p ef +150 -221 m 120 -221 l 120 0 l 150 0 l 150 -221 l p +150 -261 m 150 -303 l 120 -303 l 120 -261 l 150 -261 l p ef +227 -303 m 197 -303 l 197 0 l 227 0 l 227 -303 l p ef +339 -190 m 339 -221 l 309 -221 l 309 -282 l 279 -282 l 279 -221 l +254 -221 l 254 -190 l 279 -190 l 279 -44 l 279 -12 290 2 314 2 ct 316 2 318 2 325 1 ct +327 1 332 0 338 0 ct 338 -29 l 328 -29 l 314 -29 309 -34 309 -46 ct 309 -190 l +339 -190 l p ef +492 -69 m 489 -44 469 -26 445 -26 ct 427 -26 412 -34 404 -49 ct 396 -61 394 -73 393 -98 ct +525 -98 l 524 -142 520 -162 510 -184 ct 496 -214 476 -227 446 -227 ct 394 -227 360 -180 360 -106 ct +360 -36 392 6 444 6 ct 486 6 515 -21 523 -69 ct 492 -69 l p +393 -128 m 395 -167 416 -194 445 -194 ct 461 -194 474 -186 482 -173 ct 489 -162 492 -151 494 -128 ct +393 -128 l p ef +657 -188 m 657 -226 l 654 -227 651 -227 649 -227 ct 627 -227 613 -215 597 -183 ct +597 -221 l 568 -221 l 568 0 l 599 0 l 599 -129 l 599 -163 618 -188 645 -188 ct +657 -188 l p ef +878 -297 m 854 -297 l 844 -253 834 -244 789 -240 ct 789 -211 l 845 -211 l +845 0 l 878 0 l 878 -297 l p ef +1050 -311 m 1027 -311 l 943 8 l 965 8 l 1050 -311 l p ef +1211 -88 m 1235 0 l 1272 0 l 1182 -303 l 1144 -303 l 1050 0 l 1085 0 l +1111 -88 l 1211 -88 l p +1121 -125 m 1161 -259 l 1199 -125 l 1121 -125 l p ef +1360 -310 m 1316 -231 1301 -179 1301 -110 ct 1301 -42 1314 1 1361 87 ct 1381 87 l +1343 -5 1334 -42 1334 -107 ct 1334 -182 1344 -225 1381 -310 ct 1360 -310 l p ef +1552 -190 m 1552 -221 l 1412 -221 l 1412 -190 l 1513 -190 l 1403 -29 l +1403 0 l 1555 0 l 1555 -30 l 1444 -30 l 1552 -190 l p ef +1599 87 m 1642 8 1657 -43 1657 -111 ct 1657 -179 1644 -223 1598 -310 ct 1577 -310 l +1616 -217 1625 -179 1625 -115 ct 1625 -40 1615 2 1578 87 ct 1599 87 l p ef +pom +gr +gs +pum +5708 9956 t +63 -137 m 185 -137 l 185 -174 l 63 -174 l 63 -266 l 202 -266 l 202 -303 l +30 -303 l 30 0 l 63 0 l 63 -137 l p ef +265 -221 m 235 -221 l 235 0 l 265 0 l 265 -221 l p +265 -261 m 265 -303 l 235 -303 l 235 -261 l 265 -261 l p ef +394 -113 m 455 -221 l 418 -221 l 375 -143 l 334 -221 l 294 -221 l +355 -113 l 291 0 l 330 0 l 373 -83 l 419 0 l 458 0 l 394 -113 l +p ef +606 -69 m 603 -44 583 -26 559 -26 ct 541 -26 526 -34 518 -49 ct 510 -61 508 -73 507 -98 ct +639 -98 l 638 -142 634 -162 624 -184 ct 610 -214 590 -227 560 -227 ct 508 -227 474 -180 474 -106 ct +474 -36 506 6 558 6 ct 600 6 629 -21 637 -69 ct 606 -69 l p +507 -128 m 509 -167 530 -194 559 -194 ct 575 -194 588 -186 596 -173 ct 603 -162 606 -151 608 -128 ct +507 -128 l p ef +829 -303 m 798 -303 l 798 -187 l 784 -216 768 -227 743 -227 ct 698 -227 668 -182 668 -115 ct +668 -41 699 6 747 6 ct 772 6 787 -4 800 -31 ct 800 0 l 829 0 l 829 -303 l +p +749 -194 m 780 -194 798 -162 798 -104 ct 798 -76 793 -57 782 -43 ct 773 -32 761 -26 748 -26 ct +717 -26 699 -58 699 -113 ct 699 -167 716 -194 749 -194 ct p ef +1113 -146 m 1107 -200 1085 -227 1044 -227 ct 991 -227 958 -180 958 -106 ct +958 -37 990 6 1039 6 ct 1081 6 1106 -22 1113 -78 ct 1083 -78 l 1077 -43 1062 -26 1039 -26 ct +1008 -26 991 -56 991 -109 ct 991 -163 1009 -194 1041 -194 ct 1065 -194 1078 -180 1083 -146 ct +1113 -146 l p ef +1219 -227 m 1168 -227 1134 -180 1134 -110 ct 1134 -41 1168 5 1218 5 ct 1268 5 1302 -41 1302 -110 ct +1302 -178 1268 -227 1219 -227 ct p +1219 -195 m 1250 -195 1270 -161 1270 -110 ct 1270 -59 1250 -26 1218 -26 ct +1186 -26 1165 -59 1165 -110 ct 1165 -162 1186 -195 1219 -195 ct p ef +1490 -303 m 1459 -303 l 1459 -187 l 1445 -216 1429 -227 1404 -227 ct 1359 -227 1329 -182 1329 -115 ct +1329 -41 1360 6 1408 6 ct 1433 6 1448 -4 1461 -31 ct 1461 0 l 1490 0 l 1490 -303 l +p +1410 -194 m 1441 -194 1459 -162 1459 -104 ct 1459 -76 1454 -57 1443 -43 ct +1434 -32 1422 -26 1409 -26 ct 1378 -26 1360 -58 1360 -113 ct 1360 -167 1377 -194 1410 -194 ct +p ef +1656 -69 m 1653 -44 1633 -26 1609 -26 ct 1591 -26 1576 -34 1568 -49 ct 1560 -61 1558 -73 1557 -98 ct +1689 -98 l 1688 -142 1684 -162 1674 -184 ct 1660 -214 1640 -227 1610 -227 ct +1558 -227 1524 -180 1524 -106 ct 1524 -36 1556 6 1608 6 ct 1650 6 1679 -21 1687 -69 ct +1656 -69 l p +1557 -128 m 1559 -167 1580 -194 1609 -194 ct 1625 -194 1638 -186 1646 -173 ct +1653 -162 1656 -151 1658 -128 ct 1557 -128 l p ef +1755 0 m 1755 -28 l 1768 -3 1782 6 1806 6 ct 1854 6 1885 -41 1885 -115 ct +1885 -182 1855 -227 1810 -227 ct 1788 -227 1772 -217 1756 -192 ct 1756 -303 l +1726 -303 l 1726 0 l 1755 0 l p +1805 -194 m 1837 -194 1853 -167 1853 -113 ct 1853 -58 1835 -26 1804 -26 ct +1792 -26 1780 -32 1771 -43 ct 1760 -57 1755 -76 1755 -105 ct 1755 -163 1772 -194 1805 -194 ct +p ef +1998 -227 m 1947 -227 1913 -180 1913 -110 ct 1913 -41 1947 5 1997 5 ct 2047 5 2081 -41 2081 -110 ct +2081 -178 2047 -227 1998 -227 ct p +1998 -195 m 2029 -195 2049 -161 2049 -110 ct 2049 -59 2029 -26 1997 -26 ct +1965 -26 1944 -59 1944 -110 ct 1944 -162 1965 -195 1998 -195 ct p ef +2193 -227 m 2142 -227 2108 -180 2108 -110 ct 2108 -41 2142 5 2192 5 ct 2242 5 2276 -41 2276 -110 ct +2276 -178 2242 -227 2193 -227 ct p +2193 -195 m 2224 -195 2244 -161 2244 -110 ct 2244 -59 2224 -26 2192 -26 ct +2160 -26 2139 -59 2139 -110 ct 2139 -162 2160 -195 2193 -195 ct p ef +2390 -138 m 2459 -221 l 2421 -221 l 2342 -127 l 2342 -303 l 2313 -303 l +2313 0 l 2342 0 l 2342 -83 l 2368 -111 l 2424 0 l 2463 0 l 2390 -138 l +p ef +pom +gr +gs +pum +5390 15539 t +165 -88 m 189 0 l 226 0 l 136 -303 l 98 -303 l 4 0 l 39 0 l 65 -88 l +165 -88 l p +75 -125 m 115 -259 l 153 -125 l 75 -125 l p ef +406 -303 m 375 -303 l 375 -187 l 361 -216 345 -227 320 -227 ct 275 -227 245 -182 245 -115 ct +245 -41 276 6 324 6 ct 349 6 364 -4 377 -31 ct 377 0 l 406 0 l 406 -303 l +p +326 -194 m 357 -194 375 -162 375 -104 ct 375 -76 370 -57 359 -43 ct 350 -32 338 -26 325 -26 ct +294 -26 276 -58 276 -113 ct 276 -167 293 -194 326 -194 ct p ef +477 -153 m 481 -184 493 -196 520 -196 ct 547 -196 562 -184 562 -159 ct 562 -143 557 -136 546 -134 ct +495 -126 l 460 -121 440 -96 440 -58 ct 440 -19 463 6 498 6 ct 524 6 543 -4 562 -29 ct +565 -5 573 4 594 4 ct 598 4 602 3 608 1 ct 610 0 610 0 612 0 ct 612 -27 l 605 -25 603 -25 601 -25 ct +595 -25 591 -30 591 -38 ct 591 -165 l 591 -204 565 -227 522 -227 ct 493 -227 472 -217 460 -198 ct +453 -186 450 -175 449 -153 ct 477 -153 l p +561 -76 m 561 -48 535 -24 504 -24 ct 484 -24 472 -38 472 -61 ct 472 -83 483 -94 511 -98 ct +546 -104 554 -107 561 -112 ct 561 -76 l p ef +642 87 m 672 87 l 672 -24 l 685 -2 699 6 722 6 ct 770 6 801 -42 801 -115 ct +801 -182 771 -227 726 -227 ct 701 -227 687 -217 671 -188 ct 671 -221 l 642 -221 l +642 87 l p +721 -194 m 752 -194 769 -166 769 -114 ct 769 -58 751 -26 720 -26 ct 690 -26 671 -55 671 -103 ct +671 -163 688 -194 721 -194 ct p ef +906 -190 m 906 -221 l 876 -221 l 876 -282 l 846 -282 l 846 -221 l +821 -221 l 821 -190 l 846 -190 l 846 -44 l 846 -12 857 2 881 2 ct 883 2 885 2 892 1 ct +894 1 899 0 905 0 ct 905 -29 l 895 -29 l 881 -29 876 -34 876 -46 ct 876 -190 l +906 -190 l p ef +967 -221 m 937 -221 l 937 0 l 967 0 l 967 -221 l p +967 -261 m 967 -303 l 937 -303 l 937 -261 l 967 -261 l p ef +1076 -39 m 1029 -221 l 993 -221 l 1059 0 l 1092 0 l 1161 -221 l 1128 -221 l +1076 -39 l p ef +1309 -69 m 1306 -44 1286 -26 1262 -26 ct 1244 -26 1229 -34 1221 -49 ct 1213 -61 1211 -73 1210 -98 ct +1342 -98 l 1341 -142 1337 -162 1327 -184 ct 1313 -214 1293 -227 1263 -227 ct +1211 -227 1177 -180 1177 -106 ct 1177 -36 1209 6 1261 6 ct 1303 6 1332 -21 1340 -69 ct +1309 -69 l p +1210 -128 m 1212 -167 1233 -194 1262 -194 ct 1278 -194 1291 -186 1299 -173 ct +1306 -162 1309 -151 1311 -128 ct 1210 -128 l p ef +1621 -146 m 1615 -200 1593 -227 1552 -227 ct 1499 -227 1466 -180 1466 -106 ct +1466 -37 1498 6 1547 6 ct 1589 6 1614 -22 1621 -78 ct 1591 -78 l 1585 -43 1570 -26 1547 -26 ct +1516 -26 1499 -56 1499 -109 ct 1499 -163 1517 -194 1549 -194 ct 1573 -194 1586 -180 1591 -146 ct +1621 -146 l p ef +1727 -227 m 1676 -227 1642 -180 1642 -110 ct 1642 -41 1676 5 1726 5 ct 1776 5 1810 -41 1810 -110 ct +1810 -178 1776 -227 1727 -227 ct p +1727 -195 m 1758 -195 1778 -161 1778 -110 ct 1778 -59 1758 -26 1726 -26 ct +1694 -26 1673 -59 1673 -110 ct 1673 -162 1694 -195 1727 -195 ct p ef +1998 -303 m 1967 -303 l 1967 -187 l 1953 -216 1937 -227 1912 -227 ct 1867 -227 1837 -182 1837 -115 ct +1837 -41 1868 6 1916 6 ct 1941 6 1956 -4 1969 -31 ct 1969 0 l 1998 0 l 1998 -303 l +p +1918 -194 m 1949 -194 1967 -162 1967 -104 ct 1967 -76 1962 -57 1951 -43 ct +1942 -32 1930 -26 1917 -26 ct 1886 -26 1868 -58 1868 -113 ct 1868 -167 1885 -194 1918 -194 ct +p ef +2164 -69 m 2161 -44 2141 -26 2117 -26 ct 2099 -26 2084 -34 2076 -49 ct 2068 -61 2066 -73 2065 -98 ct +2197 -98 l 2196 -142 2192 -162 2182 -184 ct 2168 -214 2148 -227 2118 -227 ct +2066 -227 2032 -180 2032 -106 ct 2032 -36 2064 6 2116 6 ct 2158 6 2187 -21 2195 -69 ct +2164 -69 l p +2065 -128 m 2067 -167 2088 -194 2117 -194 ct 2133 -194 2146 -186 2154 -173 ct +2161 -162 2164 -151 2166 -128 ct 2065 -128 l p ef +2263 0 m 2263 -28 l 2276 -3 2290 6 2314 6 ct 2362 6 2393 -41 2393 -115 ct +2393 -182 2363 -227 2318 -227 ct 2296 -227 2280 -217 2264 -192 ct 2264 -303 l +2234 -303 l 2234 0 l 2263 0 l p +2313 -194 m 2345 -194 2361 -167 2361 -113 ct 2361 -58 2343 -26 2312 -26 ct +2300 -26 2288 -32 2279 -43 ct 2268 -57 2263 -76 2263 -105 ct 2263 -163 2280 -194 2313 -194 ct +p ef +2506 -227 m 2455 -227 2421 -180 2421 -110 ct 2421 -41 2455 5 2505 5 ct 2555 5 2589 -41 2589 -110 ct +2589 -178 2555 -227 2506 -227 ct p +2506 -195 m 2537 -195 2557 -161 2557 -110 ct 2557 -59 2537 -26 2505 -26 ct +2473 -26 2452 -59 2452 -110 ct 2452 -162 2473 -195 2506 -195 ct p ef +2701 -227 m 2650 -227 2616 -180 2616 -110 ct 2616 -41 2650 5 2700 5 ct 2750 5 2784 -41 2784 -110 ct +2784 -178 2750 -227 2701 -227 ct p +2701 -195 m 2732 -195 2752 -161 2752 -110 ct 2752 -59 2732 -26 2700 -26 ct +2668 -26 2647 -59 2647 -110 ct 2647 -162 2668 -195 2701 -195 ct p ef +2898 -138 m 2967 -221 l 2929 -221 l 2850 -127 l 2850 -303 l 2821 -303 l +2821 0 l 2850 0 l 2850 -83 l 2876 -111 l 2932 0 l 2971 0 l 2898 -138 l +p ef +pom +gr +gs +pum +14016 13846 t +213 -36 m 63 -36 l 63 -137 l 199 -137 l 199 -174 l 63 -174 l 63 -266 l +211 -266 l 211 -303 l 30 -303 l 30 0 l 213 0 l 213 -36 l p ef +339 -113 m 400 -221 l 363 -221 l 320 -143 l 279 -221 l 239 -221 l +300 -113 l 236 0 l 275 0 l 318 -83 l 364 0 l 403 0 l 339 -113 l +p ef +571 -146 m 565 -200 543 -227 502 -227 ct 449 -227 416 -180 416 -106 ct 416 -37 448 6 497 6 ct +539 6 564 -22 571 -78 ct 541 -78 l 535 -43 520 -26 497 -26 ct 466 -26 449 -56 449 -109 ct +449 -163 467 -194 499 -194 ct 523 -194 536 -180 541 -146 ct 571 -146 l p ef +633 -221 m 603 -221 l 603 0 l 633 0 l 633 -221 l p +633 -261 m 633 -303 l 603 -303 l 603 -261 l 633 -261 l p ef +745 -190 m 745 -221 l 715 -221 l 715 -282 l 685 -282 l 685 -221 l +660 -221 l 660 -190 l 685 -190 l 685 -44 l 685 -12 696 2 720 2 ct 722 2 724 2 731 1 ct +733 1 738 0 744 0 ct 744 -29 l 734 -29 l 720 -29 715 -34 715 -46 ct 715 -190 l +745 -190 l p ef +803 -153 m 807 -184 819 -196 846 -196 ct 873 -196 888 -184 888 -159 ct 888 -143 883 -136 872 -134 ct +821 -126 l 786 -121 766 -96 766 -58 ct 766 -19 789 6 824 6 ct 850 6 869 -4 888 -29 ct +891 -5 899 4 920 4 ct 924 4 928 3 934 1 ct 936 0 936 0 938 0 ct 938 -27 l 931 -25 929 -25 927 -25 ct +921 -25 917 -30 917 -38 ct 917 -165 l 917 -204 891 -227 848 -227 ct 819 -227 798 -217 786 -198 ct +779 -186 776 -175 775 -153 ct 803 -153 l p +887 -76 m 887 -48 861 -24 830 -24 ct 810 -24 798 -38 798 -61 ct 798 -83 809 -94 837 -98 ct +872 -104 880 -107 887 -112 ct 887 -76 l p ef +1037 -190 m 1037 -221 l 1007 -221 l 1007 -282 l 977 -282 l 977 -221 l +952 -221 l 952 -190 l 977 -190 l 977 -44 l 977 -12 988 2 1012 2 ct 1014 2 1016 2 1023 1 ct +1025 1 1030 0 1036 0 ct 1036 -29 l 1026 -29 l 1012 -29 1007 -34 1007 -46 ct +1007 -190 l 1037 -190 l p ef +1099 -221 m 1069 -221 l 1069 0 l 1099 0 l 1099 -221 l p +1099 -261 m 1099 -303 l 1069 -303 l 1069 -261 l 1099 -261 l p ef +1219 -227 m 1168 -227 1134 -180 1134 -110 ct 1134 -41 1168 5 1218 5 ct 1268 5 1302 -41 1302 -110 ct +1302 -178 1268 -227 1219 -227 ct p +1219 -195 m 1250 -195 1270 -161 1270 -110 ct 1270 -59 1250 -26 1218 -26 ct +1186 -26 1165 -59 1165 -110 ct 1165 -162 1186 -195 1219 -195 ct p ef +1368 -221 m 1339 -221 l 1339 0 l 1369 0 l 1369 -120 l 1369 -166 1388 -194 1419 -194 ct +1445 -194 1457 -176 1457 -136 ct 1457 0 l 1487 0 l 1487 -150 l 1487 -199 1464 -227 1426 -227 ct +1401 -227 1383 -216 1368 -188 ct 1368 -221 l p ef +pom +pum +14480 14375 t +145 -69 m 142 -44 122 -26 98 -26 ct 80 -26 65 -34 57 -49 ct 49 -61 47 -73 46 -98 ct +178 -98 l 177 -142 173 -162 163 -184 ct 149 -214 129 -227 99 -227 ct 47 -227 13 -180 13 -106 ct +13 -36 45 6 97 6 ct 139 6 168 -21 176 -69 ct 145 -69 l p +46 -128 m 48 -167 69 -194 98 -194 ct 114 -194 127 -186 135 -173 ct 142 -162 145 -151 147 -128 ct +46 -128 l p ef +244 -274 m 281 -274 l 281 -305 l 217 -305 l 217 82 l 281 82 l 281 52 l +244 52 l 244 -274 l p ef +343 -221 m 314 -221 l 314 0 l 344 0 l 344 -120 l 344 -166 363 -194 394 -194 ct +420 -194 432 -176 432 -136 ct 432 0 l 462 0 l 462 -150 l 462 -199 439 -227 401 -227 ct +376 -227 358 -216 343 -188 ct 343 -221 l p ef +533 52 m 496 52 l 496 82 l 561 82 l 561 -305 l 496 -305 l 496 -274 l +533 -274 l 533 52 l p ef +pom +gr +gs +pum +9491 13237 t +63 -137 m 185 -137 l 185 -174 l 63 -174 l 63 -266 l 202 -266 l 202 -303 l +30 -303 l 30 0 l 63 0 l 63 -137 l p ef +265 -221 m 235 -221 l 235 0 l 265 0 l 265 -221 l p +265 -261 m 265 -303 l 235 -303 l 235 -261 l 265 -261 l p ef +394 -113 m 455 -221 l 418 -221 l 375 -143 l 334 -221 l 294 -221 l +355 -113 l 291 0 l 330 0 l 373 -83 l 419 0 l 458 0 l 394 -113 l +p ef +606 -69 m 603 -44 583 -26 559 -26 ct 541 -26 526 -34 518 -49 ct 510 -61 508 -73 507 -98 ct +639 -98 l 638 -142 634 -162 624 -184 ct 610 -214 590 -227 560 -227 ct 508 -227 474 -180 474 -106 ct +474 -36 506 6 558 6 ct 600 6 629 -21 637 -69 ct 606 -69 l p +507 -128 m 509 -167 530 -194 559 -194 ct 575 -194 588 -186 596 -173 ct 603 -162 606 -151 608 -128 ct +507 -128 l p ef +829 -303 m 798 -303 l 798 -187 l 784 -216 768 -227 743 -227 ct 698 -227 668 -182 668 -115 ct +668 -41 699 6 747 6 ct 772 6 787 -4 800 -31 ct 800 0 l 829 0 l 829 -303 l +p +749 -194 m 780 -194 798 -162 798 -104 ct 798 -76 793 -57 782 -43 ct 773 -32 761 -26 748 -26 ct +717 -26 699 -58 699 -113 ct 699 -167 716 -194 749 -194 ct p ef +1113 -146 m 1107 -200 1085 -227 1044 -227 ct 991 -227 958 -180 958 -106 ct +958 -37 990 6 1039 6 ct 1081 6 1106 -22 1113 -78 ct 1083 -78 l 1077 -43 1062 -26 1039 -26 ct +1008 -26 991 -56 991 -109 ct 991 -163 1009 -194 1041 -194 ct 1065 -194 1078 -180 1083 -146 ct +1113 -146 l p ef +1219 -227 m 1168 -227 1134 -180 1134 -110 ct 1134 -41 1168 5 1218 5 ct 1268 5 1302 -41 1302 -110 ct +1302 -178 1268 -227 1219 -227 ct p +1219 -195 m 1250 -195 1270 -161 1270 -110 ct 1270 -59 1250 -26 1218 -26 ct +1186 -26 1165 -59 1165 -110 ct 1165 -162 1186 -195 1219 -195 ct p ef +1490 -303 m 1459 -303 l 1459 -187 l 1445 -216 1429 -227 1404 -227 ct 1359 -227 1329 -182 1329 -115 ct +1329 -41 1360 6 1408 6 ct 1433 6 1448 -4 1461 -31 ct 1461 0 l 1490 0 l 1490 -303 l +p +1410 -194 m 1441 -194 1459 -162 1459 -104 ct 1459 -76 1454 -57 1443 -43 ct +1434 -32 1422 -26 1409 -26 ct 1378 -26 1360 -58 1360 -113 ct 1360 -167 1377 -194 1410 -194 ct +p ef +1656 -69 m 1653 -44 1633 -26 1609 -26 ct 1591 -26 1576 -34 1568 -49 ct 1560 -61 1558 -73 1557 -98 ct +1689 -98 l 1688 -142 1684 -162 1674 -184 ct 1660 -214 1640 -227 1610 -227 ct +1558 -227 1524 -180 1524 -106 ct 1524 -36 1556 6 1608 6 ct 1650 6 1679 -21 1687 -69 ct +1656 -69 l p +1557 -128 m 1559 -167 1580 -194 1609 -194 ct 1625 -194 1638 -186 1646 -173 ct +1653 -162 1656 -151 1658 -128 ct 1557 -128 l p ef +1755 0 m 1755 -28 l 1768 -3 1782 6 1806 6 ct 1854 6 1885 -41 1885 -115 ct +1885 -182 1855 -227 1810 -227 ct 1788 -227 1772 -217 1756 -192 ct 1756 -303 l +1726 -303 l 1726 0 l 1755 0 l p +1805 -194 m 1837 -194 1853 -167 1853 -113 ct 1853 -58 1835 -26 1804 -26 ct +1792 -26 1780 -32 1771 -43 ct 1760 -57 1755 -76 1755 -105 ct 1755 -163 1772 -194 1805 -194 ct +p ef +1998 -227 m 1947 -227 1913 -180 1913 -110 ct 1913 -41 1947 5 1997 5 ct 2047 5 2081 -41 2081 -110 ct +2081 -178 2047 -227 1998 -227 ct p +1998 -195 m 2029 -195 2049 -161 2049 -110 ct 2049 -59 2029 -26 1997 -26 ct +1965 -26 1944 -59 1944 -110 ct 1944 -162 1965 -195 1998 -195 ct p ef +2193 -227 m 2142 -227 2108 -180 2108 -110 ct 2108 -41 2142 5 2192 5 ct 2242 5 2276 -41 2276 -110 ct +2276 -178 2242 -227 2193 -227 ct p +2193 -195 m 2224 -195 2244 -161 2244 -110 ct 2244 -59 2224 -26 2192 -26 ct +2160 -26 2139 -59 2139 -110 ct 2139 -162 2160 -195 2193 -195 ct p ef +2390 -138 m 2459 -221 l 2421 -221 l 2342 -127 l 2342 -303 l 2313 -303 l +2313 0 l 2342 0 l 2342 -83 l 2368 -111 l 2424 0 l 2463 0 l 2390 -138 l +p ef +2734 -221 m 2705 -221 l 2705 -188 l 2688 -217 2674 -227 2649 -227 ct 2604 -227 2574 -182 2574 -115 ct +2574 -42 2606 6 2654 6 ct 2676 6 2691 -2 2703 -24 ct 2703 -15 l 2703 11 2701 25 2695 37 ct +2687 54 2673 62 2651 62 ct 2628 62 2616 52 2610 27 ct 2580 27 l 2585 55 2591 68 2605 79 ct +2617 88 2632 93 2650 93 ct 2681 93 2705 80 2719 57 ct 2729 39 2734 17 2734 -18 ct +2734 -221 l p +2656 -194 m 2687 -194 2704 -162 2704 -104 ct 2704 -55 2686 -26 2654 -26 ct +2624 -26 2606 -58 2606 -113 ct 2606 -167 2623 -194 2656 -194 ct p ef +2805 -153 m 2809 -184 2821 -196 2848 -196 ct 2875 -196 2890 -184 2890 -159 ct +2890 -143 2885 -136 2874 -134 ct 2823 -126 l 2788 -121 2768 -96 2768 -58 ct +2768 -19 2791 6 2826 6 ct 2852 6 2871 -4 2890 -29 ct 2893 -5 2901 4 2922 4 ct 2926 4 2930 3 2936 1 ct +2938 0 2938 0 2940 0 ct 2940 -27 l 2933 -25 2931 -25 2929 -25 ct 2923 -25 2919 -30 2919 -38 ct +2919 -165 l 2919 -204 2893 -227 2850 -227 ct 2821 -227 2800 -217 2788 -198 ct +2781 -186 2778 -175 2777 -153 ct 2805 -153 l p +2889 -76 m 2889 -48 2863 -24 2832 -24 ct 2812 -24 2800 -38 2800 -61 ct 2800 -83 2811 -94 2839 -98 ct +2874 -104 2882 -107 2889 -112 ct 2889 -76 l p ef +3004 -221 m 2974 -221 l 2974 0 l 3004 0 l 3004 -221 l p +3004 -261 m 3004 -303 l 2974 -303 l 2974 -261 l 3004 -261 l p ef +3078 -221 m 3049 -221 l 3049 0 l 3079 0 l 3079 -120 l 3079 -166 3098 -194 3129 -194 ct +3155 -194 3167 -176 3167 -136 ct 3167 0 l 3197 0 l 3197 -150 l 3197 -199 3174 -227 3136 -227 ct +3111 -227 3093 -216 3078 -188 ct 3078 -221 l p ef +pom +gr +gs +pum +9174 17762 t +165 -88 m 189 0 l 226 0 l 136 -303 l 98 -303 l 4 0 l 39 0 l 65 -88 l +165 -88 l p +75 -125 m 115 -259 l 153 -125 l 75 -125 l p ef +406 -303 m 375 -303 l 375 -187 l 361 -216 345 -227 320 -227 ct 275 -227 245 -182 245 -115 ct +245 -41 276 6 324 6 ct 349 6 364 -4 377 -31 ct 377 0 l 406 0 l 406 -303 l +p +326 -194 m 357 -194 375 -162 375 -104 ct 375 -76 370 -57 359 -43 ct 350 -32 338 -26 325 -26 ct +294 -26 276 -58 276 -113 ct 276 -167 293 -194 326 -194 ct p ef +477 -153 m 481 -184 493 -196 520 -196 ct 547 -196 562 -184 562 -159 ct 562 -143 557 -136 546 -134 ct +495 -126 l 460 -121 440 -96 440 -58 ct 440 -19 463 6 498 6 ct 524 6 543 -4 562 -29 ct +565 -5 573 4 594 4 ct 598 4 602 3 608 1 ct 610 0 610 0 612 0 ct 612 -27 l 605 -25 603 -25 601 -25 ct +595 -25 591 -30 591 -38 ct 591 -165 l 591 -204 565 -227 522 -227 ct 493 -227 472 -217 460 -198 ct +453 -186 450 -175 449 -153 ct 477 -153 l p +561 -76 m 561 -48 535 -24 504 -24 ct 484 -24 472 -38 472 -61 ct 472 -83 483 -94 511 -98 ct +546 -104 554 -107 561 -112 ct 561 -76 l p ef +642 87 m 672 87 l 672 -24 l 685 -2 699 6 722 6 ct 770 6 801 -42 801 -115 ct +801 -182 771 -227 726 -227 ct 701 -227 687 -217 671 -188 ct 671 -221 l 642 -221 l +642 87 l p +721 -194 m 752 -194 769 -166 769 -114 ct 769 -58 751 -26 720 -26 ct 690 -26 671 -55 671 -103 ct +671 -163 688 -194 721 -194 ct p ef +906 -190 m 906 -221 l 876 -221 l 876 -282 l 846 -282 l 846 -221 l +821 -221 l 821 -190 l 846 -190 l 846 -44 l 846 -12 857 2 881 2 ct 883 2 885 2 892 1 ct +894 1 899 0 905 0 ct 905 -29 l 895 -29 l 881 -29 876 -34 876 -46 ct 876 -190 l +906 -190 l p ef +967 -221 m 937 -221 l 937 0 l 967 0 l 967 -221 l p +967 -261 m 967 -303 l 937 -303 l 937 -261 l 967 -261 l p ef +1076 -39 m 1029 -221 l 993 -221 l 1059 0 l 1092 0 l 1161 -221 l 1128 -221 l +1076 -39 l p ef +1309 -69 m 1306 -44 1286 -26 1262 -26 ct 1244 -26 1229 -34 1221 -49 ct 1213 -61 1211 -73 1210 -98 ct +1342 -98 l 1341 -142 1337 -162 1327 -184 ct 1313 -214 1293 -227 1263 -227 ct +1211 -227 1177 -180 1177 -106 ct 1177 -36 1209 6 1261 6 ct 1303 6 1332 -21 1340 -69 ct +1309 -69 l p +1210 -128 m 1212 -167 1233 -194 1262 -194 ct 1278 -194 1291 -186 1299 -173 ct +1306 -162 1309 -151 1311 -128 ct 1210 -128 l p ef +1621 -146 m 1615 -200 1593 -227 1552 -227 ct 1499 -227 1466 -180 1466 -106 ct +1466 -37 1498 6 1547 6 ct 1589 6 1614 -22 1621 -78 ct 1591 -78 l 1585 -43 1570 -26 1547 -26 ct +1516 -26 1499 -56 1499 -109 ct 1499 -163 1517 -194 1549 -194 ct 1573 -194 1586 -180 1591 -146 ct +1621 -146 l p ef +1727 -227 m 1676 -227 1642 -180 1642 -110 ct 1642 -41 1676 5 1726 5 ct 1776 5 1810 -41 1810 -110 ct +1810 -178 1776 -227 1727 -227 ct p +1727 -195 m 1758 -195 1778 -161 1778 -110 ct 1778 -59 1758 -26 1726 -26 ct +1694 -26 1673 -59 1673 -110 ct 1673 -162 1694 -195 1727 -195 ct p ef +1998 -303 m 1967 -303 l 1967 -187 l 1953 -216 1937 -227 1912 -227 ct 1867 -227 1837 -182 1837 -115 ct +1837 -41 1868 6 1916 6 ct 1941 6 1956 -4 1969 -31 ct 1969 0 l 1998 0 l 1998 -303 l +p +1918 -194 m 1949 -194 1967 -162 1967 -104 ct 1967 -76 1962 -57 1951 -43 ct +1942 -32 1930 -26 1917 -26 ct 1886 -26 1868 -58 1868 -113 ct 1868 -167 1885 -194 1918 -194 ct +p ef +2164 -69 m 2161 -44 2141 -26 2117 -26 ct 2099 -26 2084 -34 2076 -49 ct 2068 -61 2066 -73 2065 -98 ct +2197 -98 l 2196 -142 2192 -162 2182 -184 ct 2168 -214 2148 -227 2118 -227 ct +2066 -227 2032 -180 2032 -106 ct 2032 -36 2064 6 2116 6 ct 2158 6 2187 -21 2195 -69 ct +2164 -69 l p +2065 -128 m 2067 -167 2088 -194 2117 -194 ct 2133 -194 2146 -186 2154 -173 ct +2161 -162 2164 -151 2166 -128 ct 2065 -128 l p ef +2263 0 m 2263 -28 l 2276 -3 2290 6 2314 6 ct 2362 6 2393 -41 2393 -115 ct +2393 -182 2363 -227 2318 -227 ct 2296 -227 2280 -217 2264 -192 ct 2264 -303 l +2234 -303 l 2234 0 l 2263 0 l p +2313 -194 m 2345 -194 2361 -167 2361 -113 ct 2361 -58 2343 -26 2312 -26 ct +2300 -26 2288 -32 2279 -43 ct 2268 -57 2263 -76 2263 -105 ct 2263 -163 2280 -194 2313 -194 ct +p ef +2506 -227 m 2455 -227 2421 -180 2421 -110 ct 2421 -41 2455 5 2505 5 ct 2555 5 2589 -41 2589 -110 ct +2589 -178 2555 -227 2506 -227 ct p +2506 -195 m 2537 -195 2557 -161 2557 -110 ct 2557 -59 2537 -26 2505 -26 ct +2473 -26 2452 -59 2452 -110 ct 2452 -162 2473 -195 2506 -195 ct p ef +2701 -227 m 2650 -227 2616 -180 2616 -110 ct 2616 -41 2650 5 2700 5 ct 2750 5 2784 -41 2784 -110 ct +2784 -178 2750 -227 2701 -227 ct p +2701 -195 m 2732 -195 2752 -161 2752 -110 ct 2752 -59 2732 -26 2700 -26 ct +2668 -26 2647 -59 2647 -110 ct 2647 -162 2668 -195 2701 -195 ct p ef +2898 -138 m 2967 -221 l 2929 -221 l 2850 -127 l 2850 -303 l 2821 -303 l +2821 0 l 2850 0 l 2850 -83 l 2876 -111 l 2932 0 l 2971 0 l 2898 -138 l +p ef +3242 -221 m 3213 -221 l 3213 -188 l 3196 -217 3182 -227 3157 -227 ct 3112 -227 3082 -182 3082 -115 ct +3082 -42 3114 6 3162 6 ct 3184 6 3199 -2 3211 -24 ct 3211 -15 l 3211 11 3209 25 3203 37 ct +3195 54 3181 62 3159 62 ct 3136 62 3124 52 3118 27 ct 3088 27 l 3093 55 3099 68 3113 79 ct +3125 88 3140 93 3158 93 ct 3189 93 3213 80 3227 57 ct 3237 39 3242 17 3242 -18 ct +3242 -221 l p +3164 -194 m 3195 -194 3212 -162 3212 -104 ct 3212 -55 3194 -26 3162 -26 ct +3132 -26 3114 -58 3114 -113 ct 3114 -167 3131 -194 3164 -194 ct p ef +3313 -153 m 3317 -184 3329 -196 3356 -196 ct 3383 -196 3398 -184 3398 -159 ct +3398 -143 3393 -136 3382 -134 ct 3331 -126 l 3296 -121 3276 -96 3276 -58 ct +3276 -19 3299 6 3334 6 ct 3360 6 3379 -4 3398 -29 ct 3401 -5 3409 4 3430 4 ct 3434 4 3438 3 3444 1 ct +3446 0 3446 0 3448 0 ct 3448 -27 l 3441 -25 3439 -25 3437 -25 ct 3431 -25 3427 -30 3427 -38 ct +3427 -165 l 3427 -204 3401 -227 3358 -227 ct 3329 -227 3308 -217 3296 -198 ct +3289 -186 3286 -175 3285 -153 ct 3313 -153 l p +3397 -76 m 3397 -48 3371 -24 3340 -24 ct 3320 -24 3308 -38 3308 -61 ct 3308 -83 3319 -94 3347 -98 ct +3382 -104 3390 -107 3397 -112 ct 3397 -76 l p ef +3512 -221 m 3482 -221 l 3482 0 l 3512 0 l 3512 -221 l p +3512 -261 m 3512 -303 l 3482 -303 l 3482 -261 l 3512 -261 l p ef +3586 -221 m 3557 -221 l 3557 0 l 3587 0 l 3587 -120 l 3587 -166 3606 -194 3637 -194 ct +3663 -194 3675 -176 3675 -136 ct 3675 0 l 3705 0 l 3705 -150 l 3705 -199 3682 -227 3644 -227 ct +3619 -227 3601 -216 3586 -188 ct 3586 -221 l p ef +pom +gr +0 lw 1 lj 11185 19818 m 9435 19818 l 9435 18318 l 12935 18318 l 12935 19818 l +11185 19818 l pc +gs +pum +10523 19288 t +41 0 m 191 0 l 234 0 272 -17 297 -48 ct 332 -92 351 -157 351 -233 ct 351 -368 289 -455 193 -455 ct +41 -455 l 41 0 l p +92 -403 m 187 -403 l 259 -403 299 -341 299 -227 ct 299 -119 257 -52 190 -52 ct +92 -52 l 92 -403 l p ef +596 -104 m 591 -66 561 -39 524 -39 ct 497 -39 476 -51 462 -74 ct 451 -92 448 -110 446 -147 ct +645 -147 l 643 -213 637 -244 622 -277 ct 601 -321 570 -341 526 -341 ct 448 -341 397 -271 397 -160 ct +397 -55 445 9 523 9 ct 585 9 629 -32 641 -104 ct 596 -104 l p +446 -192 m 449 -252 481 -292 524 -292 ct 548 -292 568 -280 580 -260 ct 591 -243 595 -226 597 -192 ct +446 -192 l p ef +745 -455 m 699 -455 l 699 0 l 745 0 l 745 -455 l p ef +853 -231 m 859 -277 877 -295 917 -295 ct 958 -295 980 -276 980 -240 ct 980 -215 973 -204 956 -201 ct +880 -190 l 827 -182 798 -145 798 -87 ct 798 -29 832 9 885 9 ct 923 9 951 -6 981 -44 ct +984 -8 997 6 1028 6 ct 1035 6 1040 5 1049 1 ct 1052 0 1053 0 1055 0 ct 1055 -40 l +1045 -38 1043 -38 1039 -38 ct 1029 -38 1024 -45 1024 -57 ct 1024 -248 l 1024 -306 985 -341 920 -341 ct +878 -341 845 -326 827 -297 ct 817 -280 813 -264 811 -231 ct 853 -231 l p +979 -114 m 979 -73 940 -36 894 -36 ct 863 -36 845 -57 845 -92 ct 845 -125 862 -141 904 -148 ct +956 -157 969 -160 979 -169 ct 979 -114 l p ef +1197 -59 m 1124 -332 l 1072 -332 l 1173 8 l 1168 24 1164 38 1162 43 ct +1152 76 1144 85 1125 85 ct 1115 85 1106 83 1097 80 ct 1097 130 l 1101 132 l +1109 135 1113 135 1119 135 ct 1174 135 1182 125 1223 -6 ct 1321 -332 l 1270 -332 l +1197 -59 l p ef +pom +gr +13385 18918 m 13385 19218 l 12935 19068 l 13385 18918 l p ef +1 lw 0 lj 14935 14567 m 14935 19068 l 13295 19068 l ps +7085 18268 m 6785 18268 l 6935 17818 l 7085 18268 l p ef +9435 19068 m 6935 19068 l 6935 18178 l ps +20025 14718 m 20031 14418 l 20478 14577 l 20025 14718 l p ef +19335 14568 m 20127 14568 l ps +gs +pum +10179 20249 t +63 -128 m 141 -128 l 186 -128 215 -163 215 -217 ct 215 -269 186 -303 141 -303 ct +30 -303 l 30 0 l 63 0 l 63 -128 l p +63 -268 m 131 -268 l 164 -268 181 -251 181 -216 ct 181 -181 164 -163 130 -163 ct +63 -163 l 63 -268 l p ef +282 -153 m 286 -184 298 -196 325 -196 ct 352 -196 367 -184 367 -159 ct 367 -143 362 -136 351 -134 ct +300 -126 l 265 -121 245 -96 245 -58 ct 245 -19 268 6 303 6 ct 329 6 348 -4 367 -29 ct +370 -5 378 4 399 4 ct 403 4 407 3 413 1 ct 415 0 415 0 417 0 ct 417 -27 l 410 -25 408 -25 406 -25 ct +400 -25 396 -30 396 -38 ct 396 -165 l 396 -204 370 -227 327 -227 ct 298 -227 277 -217 265 -198 ct +258 -186 255 -175 254 -153 ct 282 -153 l p +366 -76 m 366 -48 340 -24 309 -24 ct 289 -24 277 -38 277 -61 ct 277 -83 288 -94 316 -98 ct +351 -104 359 -107 366 -112 ct 366 -76 l p ef +582 -158 m 580 -202 555 -227 514 -227 ct 472 -227 444 -200 444 -157 ct 444 -129 458 -111 486 -103 ct +522 -92 l 550 -84 558 -77 558 -60 ct 558 -39 542 -26 515 -26 ct 484 -26 470 -39 468 -71 ct +439 -71 l 440 -49 442 -38 448 -27 ct 460 -5 483 6 513 6 ct 559 6 588 -22 588 -66 ct +588 -97 574 -113 537 -125 ct 507 -134 l 480 -142 474 -148 474 -163 ct 474 -183 488 -195 512 -195 ct +538 -195 551 -183 553 -158 ct 582 -158 l p ef +690 -190 m 690 -221 l 660 -221 l 660 -282 l 630 -282 l 630 -221 l +605 -221 l 605 -190 l 630 -190 l 630 -44 l 630 -12 641 2 665 2 ct 667 2 669 2 676 1 ct +678 1 683 0 689 0 ct 689 -29 l 679 -29 l 665 -29 660 -34 660 -46 ct 660 -190 l +690 -190 l p ef +950 -158 m 948 -202 923 -227 882 -227 ct 840 -227 812 -200 812 -157 ct 812 -129 826 -111 854 -103 ct +890 -92 l 918 -84 926 -77 926 -60 ct 926 -39 910 -26 883 -26 ct 852 -26 838 -39 836 -71 ct +807 -71 l 808 -49 810 -38 816 -27 ct 828 -5 851 6 881 6 ct 927 6 956 -22 956 -66 ct +956 -97 942 -113 905 -125 ct 875 -134 l 848 -142 842 -148 842 -163 ct 842 -183 856 -195 880 -195 ct +906 -195 919 -183 921 -158 ct 950 -158 l p ef +1138 0 m 1138 -221 l 1108 -221 l 1108 -99 l 1108 -54 1088 -26 1058 -26 ct +1034 -26 1023 -42 1023 -74 ct 1023 -221 l 992 -221 l 992 -62 l 992 -19 1015 6 1052 6 ct +1079 6 1093 -3 1109 -34 ct 1109 0 l 1138 0 l p ef +1213 0 m 1213 -28 l 1226 -3 1240 6 1264 6 ct 1312 6 1343 -41 1343 -115 ct +1343 -182 1313 -227 1268 -227 ct 1246 -227 1230 -217 1214 -192 ct 1214 -303 l +1184 -303 l 1184 0 l 1213 0 l p +1263 -194 m 1295 -194 1311 -167 1311 -113 ct 1311 -58 1293 -26 1262 -26 ct +1250 -26 1238 -32 1229 -43 ct 1218 -57 1213 -76 1213 -105 ct 1213 -163 1230 -194 1263 -194 ct +p ef +1449 -190 m 1449 -221 l 1419 -221 l 1419 -248 l 1419 -266 1424 -274 1437 -274 ct +1440 -274 1444 -274 1449 -273 ct 1449 -307 l 1440 -307 1438 -307 1435 -307 ct +1405 -307 1389 -291 1389 -259 ct 1389 -221 l 1363 -221 l 1363 -190 l 1389 -190 l +1389 0 l 1419 0 l 1419 -190 l 1449 -190 l p ef +1571 -188 m 1571 -226 l 1568 -227 1565 -227 1563 -227 ct 1541 -227 1527 -215 1511 -183 ct +1511 -221 l 1482 -221 l 1482 0 l 1513 0 l 1513 -129 l 1513 -163 1532 -188 1559 -188 ct +1571 -188 l p ef +1620 -153 m 1624 -184 1636 -196 1663 -196 ct 1690 -196 1705 -184 1705 -159 ct +1705 -143 1700 -136 1689 -134 ct 1638 -126 l 1603 -121 1583 -96 1583 -58 ct +1583 -19 1606 6 1641 6 ct 1667 6 1686 -4 1705 -29 ct 1708 -5 1716 4 1737 4 ct 1741 4 1745 3 1751 1 ct +1753 0 1753 0 1755 0 ct 1755 -27 l 1748 -25 1746 -25 1744 -25 ct 1738 -25 1734 -30 1734 -38 ct +1734 -165 l 1734 -204 1708 -227 1665 -227 ct 1636 -227 1615 -217 1603 -198 ct +1596 -186 1593 -175 1592 -153 ct 1620 -153 l p +1704 -76 m 1704 -48 1678 -24 1647 -24 ct 1627 -24 1615 -38 1615 -61 ct 1615 -83 1626 -94 1654 -98 ct +1689 -104 1697 -107 1704 -112 ct 1704 -76 l p ef +1787 0 m 1817 0 l 1817 -120 l 1817 -165 1836 -194 1866 -194 ct 1883 -194 1894 -179 1894 -153 ct +1894 0 l 1924 0 l 1924 -134 l 1924 -168 1943 -194 1968 -194 ct 1990 -194 2001 -177 2001 -142 ct +2001 0 l 2031 0 l 2031 -153 l 2031 -199 2009 -227 1974 -227 ct 1952 -227 1940 -219 1920 -191 ct +1908 -217 1894 -227 1872 -227 ct 1848 -227 1831 -216 1816 -188 ct 1816 -221 l +1787 -221 l 1787 0 l p ef +2198 -69 m 2195 -44 2175 -26 2151 -26 ct 2133 -26 2118 -34 2110 -49 ct 2102 -61 2100 -73 2099 -98 ct +2231 -98 l 2230 -142 2226 -162 2216 -184 ct 2202 -214 2182 -227 2152 -227 ct +2100 -227 2066 -180 2066 -106 ct 2066 -36 2098 6 2150 6 ct 2192 6 2221 -21 2229 -69 ct +2198 -69 l p +2099 -128 m 2101 -167 2122 -194 2151 -194 ct 2167 -194 2180 -186 2188 -173 ct +2195 -162 2198 -151 2200 -128 ct 2099 -128 l p ef +pom +gr +tm setmatrix +0 0 t +1 1 s +0 11113 t +pom +count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore +%%PageTrailer +%%Trailer +%%EOF diff --git a/native/codec/libraries/speex/doc/celp_decoder.odg b/native/codec/libraries/speex/doc/celp_decoder.odg new file mode 100644 index 0000000..ed537ad Binary files /dev/null and b/native/codec/libraries/speex/doc/celp_decoder.odg differ diff --git a/native/codec/libraries/speex/doc/components.eps b/native/codec/libraries/speex/doc/components.eps new file mode 100644 index 0000000..8ac53a4 --- /dev/null +++ b/native/codec/libraries/speex/doc/components.eps @@ -0,0 +1,1361 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 0 0 770 174 +%%Pages: 0 +%%Creator: Sun Microsystems, Inc. +%%Title: none +%%CreationDate: none +%%LanguageLevel: 2 +%%EndComments +%%BeginProlog +%%BeginResource: procset SDRes-Prolog 1.0 0 +/b4_inc_state save def +/dict_count countdictstack def +/op_count count 1 sub def +userdict begin +0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath +/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if +/bdef {bind def} bind def +/c {setrgbcolor} bdef +/l {neg lineto} bdef +/rl {neg rlineto} bdef +/lc {setlinecap} bdef +/lj {setlinejoin} bdef +/lw {setlinewidth} bdef +/ml {setmiterlimit} bdef +/ld {setdash} bdef +/m {neg moveto} bdef +/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef +/r {rotate} bdef +/t {neg translate} bdef +/s {scale} bdef +/sw {show} bdef +/gs {gsave} bdef +/gr {grestore} bdef +/f {findfont dup length dict begin +{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def +currentdict end /NFont exch definefont pop /NFont findfont} bdef +/p {closepath} bdef +/sf {scalefont setfont} bdef +/ef {eofill}bdef +/pc {closepath stroke}bdef +/ps {stroke}bdef +/pum {matrix currentmatrix}bdef +/pom {setmatrix}bdef +/bs {/aString exch def /nXOfs exch def /nWidth exch def currentpoint nXOfs 0 rmoveto pum nWidth aString stringwidth pop div 1 scale aString show pom moveto} bdef +%%EndResource +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%EndPageSetup +pum +0.02835 0.0284 s +0 -6126 t +/tm matrix currentmatrix def +tm setmatrix +-450 -7975 t +1 1 s +50 lw 1 lj 0.003 0.003 0.003 c 4400 9500 m 2900 9500 l 2900 8000 l 5900 8000 l +5900 9500 l 4400 9500 l pc +gs +gs +pum +3380 8974 t +50 0 m 50 -455 l 251 -455 l 292 -455 323 -451 344 -443 ct 365 -435 382 -420 394 -399 ct +407 -379 413 -356 413 -331 ct 413 -299 403 -271 382 -249 ct 361 -227 329 -213 285 -207 ct +301 -199 313 -192 322 -184 ct 339 -168 356 -148 371 -124 ct 451 0 l 375 0 l +315 -95 l 297 -122 283 -143 271 -157 ct 260 -172 250 -182 241 -188 ct 232 -194 223 -198 213 -200 ct +207 -201 195 -202 180 -202 ct 110 -202 l 110 0 l 50 0 l p +110 -254 m 239 -254 l 267 -254 288 -257 304 -263 ct 319 -268 331 -277 339 -290 ct +347 -303 351 -316 351 -331 ct 351 -352 344 -370 328 -384 ct 312 -398 288 -405 254 -405 ct +110 -405 l 110 -254 l p ef +724 -107 m 782 -99 l 773 -66 756 -40 731 -21 ct 707 -2 675 7 637 7 ct 589 7 551 -8 523 -37 ct +494 -67 480 -109 480 -162 ct 480 -218 495 -261 523 -291 ct 552 -322 589 -337 634 -337 ct +678 -337 714 -322 742 -292 ct 770 -262 784 -220 784 -166 ct 784 -163 784 -158 783 -151 ct +538 -151 l 540 -115 550 -87 569 -68 ct 587 -49 610 -39 637 -39 ct 658 -39 675 -44 690 -55 ct +704 -66 716 -83 724 -107 ct p +541 -197 m 725 -197 l 722 -225 715 -245 704 -259 ct 686 -280 663 -291 635 -291 ct +609 -291 587 -283 570 -265 ct 553 -248 543 -226 541 -197 ct p ef +1066 -121 m 1121 -114 l 1115 -76 1099 -46 1075 -25 ct 1050 -4 1020 7 984 7 ct +939 7 902 -8 875 -37 ct 848 -67 834 -109 834 -164 ct 834 -199 840 -230 851 -257 ct +863 -284 881 -304 905 -317 ct 929 -330 956 -337 984 -337 ct 1020 -337 1049 -328 1072 -310 ct +1094 -292 1109 -266 1115 -233 ct 1061 -224 l 1056 -247 1047 -263 1034 -274 ct +1021 -286 1005 -291 986 -291 ct 958 -291 935 -281 918 -261 ct 900 -241 891 -209 891 -165 ct +891 -121 900 -89 917 -69 ct 934 -49 956 -39 983 -39 ct 1005 -39 1023 -46 1038 -59 ct +1053 -72 1062 -93 1066 -121 ct p ef +1147 -165 m 1147 -226 1164 -271 1198 -301 ct 1226 -325 1261 -337 1302 -337 ct +1347 -337 1384 -322 1412 -293 ct 1441 -263 1456 -222 1456 -170 ct 1456 -127 1449 -94 1437 -70 ct +1424 -45 1405 -27 1381 -13 ct 1357 0 1330 7 1302 7 ct 1255 7 1218 -8 1190 -37 ct +1161 -67 1147 -110 1147 -165 ct p +1204 -165 m 1204 -123 1214 -91 1232 -70 ct 1250 -49 1274 -39 1302 -39 ct 1329 -39 1352 -49 1371 -71 ct +1389 -92 1398 -124 1398 -167 ct 1398 -208 1389 -239 1370 -260 ct 1352 -281 1329 -291 1302 -291 ct +1274 -291 1250 -281 1232 -260 ct 1214 -239 1204 -207 1204 -165 ct p ef +1518 0 m 1518 -330 l 1568 -330 l 1568 -280 l 1581 -303 1593 -318 1604 -326 ct +1615 -333 1627 -337 1640 -337 ct 1659 -337 1678 -331 1697 -319 ct 1678 -267 l +1664 -275 1651 -279 1637 -279 ct 1625 -279 1614 -276 1604 -268 ct 1594 -261 1587 -251 1583 -238 ct +1577 -218 1574 -196 1574 -173 ct 1574 0 l 1518 0 l p ef +1944 0 m 1944 -42 l 1924 -9 1893 7 1852 7 ct 1826 7 1802 0 1780 -15 ct 1758 -29 1741 -49 1729 -75 ct +1717 -101 1711 -131 1711 -165 ct 1711 -198 1716 -228 1727 -254 ct 1738 -281 1755 -302 1776 -316 ct +1798 -330 1823 -337 1850 -337 ct 1870 -337 1887 -333 1903 -325 ct 1918 -316 1931 -305 1941 -292 ct +1941 -455 l 1996 -455 l 1996 0 l 1944 0 l p +1768 -165 m 1768 -123 1777 -91 1795 -70 ct 1813 -49 1833 -39 1858 -39 ct 1882 -39 1903 -49 1920 -69 ct +1937 -89 1945 -119 1945 -160 ct 1945 -205 1937 -238 1919 -259 ct 1902 -280 1881 -291 1855 -291 ct +1830 -291 1810 -281 1793 -261 ct 1776 -240 1768 -208 1768 -165 ct p ef +pom +gr +gr +12748 9525 m 12697 9525 l 12697 9475 l 12748 9475 l 12748 9525 l p ef +12646 9525 m 12595 9525 l 12595 9475 l 12646 9475 l 12646 9525 l p ef +12544 9525 m 12493 9525 l 12493 9475 l 12544 9475 l 12544 9525 l p ef +12442 9525 m 12391 9525 l 12391 9475 l 12442 9475 l 12442 9525 l p ef +12340 9525 m 12289 9525 l 12289 9475 l 12340 9475 l 12340 9525 l p ef +12238 9525 m 12187 9525 l 12187 9475 l 12238 9475 l 12238 9525 l p ef +12136 9525 m 12085 9525 l 12085 9475 l 12136 9475 l 12136 9525 l p ef +12034 9525 m 11983 9525 l 11983 9475 l 12034 9475 l 12034 9525 l p ef +11932 9525 m 11881 9525 l 11881 9475 l 11932 9475 l 11932 9525 l p ef +11830 9525 m 11779 9525 l 11779 9475 l 11830 9475 l 11830 9525 l p ef +11728 9525 m 11677 9525 l 11677 9475 l 11728 9475 l 11728 9525 l p ef +11626 9525 m 11575 9525 l 11575 9475 l 11626 9475 l 11626 9525 l p ef +11524 9525 m 11473 9525 l 11473 9475 l 11524 9475 l 11524 9525 l p ef +11422 9525 m 11400 9525 l 11400 9500 l 11400 9475 l 11422 9475 l 11422 9500 l +11422 9525 l p ef +11400 9500 m 11400 9525 l 11396 9525 l 11391 9523 l 11388 9522 l 11384 9519 l +11381 9516 l 11378 9513 l 11377 9509 l 11375 9504 l 11375 9500 l 11375 9500 l +11400 9500 l p ef +11375 9500 m 11375 9471 l 11400 9471 l 11425 9471 l 11425 9500 l 11400 9500 l +11375 9500 l p ef +11375 9420 m 11375 9369 l 11425 9369 l 11425 9420 l 11375 9420 l p ef +11375 9318 m 11375 9267 l 11425 9267 l 11425 9318 l 11375 9318 l p ef +11375 9216 m 11375 9165 l 11425 9165 l 11425 9216 l 11375 9216 l p ef +11375 9114 m 11375 9063 l 11425 9063 l 11425 9114 l 11375 9114 l p ef +11375 9012 m 11375 8961 l 11425 8961 l 11425 9012 l 11375 9012 l p ef +11375 8910 m 11375 8859 l 11425 8859 l 11425 8910 l 11375 8910 l p ef +11375 8808 m 11375 8757 l 11425 8757 l 11425 8808 l 11375 8808 l p ef +11375 8706 m 11375 8655 l 11425 8655 l 11425 8706 l 11375 8706 l p ef +11375 8604 m 11375 8553 l 11425 8553 l 11425 8604 l 11375 8604 l p ef +11375 8502 m 11375 8451 l 11425 8451 l 11425 8502 l 11375 8502 l p ef +11375 8400 m 11375 8349 l 11425 8349 l 11425 8400 l 11375 8400 l p ef +11375 8298 m 11375 8247 l 11425 8247 l 11425 8298 l 11375 8298 l p ef +11375 8196 m 11375 8145 l 11425 8145 l 11425 8196 l 11375 8196 l p ef +11375 8094 m 11375 8043 l 11425 8043 l 11425 8094 l 11375 8094 l p ef +11408 7975 m 11459 7975 l 11459 8025 l 11408 8025 l 11408 7975 l p ef +11510 7975 m 11561 7975 l 11561 8025 l 11510 8025 l 11510 7975 l p ef +11612 7975 m 11663 7975 l 11663 8025 l 11612 8025 l 11612 7975 l p ef +11714 7975 m 11765 7975 l 11765 8025 l 11714 8025 l 11714 7975 l p ef +11816 7975 m 11867 7975 l 11867 8025 l 11816 8025 l 11816 7975 l p ef +11918 7975 m 11969 7975 l 11969 8025 l 11918 8025 l 11918 7975 l p ef +12020 7975 m 12071 7975 l 12071 8025 l 12020 8025 l 12020 7975 l p ef +12122 7975 m 12173 7975 l 12173 8025 l 12122 8025 l 12122 7975 l p ef +12224 7975 m 12275 7975 l 12275 8025 l 12224 8025 l 12224 7975 l p ef +12326 7975 m 12377 7975 l 12377 8025 l 12326 8025 l 12326 7975 l p ef +12428 7975 m 12479 7975 l 12479 8025 l 12428 8025 l 12428 7975 l p ef +12530 7975 m 12581 7975 l 12581 8025 l 12530 8025 l 12530 7975 l p ef +12632 7975 m 12683 7975 l 12683 8025 l 12632 8025 l 12632 7975 l p ef +12734 7975 m 12785 7975 l 12785 8025 l 12734 8025 l 12734 7975 l p ef +12836 7975 m 12887 7975 l 12887 8025 l 12836 8025 l 12836 7975 l p ef +12938 7975 m 12989 7975 l 12989 8025 l 12938 8025 l 12938 7975 l p ef +13040 7975 m 13091 7975 l 13091 8025 l 13040 8025 l 13040 7975 l p ef +13142 7975 m 13193 7975 l 13193 8025 l 13142 8025 l 13142 7975 l p ef +13244 7975 m 13295 7975 l 13295 8025 l 13244 8025 l 13244 7975 l p ef +13346 7975 m 13397 7975 l 13397 8025 l 13346 8025 l 13346 7975 l p ef +13448 7975 m 13499 7975 l 13499 8025 l 13448 8025 l 13448 7975 l p ef +13550 7975 m 13601 7975 l 13601 8025 l 13550 8025 l 13550 7975 l p ef +13652 7975 m 13703 7975 l 13703 8025 l 13652 8025 l 13652 7975 l p ef +13754 7975 m 13805 7975 l 13805 8025 l 13754 8025 l 13754 7975 l p ef +13856 7975 m 13907 7975 l 13907 8025 l 13856 8025 l 13856 7975 l p ef +13958 7975 m 14009 7975 l 14009 8025 l 13958 8025 l 13958 7975 l p ef +14060 7975 m 14111 7975 l 14111 8025 l 14060 8025 l 14060 7975 l p ef +14162 7975 m 14213 7975 l 14213 8025 l 14162 8025 l 14162 7975 l p ef +14264 7975 m 14300 7975 l 14300 8000 l 14300 8025 l 14264 8025 l 14264 8000 l +14264 7975 l p ef +14300 8000 m 14300 7975 l 14304 7975 l 14309 7977 l 14312 7978 l 14316 7981 l +14319 7984 l 14322 7987 l 14323 7991 l 14325 7996 l 14325 8000 l 14325 8000 l +14300 8000 l p ef +14325 8000 m 14325 8015 l 14300 8015 l 14275 8015 l 14275 8000 l 14300 8000 l +14325 8000 l p ef +14325 8066 m 14325 8117 l 14275 8117 l 14275 8066 l 14325 8066 l p ef +14325 8168 m 14325 8219 l 14275 8219 l 14275 8168 l 14325 8168 l p ef +14325 8270 m 14325 8321 l 14275 8321 l 14275 8270 l 14325 8270 l p ef +14325 8372 m 14325 8423 l 14275 8423 l 14275 8372 l 14325 8372 l p ef +14325 8474 m 14325 8525 l 14275 8525 l 14275 8474 l 14325 8474 l p ef +14325 8576 m 14325 8627 l 14275 8627 l 14275 8576 l 14325 8576 l p ef +14325 8678 m 14325 8729 l 14275 8729 l 14275 8678 l 14325 8678 l p ef +14325 8780 m 14325 8831 l 14275 8831 l 14275 8780 l 14325 8780 l p ef +14325 8882 m 14325 8933 l 14275 8933 l 14275 8882 l 14325 8882 l p ef +14325 8984 m 14325 9035 l 14275 9035 l 14275 8984 l 14325 8984 l p ef +14325 9086 m 14325 9137 l 14275 9137 l 14275 9086 l 14325 9086 l p ef +14325 9188 m 14325 9239 l 14275 9239 l 14275 9188 l 14325 9188 l p ef +14325 9290 m 14325 9341 l 14275 9341 l 14275 9290 l 14325 9290 l p ef +14325 9392 m 14325 9443 l 14275 9443 l 14275 9392 l 14325 9392 l p ef +14325 9494 m 14325 9500 l 14300 9500 l 14275 9500 l 14275 9494 l 14300 9494 l +14325 9494 l p ef +14300 9500 m 14325 9500 l 14325 9504 l 14323 9509 l 14322 9512 l 14319 9516 l +14316 9519 l 14313 9522 l 14309 9523 l 14304 9525 l 14300 9525 l 14300 9525 l +14300 9500 l p ef +14300 9525 m 14255 9525 l 14255 9500 l 14255 9475 l 14300 9475 l 14300 9500 l +14300 9525 l p ef +14204 9525 m 14153 9525 l 14153 9475 l 14204 9475 l 14204 9525 l p ef +14102 9525 m 14051 9525 l 14051 9475 l 14102 9475 l 14102 9525 l p ef +14000 9525 m 13949 9525 l 13949 9475 l 14000 9475 l 14000 9525 l p ef +13898 9525 m 13847 9525 l 13847 9475 l 13898 9475 l 13898 9525 l p ef +13796 9525 m 13745 9525 l 13745 9475 l 13796 9475 l 13796 9525 l p ef +13694 9525 m 13643 9525 l 13643 9475 l 13694 9475 l 13694 9525 l p ef +13592 9525 m 13541 9525 l 13541 9475 l 13592 9475 l 13592 9525 l p ef +13490 9525 m 13439 9525 l 13439 9475 l 13490 9475 l 13490 9525 l p ef +13388 9525 m 13337 9525 l 13337 9475 l 13388 9475 l 13388 9525 l p ef +13286 9525 m 13235 9525 l 13235 9475 l 13286 9475 l 13286 9525 l p ef +13184 9525 m 13133 9525 l 13133 9475 l 13184 9475 l 13184 9525 l p ef +13082 9525 m 13031 9525 l 13031 9475 l 13082 9475 l 13082 9525 l p ef +12980 9525 m 12929 9525 l 12929 9475 l 12980 9475 l 12980 9525 l p ef +12878 9525 m 12850 9525 l 12850 9500 l 12850 9475 l 12878 9475 l 12878 9500 l +12878 9525 l p ef +12850 9525 m 12799 9525 l 12799 9500 l 12799 9475 l 12850 9475 l 12850 9500 l +12850 9525 l p ef +gs +gs +pum +12191 8974 t +-1 0 m 174 -455 l 238 -455 l 424 0 l 356 0 l 303 -138 l 113 -138 l +63 0 l -1 0 l p +130 -187 m 284 -187 l 237 -313 l 222 -351 212 -383 205 -407 ct 199 -378 191 -349 180 -320 ct +130 -187 l p ef +473 0 m 473 -455 l 802 -455 l 802 -401 l 533 -401 l 533 -262 l 785 -262 l +785 -209 l 533 -209 l 533 -54 l 812 -54 l 812 0 l 473 0 l p ef +1220 -159 m 1280 -144 l 1268 -95 1245 -57 1212 -31 ct 1180 -5 1140 8 1092 8 ct +1043 8 1003 -2 973 -22 ct 942 -42 919 -71 903 -109 ct 887 -147 879 -187 879 -231 ct +879 -278 888 -319 906 -355 ct 924 -390 950 -417 983 -435 ct 1016 -453 1053 -463 1093 -463 ct +1139 -463 1177 -451 1208 -428 ct 1239 -405 1261 -372 1273 -330 ct 1213 -316 l +1203 -349 1188 -373 1168 -388 ct 1148 -403 1122 -411 1092 -411 ct 1057 -411 1028 -403 1004 -386 ct +981 -369 964 -347 955 -318 ct 945 -290 941 -261 941 -231 ct 941 -192 946 -159 958 -130 ct +969 -101 986 -79 1010 -65 ct 1034 -51 1060 -44 1087 -44 ct 1121 -44 1150 -53 1173 -73 ct +1196 -92 1212 -121 1220 -159 ct p ef +pom +gr +gr +17600 9525 m 17549 9525 l 17549 9475 l 17600 9475 l 17600 9525 l p ef +17498 9525 m 17447 9525 l 17447 9475 l 17498 9475 l 17498 9525 l p ef +17396 9525 m 17345 9525 l 17345 9475 l 17396 9475 l 17396 9525 l p ef +17294 9525 m 17243 9525 l 17243 9475 l 17294 9475 l 17294 9525 l p ef +17192 9525 m 17141 9525 l 17141 9475 l 17192 9475 l 17192 9525 l p ef +17090 9525 m 17039 9525 l 17039 9475 l 17090 9475 l 17090 9525 l p ef +16988 9525 m 16937 9525 l 16937 9475 l 16988 9475 l 16988 9525 l p ef +16886 9525 m 16835 9525 l 16835 9475 l 16886 9475 l 16886 9525 l p ef +16784 9525 m 16733 9525 l 16733 9475 l 16784 9475 l 16784 9525 l p ef +16682 9525 m 16631 9525 l 16631 9475 l 16682 9475 l 16682 9525 l p ef +16580 9525 m 16529 9525 l 16529 9475 l 16580 9475 l 16580 9525 l p ef +16478 9525 m 16427 9525 l 16427 9475 l 16478 9475 l 16478 9525 l p ef +16376 9525 m 16325 9525 l 16325 9475 l 16376 9475 l 16376 9525 l p ef +16274 9525 m 16223 9525 l 16223 9475 l 16274 9475 l 16274 9525 l p ef +16172 9525 m 16121 9525 l 16121 9475 l 16172 9475 l 16172 9525 l p ef +16070 9525 m 16019 9525 l 16019 9475 l 16070 9475 l 16070 9525 l p ef +15968 9525 m 15917 9525 l 15917 9475 l 15968 9475 l 15968 9525 l p ef +15866 9525 m 15815 9525 l 15815 9475 l 15866 9475 l 15866 9525 l p ef +15764 9525 m 15713 9525 l 15713 9475 l 15764 9475 l 15764 9525 l p ef +15662 9525 m 15611 9525 l 15611 9475 l 15662 9475 l 15662 9525 l p ef +15560 9525 m 15509 9525 l 15509 9475 l 15560 9475 l 15560 9525 l p ef +15458 9525 m 15407 9525 l 15407 9475 l 15458 9475 l 15458 9525 l p ef +15375 9456 m 15375 9405 l 15425 9405 l 15425 9456 l 15375 9456 l p ef +15375 9354 m 15375 9303 l 15425 9303 l 15425 9354 l 15375 9354 l p ef +15375 9252 m 15375 9201 l 15425 9201 l 15425 9252 l 15375 9252 l p ef +15375 9150 m 15375 9099 l 15425 9099 l 15425 9150 l 15375 9150 l p ef +15375 9048 m 15375 8997 l 15425 8997 l 15425 9048 l 15375 9048 l p ef +15375 8946 m 15375 8895 l 15425 8895 l 15425 8946 l 15375 8946 l p ef +15375 8844 m 15375 8793 l 15425 8793 l 15425 8844 l 15375 8844 l p ef +15375 8742 m 15375 8691 l 15425 8691 l 15425 8742 l 15375 8742 l p ef +15375 8640 m 15375 8589 l 15425 8589 l 15425 8640 l 15375 8640 l p ef +15375 8538 m 15375 8487 l 15425 8487 l 15425 8538 l 15375 8538 l p ef +15375 8436 m 15375 8385 l 15425 8385 l 15425 8436 l 15375 8436 l p ef +15375 8334 m 15375 8283 l 15425 8283 l 15425 8334 l 15375 8334 l p ef +15375 8232 m 15375 8181 l 15425 8181 l 15425 8232 l 15375 8232 l p ef +15375 8130 m 15375 8079 l 15425 8079 l 15425 8130 l 15375 8130 l p ef +15375 8028 m 15375 8000 l 15400 8000 l 15425 8000 l 15425 8028 l 15400 8028 l +15375 8028 l p ef +15400 8000 m 15375 8000 l 15375 7996 l 15377 7991 l 15378 7988 l 15381 7984 l +15384 7981 l 15387 7978 l 15391 7977 l 15396 7975 l 15400 7975 l 15400 7975 l +15400 8000 l p ef +15400 7975 m 15423 7975 l 15423 8000 l 15423 8025 l 15400 8025 l 15400 8000 l +15400 7975 l p ef +15474 7975 m 15525 7975 l 15525 8025 l 15474 8025 l 15474 7975 l p ef +15576 7975 m 15627 7975 l 15627 8025 l 15576 8025 l 15576 7975 l p ef +15678 7975 m 15729 7975 l 15729 8025 l 15678 8025 l 15678 7975 l p ef +15780 7975 m 15831 7975 l 15831 8025 l 15780 8025 l 15780 7975 l p ef +15882 7975 m 15933 7975 l 15933 8025 l 15882 8025 l 15882 7975 l p ef +15984 7975 m 16035 7975 l 16035 8025 l 15984 8025 l 15984 7975 l p ef +16086 7975 m 16137 7975 l 16137 8025 l 16086 8025 l 16086 7975 l p ef +16188 7975 m 16239 7975 l 16239 8025 l 16188 8025 l 16188 7975 l p ef +16290 7975 m 16341 7975 l 16341 8025 l 16290 8025 l 16290 7975 l p ef +16392 7975 m 16443 7975 l 16443 8025 l 16392 8025 l 16392 7975 l p ef +16494 7975 m 16545 7975 l 16545 8025 l 16494 8025 l 16494 7975 l p ef +16596 7975 m 16647 7975 l 16647 8025 l 16596 8025 l 16596 7975 l p ef +16698 7975 m 16749 7975 l 16749 8025 l 16698 8025 l 16698 7975 l p ef +16800 7975 m 16851 7975 l 16851 8025 l 16800 8025 l 16800 7975 l p ef +16902 7975 m 16953 7975 l 16953 8025 l 16902 8025 l 16902 7975 l p ef +17004 7975 m 17055 7975 l 17055 8025 l 17004 8025 l 17004 7975 l p ef +17106 7975 m 17157 7975 l 17157 8025 l 17106 8025 l 17106 7975 l p ef +17208 7975 m 17259 7975 l 17259 8025 l 17208 8025 l 17208 7975 l p ef +17310 7975 m 17361 7975 l 17361 8025 l 17310 8025 l 17310 7975 l p ef +17412 7975 m 17463 7975 l 17463 8025 l 17412 8025 l 17412 7975 l p ef +17514 7975 m 17565 7975 l 17565 8025 l 17514 8025 l 17514 7975 l p ef +17616 7975 m 17667 7975 l 17667 8025 l 17616 8025 l 17616 7975 l p ef +17718 7975 m 17769 7975 l 17769 8025 l 17718 8025 l 17718 7975 l p ef +17820 7975 m 17871 7975 l 17871 8025 l 17820 8025 l 17820 7975 l p ef +17922 7975 m 17973 7975 l 17973 8025 l 17922 8025 l 17922 7975 l p ef +18024 7975 m 18075 7975 l 18075 8025 l 18024 8025 l 18024 7975 l p ef +18126 7975 m 18177 7975 l 18177 8025 l 18126 8025 l 18126 7975 l p ef +18228 7975 m 18279 7975 l 18279 8025 l 18228 8025 l 18228 7975 l p ef +18330 7975 m 18381 7975 l 18381 8025 l 18330 8025 l 18330 7975 l p ef +18432 7975 m 18483 7975 l 18483 8025 l 18432 8025 l 18432 7975 l p ef +18534 7975 m 18585 7975 l 18585 8025 l 18534 8025 l 18534 7975 l p ef +18636 7975 m 18687 7975 l 18687 8025 l 18636 8025 l 18636 7975 l p ef +18738 7975 m 18789 7975 l 18789 8025 l 18738 8025 l 18738 7975 l p ef +18840 7975 m 18891 7975 l 18891 8025 l 18840 8025 l 18840 7975 l p ef +18942 7975 m 18993 7975 l 18993 8025 l 18942 8025 l 18942 7975 l p ef +19044 7975 m 19095 7975 l 19095 8025 l 19044 8025 l 19044 7975 l p ef +19146 7975 m 19197 7975 l 19197 8025 l 19146 8025 l 19146 7975 l p ef +19248 7975 m 19299 7975 l 19299 8025 l 19248 8025 l 19248 7975 l p ef +19350 7975 m 19401 7975 l 19401 8025 l 19350 8025 l 19350 7975 l p ef +19452 7975 m 19503 7975 l 19503 8025 l 19452 8025 l 19452 7975 l p ef +19554 7975 m 19605 7975 l 19605 8025 l 19554 8025 l 19554 7975 l p ef +19656 7975 m 19707 7975 l 19707 8025 l 19656 8025 l 19656 7975 l p ef +19758 7975 m 19800 7975 l 19800 8000 l 19800 8025 l 19758 8025 l 19758 8000 l +19758 7975 l p ef +19800 8000 m 19800 7975 l 19804 7975 l 19809 7977 l 19812 7978 l 19816 7981 l +19819 7984 l 19822 7987 l 19823 7991 l 19825 7996 l 19825 8000 l 19825 8000 l +19800 8000 l p ef +19825 8000 m 19825 8009 l 19800 8009 l 19775 8009 l 19775 8000 l 19800 8000 l +19825 8000 l p ef +19825 8060 m 19825 8111 l 19775 8111 l 19775 8060 l 19825 8060 l p ef +19825 8162 m 19825 8213 l 19775 8213 l 19775 8162 l 19825 8162 l p ef +19825 8264 m 19825 8315 l 19775 8315 l 19775 8264 l 19825 8264 l p ef +19825 8366 m 19825 8417 l 19775 8417 l 19775 8366 l 19825 8366 l p ef +19825 8468 m 19825 8519 l 19775 8519 l 19775 8468 l 19825 8468 l p ef +19825 8570 m 19825 8621 l 19775 8621 l 19775 8570 l 19825 8570 l p ef +19825 8672 m 19825 8723 l 19775 8723 l 19775 8672 l 19825 8672 l p ef +19825 8774 m 19825 8825 l 19775 8825 l 19775 8774 l 19825 8774 l p ef +19825 8876 m 19825 8927 l 19775 8927 l 19775 8876 l 19825 8876 l p ef +19825 8978 m 19825 9029 l 19775 9029 l 19775 8978 l 19825 8978 l p ef +19825 9080 m 19825 9131 l 19775 9131 l 19775 9080 l 19825 9080 l p ef +19825 9182 m 19825 9233 l 19775 9233 l 19775 9182 l 19825 9182 l p ef +19825 9284 m 19825 9335 l 19775 9335 l 19775 9284 l 19825 9284 l p ef +19825 9386 m 19825 9437 l 19775 9437 l 19775 9386 l 19825 9386 l p ef +19825 9488 m 19825 9500 l 19800 9500 l 19775 9500 l 19775 9488 l 19800 9488 l +19825 9488 l p ef +19800 9500 m 19825 9500 l 19825 9504 l 19823 9509 l 19822 9512 l 19819 9516 l +19816 9519 l 19813 9522 l 19809 9523 l 19804 9525 l 19800 9525 l 19800 9525 l +19800 9500 l p ef +19800 9525 m 19761 9525 l 19761 9500 l 19761 9475 l 19800 9475 l 19800 9500 l +19800 9525 l p ef +19710 9525 m 19659 9525 l 19659 9475 l 19710 9475 l 19710 9525 l p ef +19608 9525 m 19557 9525 l 19557 9475 l 19608 9475 l 19608 9525 l p ef +19506 9525 m 19455 9525 l 19455 9475 l 19506 9475 l 19506 9525 l p ef +19404 9525 m 19353 9525 l 19353 9475 l 19404 9475 l 19404 9525 l p ef +19302 9525 m 19251 9525 l 19251 9475 l 19302 9475 l 19302 9525 l p ef +19200 9525 m 19149 9525 l 19149 9475 l 19200 9475 l 19200 9525 l p ef +19098 9525 m 19047 9525 l 19047 9475 l 19098 9475 l 19098 9525 l p ef +18996 9525 m 18945 9525 l 18945 9475 l 18996 9475 l 18996 9525 l p ef +18894 9525 m 18843 9525 l 18843 9475 l 18894 9475 l 18894 9525 l p ef +18792 9525 m 18741 9525 l 18741 9475 l 18792 9475 l 18792 9525 l p ef +18690 9525 m 18639 9525 l 18639 9475 l 18690 9475 l 18690 9525 l p ef +18588 9525 m 18537 9525 l 18537 9475 l 18588 9475 l 18588 9525 l p ef +18486 9525 m 18435 9525 l 18435 9475 l 18486 9475 l 18486 9525 l p ef +18384 9525 m 18333 9525 l 18333 9475 l 18384 9475 l 18384 9525 l p ef +18282 9525 m 18231 9525 l 18231 9475 l 18282 9475 l 18282 9525 l p ef +18180 9525 m 18129 9525 l 18129 9475 l 18180 9475 l 18180 9525 l p ef +18078 9525 m 18027 9525 l 18027 9475 l 18078 9475 l 18078 9525 l p ef +17976 9525 m 17925 9525 l 17925 9475 l 17976 9475 l 17976 9525 l p ef +17874 9525 m 17823 9525 l 17823 9475 l 17874 9475 l 17874 9525 l p ef +17772 9525 m 17721 9525 l 17721 9475 l 17772 9475 l 17772 9525 l p ef +17670 9525 m 17619 9525 l 17619 9475 l 17670 9475 l 17670 9525 l p ef +gs +gs +pum +15705 8974 t +49 0 m 49 -455 l 220 -455 l 251 -455 274 -454 290 -451 ct 312 -447 331 -440 346 -429 ct +361 -419 373 -404 382 -385 ct 391 -367 396 -346 396 -323 ct 396 -285 384 -252 359 -225 ct +334 -198 290 -185 226 -185 ct 109 -185 l 109 0 l 49 0 l p +109 -239 m 227 -239 l 266 -239 293 -246 309 -260 ct 326 -275 334 -295 334 -322 ct +334 -341 329 -357 320 -370 ct 310 -384 297 -393 282 -397 ct 271 -400 253 -401 225 -401 ct +109 -401 l 109 -239 l p ef +464 0 m 464 -330 l 514 -330 l 514 -280 l 527 -303 539 -318 550 -326 ct +561 -333 573 -337 586 -337 ct 605 -337 624 -331 643 -319 ct 624 -267 l 610 -275 597 -279 583 -279 ct +571 -279 560 -276 550 -268 ct 540 -261 533 -251 529 -238 ct 523 -218 520 -196 520 -173 ct +520 0 l 464 0 l p ef +902 -107 m 960 -99 l 951 -66 934 -40 909 -21 ct 885 -2 853 7 815 7 ct 767 7 729 -8 701 -37 ct +672 -67 658 -109 658 -162 ct 658 -218 673 -261 701 -291 ct 730 -322 767 -337 812 -337 ct +856 -337 892 -322 920 -292 ct 948 -262 962 -220 962 -166 ct 962 -163 962 -158 961 -151 ct +716 -151 l 718 -115 728 -87 747 -68 ct 765 -49 788 -39 815 -39 ct 836 -39 853 -44 868 -55 ct +882 -66 894 -83 902 -107 ct p +719 -197 m 903 -197 l 900 -225 893 -245 882 -259 ct 864 -280 841 -291 813 -291 ct +787 -291 765 -283 748 -265 ct 731 -248 721 -226 719 -197 ct p ef +1028 126 m 1028 -330 l 1079 -330 l 1079 -287 l 1091 -304 1104 -316 1119 -324 ct +1134 -333 1153 -337 1174 -337 ct 1202 -337 1227 -330 1249 -315 ct 1270 -301 1286 -280 1297 -254 ct +1308 -228 1314 -199 1314 -167 ct 1314 -134 1308 -103 1296 -77 ct 1284 -50 1266 -29 1243 -15 ct +1220 0 1196 7 1170 7 ct 1152 7 1135 3 1120 -5 ct 1105 -13 1093 -23 1084 -35 ct +1084 126 l 1028 126 l p +1078 -163 m 1078 -121 1087 -90 1104 -69 ct 1121 -49 1142 -39 1166 -39 ct 1191 -39 1213 -49 1230 -70 ct +1248 -91 1257 -124 1257 -168 ct 1257 -210 1248 -241 1231 -262 ct 1214 -283 1193 -293 1169 -293 ct +1145 -293 1124 -282 1106 -260 ct 1088 -238 1078 -205 1078 -163 ct p ef +1379 0 m 1379 -330 l 1429 -330 l 1429 -280 l 1442 -303 1454 -318 1465 -326 ct +1476 -333 1488 -337 1501 -337 ct 1520 -337 1539 -331 1558 -319 ct 1539 -267 l +1525 -275 1512 -279 1498 -279 ct 1486 -279 1475 -276 1465 -268 ct 1455 -261 1448 -251 1444 -238 ct +1438 -218 1435 -196 1435 -173 ct 1435 0 l 1379 0 l p ef +1570 -165 m 1570 -226 1587 -271 1621 -301 ct 1649 -325 1684 -337 1725 -337 ct +1770 -337 1807 -322 1835 -293 ct 1864 -263 1879 -222 1879 -170 ct 1879 -127 1872 -94 1860 -70 ct +1847 -45 1828 -27 1804 -13 ct 1780 0 1753 7 1725 7 ct 1678 7 1641 -8 1613 -37 ct +1584 -67 1570 -110 1570 -165 ct p +1627 -165 m 1627 -123 1637 -91 1655 -70 ct 1673 -49 1697 -39 1725 -39 ct 1752 -39 1775 -49 1794 -71 ct +1812 -92 1821 -124 1821 -167 ct 1821 -208 1812 -239 1793 -260 ct 1775 -281 1752 -291 1725 -291 ct +1697 -291 1673 -281 1655 -260 ct 1637 -239 1627 -207 1627 -165 ct p ef +2158 -121 m 2213 -114 l 2207 -76 2191 -46 2167 -25 ct 2142 -4 2112 7 2076 7 ct +2031 7 1994 -8 1967 -37 ct 1940 -67 1926 -109 1926 -164 ct 1926 -199 1932 -230 1943 -257 ct +1955 -284 1973 -304 1997 -317 ct 2021 -330 2048 -337 2076 -337 ct 2112 -337 2141 -328 2164 -310 ct +2186 -292 2201 -266 2207 -233 ct 2153 -224 l 2148 -247 2139 -263 2126 -274 ct +2113 -286 2097 -291 2078 -291 ct 2050 -291 2027 -281 2010 -261 ct 1992 -241 1983 -209 1983 -165 ct +1983 -121 1992 -89 2009 -69 ct 2026 -49 2048 -39 2075 -39 ct 2097 -39 2115 -46 2130 -59 ct +2145 -72 2154 -93 2158 -121 ct p ef +2485 -107 m 2543 -99 l 2534 -66 2517 -40 2492 -21 ct 2468 -2 2436 7 2398 7 ct +2350 7 2312 -8 2284 -37 ct 2255 -67 2241 -109 2241 -162 ct 2241 -218 2256 -261 2284 -291 ct +2313 -322 2350 -337 2395 -337 ct 2439 -337 2475 -322 2503 -292 ct 2531 -262 2545 -220 2545 -166 ct +2545 -163 2545 -158 2544 -151 ct 2299 -151 l 2301 -115 2311 -87 2330 -68 ct +2348 -49 2371 -39 2398 -39 ct 2419 -39 2436 -44 2451 -55 ct 2465 -66 2477 -83 2485 -107 ct +p +2302 -197 m 2486 -197 l 2483 -225 2476 -245 2465 -259 ct 2447 -280 2424 -291 2396 -291 ct +2370 -291 2348 -283 2331 -265 ct 2314 -248 2304 -226 2302 -197 ct p ef +2590 -99 m 2645 -107 l 2648 -85 2656 -68 2671 -57 ct 2685 -45 2705 -39 2730 -39 ct +2756 -39 2775 -44 2787 -55 ct 2799 -65 2806 -77 2806 -91 ct 2806 -104 2800 -114 2789 -121 ct +2782 -126 2763 -132 2732 -140 ct 2691 -150 2663 -159 2647 -167 ct 2631 -174 2619 -185 2611 -198 ct +2603 -211 2599 -226 2599 -242 ct 2599 -257 2602 -270 2609 -283 ct 2616 -295 2625 -306 2636 -314 ct +2645 -320 2657 -326 2672 -330 ct 2687 -335 2703 -337 2720 -337 ct 2746 -337 2769 -333 2788 -326 ct +2808 -318 2822 -308 2831 -296 ct 2841 -283 2847 -266 2851 -245 ct 2796 -237 l +2794 -254 2786 -267 2774 -277 ct 2763 -286 2746 -291 2724 -291 ct 2698 -291 2680 -287 2669 -278 ct +2658 -270 2653 -260 2653 -249 ct 2653 -241 2655 -235 2660 -229 ct 2664 -223 2671 -218 2681 -214 ct +2687 -212 2703 -207 2730 -200 ct 2770 -189 2797 -181 2813 -174 ct 2829 -167 2841 -158 2850 -145 ct +2859 -132 2863 -116 2863 -97 ct 2863 -79 2858 -61 2847 -45 ct 2836 -28 2820 -15 2800 -6 ct +2779 3 2756 7 2730 7 ct 2688 7 2655 -2 2632 -20 ct 2610 -37 2596 -64 2590 -99 ct +p ef +2907 -99 m 2962 -107 l 2965 -85 2973 -68 2988 -57 ct 3002 -45 3022 -39 3047 -39 ct +3073 -39 3092 -44 3104 -55 ct 3116 -65 3123 -77 3123 -91 ct 3123 -104 3117 -114 3106 -121 ct +3099 -126 3080 -132 3049 -140 ct 3008 -150 2980 -159 2964 -167 ct 2948 -174 2936 -185 2928 -198 ct +2920 -211 2916 -226 2916 -242 ct 2916 -257 2919 -270 2926 -283 ct 2933 -295 2942 -306 2953 -314 ct +2962 -320 2974 -326 2989 -330 ct 3004 -335 3020 -337 3037 -337 ct 3063 -337 3086 -333 3105 -326 ct +3125 -318 3139 -308 3148 -296 ct 3158 -283 3164 -266 3168 -245 ct 3113 -237 l +3111 -254 3103 -267 3091 -277 ct 3080 -286 3063 -291 3041 -291 ct 3015 -291 2997 -287 2986 -278 ct +2975 -270 2970 -260 2970 -249 ct 2970 -241 2972 -235 2977 -229 ct 2981 -223 2988 -218 2998 -214 ct +3004 -212 3020 -207 3047 -200 ct 3087 -189 3114 -181 3130 -174 ct 3146 -167 3158 -158 3167 -145 ct +3176 -132 3180 -116 3180 -97 ct 3180 -79 3175 -61 3164 -45 ct 3153 -28 3137 -15 3117 -6 ct +3096 3 3073 7 3047 7 ct 3005 7 2972 -2 2949 -20 ct 2927 -37 2913 -64 2907 -99 ct +p ef +3226 -165 m 3226 -226 3243 -271 3277 -301 ct 3305 -325 3340 -337 3381 -337 ct +3426 -337 3463 -322 3491 -293 ct 3520 -263 3535 -222 3535 -170 ct 3535 -127 3528 -94 3516 -70 ct +3503 -45 3484 -27 3460 -13 ct 3436 0 3409 7 3381 7 ct 3334 7 3297 -8 3269 -37 ct +3240 -67 3226 -110 3226 -165 ct p +3283 -165 m 3283 -123 3293 -91 3311 -70 ct 3329 -49 3353 -39 3381 -39 ct 3408 -39 3431 -49 3450 -71 ct +3468 -92 3477 -124 3477 -167 ct 3477 -208 3468 -239 3449 -260 ct 3431 -281 3408 -291 3381 -291 ct +3353 -291 3329 -281 3311 -260 ct 3293 -239 3283 -207 3283 -165 ct p ef +3597 0 m 3597 -330 l 3647 -330 l 3647 -280 l 3660 -303 3672 -318 3683 -326 ct +3694 -333 3706 -337 3719 -337 ct 3738 -337 3757 -331 3776 -319 ct 3757 -267 l +3743 -275 3730 -279 3716 -279 ct 3704 -279 3693 -276 3683 -268 ct 3673 -261 3666 -251 3662 -238 ct +3656 -218 3653 -196 3653 -173 ct 3653 0 l 3597 0 l p ef +pom +gr +gr +4400 13500 m 2900 13500 l 2900 12000 l 5900 12000 l 5900 13500 l 4400 13500 l +pc +gs +gs +pum +3122 12970 t +49 0 m 49 -455 l 220 -455 l 251 -455 274 -454 290 -451 ct 312 -447 331 -440 346 -429 ct +361 -419 373 -404 382 -385 ct 391 -367 396 -346 396 -323 ct 396 -285 384 -252 359 -225 ct +334 -198 290 -185 226 -185 ct 109 -185 l 109 0 l 49 0 l p +109 -239 m 227 -239 l 266 -239 293 -246 309 -260 ct 326 -275 334 -295 334 -322 ct +334 -341 329 -357 320 -370 ct 310 -384 297 -393 282 -397 ct 271 -400 253 -401 225 -401 ct +109 -401 l 109 -239 l p ef +464 0 m 464 -455 l 519 -455 l 519 0 l 464 0 l p ef +820 -41 m 799 -24 779 -11 760 -4 ct 741 3 720 7 699 7 ct 662 7 635 -2 615 -20 ct +596 -37 586 -60 586 -87 ct 586 -103 590 -118 597 -131 ct 604 -145 614 -156 626 -164 ct +638 -172 651 -178 666 -182 ct 677 -185 693 -188 716 -190 ct 761 -196 794 -202 815 -209 ct +815 -217 815 -222 815 -224 ct 815 -247 810 -263 800 -272 ct 785 -285 764 -291 736 -291 ct +710 -291 690 -286 678 -277 ct 665 -268 656 -252 650 -228 ct 596 -236 l 601 -259 609 -278 620 -292 ct +631 -307 648 -318 669 -326 ct 691 -333 716 -337 744 -337 ct 772 -337 795 -334 813 -327 ct +830 -321 843 -312 851 -302 ct 860 -292 865 -280 869 -264 ct 871 -255 872 -238 872 -213 ct +872 -138 l 872 -87 873 -54 875 -40 ct 877 -26 882 -13 889 0 ct 831 0 l 825 -12 821 -26 820 -41 ct +p +815 -166 m 795 -157 764 -150 724 -145 ct 701 -141 685 -138 675 -133 ct 666 -129 658 -123 653 -115 ct +648 -107 645 -99 645 -89 ct 645 -74 651 -62 662 -52 ct 674 -42 690 -37 712 -37 ct +733 -37 752 -41 769 -51 ct 786 -60 798 -73 806 -89 ct 812 -102 815 -121 815 -145 ct +815 -166 l p ef +953 127 m 947 75 l 959 78 970 80 979 80 ct 992 80 1001 78 1009 73 ct 1016 69 1022 64 1027 56 ct +1031 51 1036 37 1044 15 ct 1045 11 1047 7 1049 1 ct 924 -330 l 984 -330 l 1053 -139 l +1062 -114 1070 -89 1077 -62 ct 1083 -88 1091 -113 1100 -137 ct 1170 -330 l 1226 -330 l +1101 6 l 1087 42 1077 67 1069 81 ct 1059 99 1048 113 1035 121 ct 1022 130 1007 134 989 134 ct +979 134 967 132 953 127 ct p ef +1316 0 m 1265 0 l 1265 -455 l 1320 -455 l 1320 -293 l 1344 -322 1374 -337 1411 -337 ct +1431 -337 1450 -333 1468 -325 ct 1486 -317 1501 -305 1513 -290 ct 1524 -276 1534 -258 1540 -237 ct +1547 -216 1550 -194 1550 -170 ct 1550 -114 1536 -70 1508 -39 ct 1480 -8 1447 7 1408 7 ct +1369 7 1338 -9 1316 -42 ct 1316 0 l p +1316 -167 m 1316 -128 1321 -100 1332 -82 ct 1349 -53 1373 -39 1403 -39 ct 1428 -39 1449 -50 1466 -71 ct +1484 -92 1493 -123 1493 -165 ct 1493 -208 1485 -240 1467 -260 ct 1450 -281 1430 -291 1406 -291 ct +1381 -291 1360 -281 1342 -259 ct 1325 -238 1316 -208 1316 -167 ct p ef +1832 -41 m 1811 -24 1791 -11 1772 -4 ct 1753 3 1732 7 1711 7 ct 1674 7 1647 -2 1627 -20 ct +1608 -37 1598 -60 1598 -87 ct 1598 -103 1602 -118 1609 -131 ct 1616 -145 1626 -156 1638 -164 ct +1650 -172 1663 -178 1678 -182 ct 1689 -185 1705 -188 1728 -190 ct 1773 -196 1806 -202 1827 -209 ct +1827 -217 1827 -222 1827 -224 ct 1827 -247 1822 -263 1812 -272 ct 1797 -285 1776 -291 1748 -291 ct +1722 -291 1702 -286 1690 -277 ct 1677 -268 1668 -252 1662 -228 ct 1608 -236 l +1613 -259 1621 -278 1632 -292 ct 1643 -307 1660 -318 1681 -326 ct 1703 -333 1728 -337 1756 -337 ct +1784 -337 1807 -334 1825 -327 ct 1842 -321 1855 -312 1863 -302 ct 1872 -292 1877 -280 1881 -264 ct +1883 -255 1884 -238 1884 -213 ct 1884 -138 l 1884 -87 1885 -54 1887 -40 ct +1889 -26 1894 -13 1901 0 ct 1843 0 l 1837 -12 1833 -26 1832 -41 ct p +1827 -166 m 1807 -157 1776 -150 1736 -145 ct 1713 -141 1697 -138 1687 -133 ct +1678 -129 1670 -123 1665 -115 ct 1660 -107 1657 -99 1657 -89 ct 1657 -74 1663 -62 1674 -52 ct +1686 -42 1702 -37 1724 -37 ct 1745 -37 1764 -41 1781 -51 ct 1798 -60 1810 -73 1818 -89 ct +1824 -102 1827 -121 1827 -145 ct 1827 -166 l p ef +2183 -121 m 2238 -114 l 2232 -76 2216 -46 2192 -25 ct 2167 -4 2137 7 2101 7 ct +2056 7 2019 -8 1992 -37 ct 1965 -67 1951 -109 1951 -164 ct 1951 -199 1957 -230 1968 -257 ct +1980 -284 1998 -304 2022 -317 ct 2046 -330 2073 -337 2101 -337 ct 2137 -337 2166 -328 2189 -310 ct +2211 -292 2226 -266 2232 -233 ct 2178 -224 l 2173 -247 2164 -263 2151 -274 ct +2138 -286 2122 -291 2103 -291 ct 2075 -291 2052 -281 2035 -261 ct 2017 -241 2008 -209 2008 -165 ct +2008 -121 2017 -89 2034 -69 ct 2051 -49 2073 -39 2100 -39 ct 2122 -39 2140 -46 2155 -59 ct +2170 -72 2179 -93 2183 -121 ct p ef +2286 0 m 2286 -455 l 2342 -455 l 2342 -196 l 2474 -330 l 2546 -330 l +2420 -207 l 2559 0 l 2490 0 l 2381 -169 l 2342 -131 l 2342 0 l 2286 0 l +p ef +pom +gr +gr +22600 9500 m 21100 9500 l 21100 8000 l 24100 8000 l 24100 9500 l 22600 9500 l +pc +gs +gs +pum +21425 8974 t +50 0 m 50 -455 l 379 -455 l 379 -401 l 110 -401 l 110 -262 l 362 -262 l +362 -209 l 110 -209 l 110 -54 l 389 -54 l 389 0 l 50 0 l p ef +465 0 m 465 -330 l 515 -330 l 515 -283 l 539 -319 574 -337 620 -337 ct +640 -337 658 -333 675 -326 ct 691 -319 704 -310 712 -298 ct 720 -287 726 -273 729 -257 ct +731 -247 732 -229 732 -203 ct 732 0 l 677 0 l 677 -200 l 677 -223 674 -240 670 -252 ct +666 -263 658 -272 647 -279 ct 636 -285 623 -289 608 -289 ct 584 -289 564 -281 547 -266 ct +529 -251 521 -222 521 -180 ct 521 0 l 465 0 l p ef +1032 -121 m 1087 -114 l 1081 -76 1065 -46 1041 -25 ct 1016 -4 986 7 950 7 ct +905 7 868 -8 841 -37 ct 814 -67 800 -109 800 -164 ct 800 -199 806 -230 817 -257 ct +829 -284 847 -304 871 -317 ct 895 -330 922 -337 950 -337 ct 986 -337 1015 -328 1038 -310 ct +1060 -292 1075 -266 1081 -233 ct 1027 -224 l 1022 -247 1013 -263 1000 -274 ct +987 -286 971 -291 952 -291 ct 924 -291 901 -281 884 -261 ct 866 -241 857 -209 857 -165 ct +857 -121 866 -89 883 -69 ct 900 -49 922 -39 949 -39 ct 971 -39 989 -46 1004 -59 ct +1019 -72 1028 -93 1032 -121 ct p ef +1113 -165 m 1113 -226 1130 -271 1164 -301 ct 1192 -325 1227 -337 1268 -337 ct +1313 -337 1350 -322 1378 -293 ct 1407 -263 1422 -222 1422 -170 ct 1422 -127 1415 -94 1403 -70 ct +1390 -45 1371 -27 1347 -13 ct 1323 0 1296 7 1268 7 ct 1221 7 1184 -8 1156 -37 ct +1127 -67 1113 -110 1113 -165 ct p +1170 -165 m 1170 -123 1180 -91 1198 -70 ct 1216 -49 1240 -39 1268 -39 ct 1295 -39 1318 -49 1337 -71 ct +1355 -92 1364 -124 1364 -167 ct 1364 -208 1355 -239 1336 -260 ct 1318 -281 1295 -291 1268 -291 ct +1240 -291 1216 -281 1198 -260 ct 1180 -239 1170 -207 1170 -165 ct p ef +1699 0 m 1699 -42 l 1679 -9 1648 7 1607 7 ct 1581 7 1557 0 1535 -15 ct 1513 -29 1496 -49 1484 -75 ct +1472 -101 1466 -131 1466 -165 ct 1466 -198 1471 -228 1482 -254 ct 1493 -281 1510 -302 1531 -316 ct +1553 -330 1578 -337 1605 -337 ct 1625 -337 1642 -333 1658 -325 ct 1673 -316 1686 -305 1696 -292 ct +1696 -455 l 1751 -455 l 1751 0 l 1699 0 l p +1523 -165 m 1523 -123 1532 -91 1550 -70 ct 1568 -49 1588 -39 1613 -39 ct 1637 -39 1658 -49 1675 -69 ct +1692 -89 1700 -119 1700 -160 ct 1700 -205 1692 -238 1674 -259 ct 1657 -280 1636 -291 1610 -291 ct +1585 -291 1565 -281 1548 -261 ct 1531 -240 1523 -208 1523 -165 ct p ef +2062 -107 m 2120 -99 l 2111 -66 2094 -40 2069 -21 ct 2045 -2 2013 7 1975 7 ct +1927 7 1889 -8 1861 -37 ct 1832 -67 1818 -109 1818 -162 ct 1818 -218 1833 -261 1861 -291 ct +1890 -322 1927 -337 1972 -337 ct 2016 -337 2052 -322 2080 -292 ct 2108 -262 2122 -220 2122 -166 ct +2122 -163 2122 -158 2121 -151 ct 1876 -151 l 1878 -115 1888 -87 1907 -68 ct +1925 -49 1948 -39 1975 -39 ct 1996 -39 2013 -44 2028 -55 ct 2042 -66 2054 -83 2062 -107 ct +p +1879 -197 m 2063 -197 l 2060 -225 2053 -245 2042 -259 ct 2024 -280 2001 -291 1973 -291 ct +1947 -291 1925 -283 1908 -265 ct 1891 -248 1881 -226 1879 -197 ct p ef +2187 0 m 2187 -330 l 2237 -330 l 2237 -280 l 2250 -303 2262 -318 2273 -326 ct +2284 -333 2296 -337 2309 -337 ct 2328 -337 2347 -331 2366 -319 ct 2347 -267 l +2333 -275 2320 -279 2306 -279 ct 2294 -279 2283 -276 2273 -268 ct 2263 -261 2256 -251 2252 -238 ct +2246 -218 2243 -196 2243 -173 ct 2243 0 l 2187 0 l p ef +pom +gr +gr +17400 13500 m 15900 13500 l 15900 12000 l 18900 12000 l 18900 13500 l +17400 13500 l pc +gs +gs +pum +16195 12970 t +49 0 m 49 -455 l 206 -455 l 241 -455 268 -453 287 -448 ct 313 -442 335 -432 353 -416 ct +377 -396 395 -370 407 -338 ct 419 -307 425 -271 425 -230 ct 425 -195 421 -165 413 -138 ct +405 -111 394 -89 382 -72 ct 369 -54 355 -41 340 -31 ct 325 -21 307 -13 286 -8 ct +265 -3 241 0 213 0 ct 49 0 l p +109 -54 m 206 -54 l 236 -54 260 -56 277 -62 ct 294 -68 307 -76 318 -86 ct +332 -100 343 -119 351 -143 ct 359 -167 363 -197 363 -231 ct 363 -279 355 -315 339 -341 ct +324 -366 305 -383 282 -392 ct 266 -398 240 -401 205 -401 ct 109 -401 l 109 -54 l +p ef +724 -107 m 782 -99 l 773 -66 756 -40 731 -21 ct 707 -2 675 7 637 7 ct 589 7 551 -8 523 -37 ct +494 -67 480 -109 480 -162 ct 480 -218 495 -261 523 -291 ct 552 -322 589 -337 634 -337 ct +678 -337 714 -322 742 -292 ct 770 -262 784 -220 784 -166 ct 784 -163 784 -158 783 -151 ct +538 -151 l 540 -115 550 -87 569 -68 ct 587 -49 610 -39 637 -39 ct 658 -39 675 -44 690 -55 ct +704 -66 716 -83 724 -107 ct p +541 -197 m 725 -197 l 722 -225 715 -245 704 -259 ct 686 -280 663 -291 635 -291 ct +609 -291 587 -283 570 -265 ct 553 -248 543 -226 541 -197 ct p ef +1066 -121 m 1121 -114 l 1115 -76 1099 -46 1075 -25 ct 1050 -4 1020 7 984 7 ct +939 7 902 -8 875 -37 ct 848 -67 834 -109 834 -164 ct 834 -199 840 -230 851 -257 ct +863 -284 881 -304 905 -317 ct 929 -330 956 -337 984 -337 ct 1020 -337 1049 -328 1072 -310 ct +1094 -292 1109 -266 1115 -233 ct 1061 -224 l 1056 -247 1047 -263 1034 -274 ct +1021 -286 1005 -291 986 -291 ct 958 -291 935 -281 918 -261 ct 900 -241 891 -209 891 -165 ct +891 -121 900 -89 917 -69 ct 934 -49 956 -39 983 -39 ct 1005 -39 1023 -46 1038 -59 ct +1053 -72 1062 -93 1066 -121 ct p ef +1147 -165 m 1147 -226 1164 -271 1198 -301 ct 1226 -325 1261 -337 1302 -337 ct +1347 -337 1384 -322 1412 -293 ct 1441 -263 1456 -222 1456 -170 ct 1456 -127 1449 -94 1437 -70 ct +1424 -45 1405 -27 1381 -13 ct 1357 0 1330 7 1302 7 ct 1255 7 1218 -8 1190 -37 ct +1161 -67 1147 -110 1147 -165 ct p +1204 -165 m 1204 -123 1214 -91 1232 -70 ct 1250 -49 1274 -39 1302 -39 ct 1329 -39 1352 -49 1371 -71 ct +1389 -92 1398 -124 1398 -167 ct 1398 -208 1389 -239 1370 -260 ct 1352 -281 1329 -291 1302 -291 ct +1274 -291 1250 -281 1232 -260 ct 1214 -239 1204 -207 1204 -165 ct p ef +1732 0 m 1732 -42 l 1712 -9 1681 7 1640 7 ct 1614 7 1590 0 1568 -15 ct 1546 -29 1529 -49 1517 -75 ct +1505 -101 1499 -131 1499 -165 ct 1499 -198 1504 -228 1515 -254 ct 1526 -281 1543 -302 1564 -316 ct +1586 -330 1611 -337 1638 -337 ct 1658 -337 1675 -333 1691 -325 ct 1706 -316 1719 -305 1729 -292 ct +1729 -455 l 1784 -455 l 1784 0 l 1732 0 l p +1556 -165 m 1556 -123 1565 -91 1583 -70 ct 1601 -49 1621 -39 1646 -39 ct 1670 -39 1691 -49 1708 -69 ct +1725 -89 1733 -119 1733 -160 ct 1733 -205 1725 -238 1707 -259 ct 1690 -280 1669 -291 1643 -291 ct +1618 -291 1598 -281 1581 -261 ct 1564 -240 1556 -208 1556 -165 ct p ef +2096 -107 m 2154 -99 l 2145 -66 2128 -40 2103 -21 ct 2079 -2 2047 7 2009 7 ct +1961 7 1923 -8 1895 -37 ct 1866 -67 1852 -109 1852 -162 ct 1852 -218 1867 -261 1895 -291 ct +1924 -322 1961 -337 2006 -337 ct 2050 -337 2086 -322 2114 -292 ct 2142 -262 2156 -220 2156 -166 ct +2156 -163 2156 -158 2155 -151 ct 1910 -151 l 1912 -115 1922 -87 1941 -68 ct +1959 -49 1982 -39 2009 -39 ct 2030 -39 2047 -44 2062 -55 ct 2076 -66 2088 -83 2096 -107 ct +p +1913 -197 m 2097 -197 l 2094 -225 2087 -245 2076 -259 ct 2058 -280 2035 -291 2007 -291 ct +1981 -291 1959 -283 1942 -265 ct 1925 -248 1915 -226 1913 -197 ct p ef +2221 0 m 2221 -330 l 2271 -330 l 2271 -280 l 2284 -303 2296 -318 2307 -326 ct +2318 -333 2330 -337 2343 -337 ct 2362 -337 2381 -331 2400 -319 ct 2381 -267 l +2367 -275 2354 -279 2340 -279 ct 2328 -279 2317 -276 2307 -268 ct 2297 -261 2290 -251 2286 -238 ct +2280 -218 2277 -196 2277 -173 ct 2277 0 l 2221 0 l p ef +pom +gr +gr +22600 13500 m 21100 13500 l 21100 12000 l 24100 12000 l 24100 13500 l +22600 13500 l pc +gs +gs +pum +21916 12626 t +18 -129 m 73 -136 l 74 -102 81 -78 92 -65 ct 104 -52 120 -46 140 -46 ct 155 -46 168 -49 179 -56 ct +190 -63 198 -72 202 -84 ct 206 -96 208 -115 208 -141 ct 208 -455 l 268 -455 l +268 -145 l 268 -107 264 -77 254 -56 ct 245 -35 231 -19 211 -8 ct 191 3 167 8 140 8 ct +101 8 70 -3 49 -26 ct 28 -49 17 -84 18 -129 ct p ef +360 -391 m 360 -455 l 416 -455 l 416 -391 l 360 -391 l p +360 0 m 360 -330 l 416 -330 l 416 0 l 360 0 l p ef +621 -50 m 629 -1 l 613 2 599 4 587 4 ct 566 4 551 1 539 -6 ct 528 -12 520 -20 516 -31 ct +511 -41 509 -63 509 -97 ct 509 -287 l 468 -287 l 468 -330 l 509 -330 l +509 -412 l 565 -445 l 565 -330 l 621 -330 l 621 -287 l 565 -287 l +565 -94 l 565 -78 566 -68 568 -63 ct 570 -58 573 -55 577 -52 ct 582 -49 588 -48 596 -48 ct +602 -48 611 -49 621 -50 ct p ef +799 -50 m 807 -1 l 791 2 777 4 765 4 ct 744 4 729 1 717 -6 ct 706 -12 698 -20 694 -31 ct +689 -41 687 -63 687 -97 ct 687 -287 l 646 -287 l 646 -330 l 687 -330 l +687 -412 l 743 -445 l 743 -330 l 799 -330 l 799 -287 l 743 -287 l +743 -94 l 743 -78 744 -68 746 -63 ct 748 -58 751 -55 755 -52 ct 760 -49 766 -48 774 -48 ct +780 -48 789 -49 799 -50 ct p ef +1080 -107 m 1138 -99 l 1129 -66 1112 -40 1087 -21 ct 1063 -2 1031 7 993 7 ct +945 7 907 -8 879 -37 ct 850 -67 836 -109 836 -162 ct 836 -218 851 -261 879 -291 ct +908 -322 945 -337 990 -337 ct 1034 -337 1070 -322 1098 -292 ct 1126 -262 1140 -220 1140 -166 ct +1140 -163 1140 -158 1139 -151 ct 894 -151 l 896 -115 906 -87 925 -68 ct 943 -49 966 -39 993 -39 ct +1014 -39 1031 -44 1046 -55 ct 1060 -66 1072 -83 1080 -107 ct p +897 -197 m 1081 -197 l 1078 -225 1071 -245 1060 -259 ct 1042 -280 1019 -291 991 -291 ct +965 -291 943 -283 926 -265 ct 909 -248 899 -226 897 -197 ct p ef +1205 0 m 1205 -330 l 1255 -330 l 1255 -280 l 1268 -303 1280 -318 1291 -326 ct +1302 -333 1314 -337 1327 -337 ct 1346 -337 1365 -331 1384 -319 ct 1365 -267 l +1351 -275 1338 -279 1324 -279 ct 1312 -279 1301 -276 1291 -268 ct 1281 -261 1274 -251 1270 -238 ct +1264 -218 1261 -196 1261 -173 ct 1261 0 l 1205 0 l p ef +pom +gr +gs +pum +21764 13337 t +47 0 m 47 -455 l 217 -455 l 252 -455 280 -450 301 -441 ct 322 -432 338 -418 350 -399 ct +362 -380 368 -359 368 -339 ct 368 -319 362 -301 352 -284 ct 341 -266 325 -253 304 -242 ct +332 -234 353 -220 368 -201 ct 382 -181 390 -158 390 -132 ct 390 -111 385 -91 376 -72 ct +367 -54 356 -40 343 -30 ct 330 -20 313 -13 293 -8 ct 273 -3 249 0 220 0 ct 47 0 l +p +107 -264 m 205 -264 l 232 -264 251 -265 262 -269 ct 278 -274 289 -281 297 -292 ct +305 -302 309 -315 309 -331 ct 309 -347 305 -360 298 -371 ct 290 -383 280 -391 267 -395 ct +253 -399 230 -401 198 -401 ct 107 -401 l 107 -264 l p +107 -54 m 220 -54 l 239 -54 253 -54 261 -56 ct 275 -58 286 -62 295 -68 ct +305 -74 312 -82 318 -94 ct 324 -105 327 -117 327 -132 ct 327 -149 323 -164 314 -176 ct +306 -189 294 -197 278 -202 ct 263 -207 241 -210 212 -210 ct 107 -210 l 107 -54 l +p ef +681 0 m 681 -49 l 655 -12 620 7 576 7 ct 557 7 539 3 522 -4 ct 505 -12 492 -21 484 -32 ct +476 -44 470 -57 467 -74 ct 465 -85 464 -102 464 -126 ct 464 -330 l 519 -330 l +519 -147 l 519 -118 521 -98 523 -88 ct 526 -74 534 -62 545 -54 ct 557 -45 571 -41 587 -41 ct +604 -41 620 -45 634 -54 ct 649 -63 660 -74 666 -89 ct 672 -104 675 -125 675 -153 ct +675 -330 l 731 -330 l 731 0 l 681 0 l p ef +830 0 m 830 -286 l 781 -286 l 781 -329 l 830 -329 l 830 -364 l 830 -387 832 -403 836 -414 ct +841 -428 851 -440 864 -449 ct 878 -458 897 -462 921 -462 ct 937 -462 954 -460 973 -457 ct +965 -408 l 953 -410 943 -411 932 -411 ct 915 -411 903 -407 896 -400 ct 889 -393 886 -379 886 -360 ct +886 -329 l 950 -329 l 950 -286 l 886 -286 l 886 0 l 830 0 l p ef +995 0 m 995 -286 l 946 -286 l 946 -329 l 995 -329 l 995 -364 l 995 -387 997 -403 1001 -414 ct +1006 -428 1016 -440 1029 -449 ct 1043 -458 1062 -462 1086 -462 ct 1102 -462 1119 -460 1138 -457 ct +1130 -408 l 1118 -410 1108 -411 1097 -411 ct 1080 -411 1068 -407 1061 -400 ct +1054 -393 1051 -379 1051 -360 ct 1051 -329 l 1115 -329 l 1115 -286 l 1051 -286 l +1051 0 l 995 0 l p ef +1385 -107 m 1443 -99 l 1434 -66 1417 -40 1392 -21 ct 1368 -2 1336 7 1298 7 ct +1250 7 1212 -8 1184 -37 ct 1155 -67 1141 -109 1141 -162 ct 1141 -218 1156 -261 1184 -291 ct +1213 -322 1250 -337 1295 -337 ct 1339 -337 1375 -322 1403 -292 ct 1431 -262 1445 -220 1445 -166 ct +1445 -163 1445 -158 1444 -151 ct 1199 -151 l 1201 -115 1211 -87 1230 -68 ct +1248 -49 1271 -39 1298 -39 ct 1319 -39 1336 -44 1351 -55 ct 1365 -66 1377 -83 1385 -107 ct +p +1202 -197 m 1386 -197 l 1383 -225 1376 -245 1365 -259 ct 1347 -280 1324 -291 1296 -291 ct +1270 -291 1248 -283 1231 -265 ct 1214 -248 1204 -226 1202 -197 ct p ef +1510 0 m 1510 -330 l 1560 -330 l 1560 -280 l 1573 -303 1585 -318 1596 -326 ct +1607 -333 1619 -337 1632 -337 ct 1651 -337 1670 -331 1689 -319 ct 1670 -267 l +1656 -275 1643 -279 1629 -279 ct 1617 -279 1606 -276 1596 -268 ct 1586 -261 1579 -251 1575 -238 ct +1569 -218 1566 -196 1566 -173 ct 1566 0 l 1510 0 l p ef +pom +gr +gr +7100 8750 m 6538 8938 l 6538 8563 l 7100 8750 l p ef +5900 8725 m 6650 8725 l 6650 8775 l 5900 8775 l 5900 8725 l p ef +15400 8750 m 14838 8938 l 14838 8563 l 15400 8750 l p ef +14300 8725 m 14950 8725 l 14950 8775 l 14300 8775 l 14300 8725 l p ef +21100 8750 m 20538 8938 l 20538 8563 l 21100 8750 l p ef +19800 8725 m 20650 8725 l 20650 8775 l 19800 8775 l 19800 8725 l p ef +10500 12750 m 11063 12563 l 11063 12938 l 10500 12750 l p ef +15900 12775 m 10950 12775 l 10950 12725 l 15900 12725 l 15900 12775 l +p ef +18900 12750 m 19463 12563 l 19463 12938 l 18900 12750 l p ef +21100 12775 m 19350 12775 l 19350 12725 l 21100 12725 l 21100 12775 l +p ef +12850 9500 m 13038 10063 l 12663 10063 l 12850 9500 l p ef +15900 12775 m 12850 12775 l 12850 12750 l 12850 12725 l 15900 12725 l +15900 12750 l 15900 12775 l p ef +12850 12750 m 12850 12775 l 12846 12775 l 12841 12773 l 12838 12772 l +12834 12769 l 12831 12766 l 12828 12763 l 12827 12759 l 12825 12754 l +12825 12750 l 12825 12750 l 12850 12750 l p ef +12825 12750 m 12825 9950 l 12850 9950 l 12875 9950 l 12875 12750 l +12850 12750 l 12825 12750 l p ef +1225 13350 m 1000 13350 l 1000 12150 l 1450 12150 l 1450 13350 l 1225 13350 l +pc +500 14050 m 500 11549 l 1001 12175 l 1001 13425 l 500 14050 l pc +1450 12750 m 2013 12563 l 2013 12938 l 1450 12750 l p ef +2900 12775 m 1900 12775 l 1900 12725 l 2900 12725 l 2900 12775 l p ef +24100 12750 m 24663 12563 l 24663 12938 l 24100 12750 l p ef +25100 12775 m 24550 12775 l 24550 12725 l 25100 12725 l 25100 12775 l +p ef +25100 8750 m 24538 8938 l 24538 8563 l 25100 8750 l p ef +24100 8725 m 24650 8725 l 24650 8775 l 24100 8775 l 24100 8725 l p ef +1000 9250 m 724 9250 500 9026 500 8750 ct 500 8474 724 8250 1000 8250 ct 1276 8250 1500 8474 1500 8750 ct +1500 9026 1276 9250 1000 9250 ct pc +500 8250 m 500 9250 l ps +2900 8750 m 2338 8938 l 2338 8563 l 2900 8750 l p ef +1500 8724 m 2200 8724 l 2200 8749 l 2200 8774 l 1500 8774 l 1500 8749 l +1500 8724 l p ef +2200 8749 m 2200 8724 l 2204 8724 l 2209 8726 l 2212 8727 l 2216 8730 l +2219 8733 l 2222 8736 l 2223 8740 l 2225 8745 l 2225 8749 l 2225 8749 l +2200 8749 l p ef +2225 8749 m 2225 8750 l 2200 8750 l 2175 8750 l 2175 8749 l 2200 8749 l +2225 8749 l p ef +2200 8750 m 2200 8775 l 2196 8775 l 2191 8773 l 2188 8772 l 2184 8769 l +2181 8766 l 2178 8763 l 2177 8759 l 2175 8754 l 2175 8750 l 2175 8750 l +2200 8750 l p ef +2200 8725 m 2450 8725 l 2450 8750 l 2450 8775 l 2200 8775 l 2200 8750 l +2200 8725 l p ef +4400 9500 m 4588 10063 l 4213 10063 l 4400 9500 l p ef +4400 12000 m 4213 11438 l 4588 11438 l 4400 12000 l p ef +4425 9950 m 4425 11550 l 4375 11550 l 4375 9950 l 4425 9950 l p ef +8698 9525 m 8647 9525 l 8647 9475 l 8698 9475 l 8698 9525 l p ef +8596 9525 m 8545 9525 l 8545 9475 l 8596 9475 l 8596 9525 l p ef +8494 9525 m 8443 9525 l 8443 9475 l 8494 9475 l 8494 9525 l p ef +8392 9525 m 8341 9525 l 8341 9475 l 8392 9475 l 8392 9525 l p ef +8290 9525 m 8239 9525 l 8239 9475 l 8290 9475 l 8290 9525 l p ef +8188 9525 m 8137 9525 l 8137 9475 l 8188 9475 l 8188 9525 l p ef +8086 9525 m 8035 9525 l 8035 9475 l 8086 9475 l 8086 9525 l p ef +7984 9525 m 7933 9525 l 7933 9475 l 7984 9475 l 7984 9525 l p ef +7882 9525 m 7831 9525 l 7831 9475 l 7882 9475 l 7882 9525 l p ef +7780 9525 m 7729 9525 l 7729 9475 l 7780 9475 l 7780 9525 l p ef +7678 9525 m 7627 9525 l 7627 9475 l 7678 9475 l 7678 9525 l p ef +7576 9525 m 7525 9525 l 7525 9475 l 7576 9475 l 7576 9525 l p ef +7474 9525 m 7423 9525 l 7423 9475 l 7474 9475 l 7474 9525 l p ef +7372 9525 m 7321 9525 l 7321 9475 l 7372 9475 l 7372 9525 l p ef +7270 9525 m 7219 9525 l 7219 9475 l 7270 9475 l 7270 9525 l p ef +7168 9525 m 7117 9525 l 7117 9475 l 7168 9475 l 7168 9525 l p ef +7075 9466 m 7075 9415 l 7125 9415 l 7125 9466 l 7075 9466 l p ef +7075 9364 m 7075 9313 l 7125 9313 l 7125 9364 l 7075 9364 l p ef +7075 9262 m 7075 9211 l 7125 9211 l 7125 9262 l 7075 9262 l p ef +7075 9160 m 7075 9109 l 7125 9109 l 7125 9160 l 7075 9160 l p ef +7075 9058 m 7075 9007 l 7125 9007 l 7125 9058 l 7075 9058 l p ef +7075 8956 m 7075 8905 l 7125 8905 l 7125 8956 l 7075 8956 l p ef +7075 8854 m 7075 8803 l 7125 8803 l 7125 8854 l 7075 8854 l p ef +7075 8752 m 7075 8701 l 7125 8701 l 7125 8752 l 7075 8752 l p ef +7075 8650 m 7075 8599 l 7125 8599 l 7125 8650 l 7075 8650 l p ef +7075 8548 m 7075 8497 l 7125 8497 l 7125 8548 l 7075 8548 l p ef +7075 8446 m 7075 8395 l 7125 8395 l 7125 8446 l 7075 8446 l p ef +7075 8344 m 7075 8293 l 7125 8293 l 7125 8344 l 7075 8344 l p ef +7075 8242 m 7075 8191 l 7125 8191 l 7125 8242 l 7075 8242 l p ef +7075 8140 m 7075 8089 l 7125 8089 l 7125 8140 l 7075 8140 l p ef +7075 8038 m 7075 8000 l 7100 8000 l 7125 8000 l 7125 8038 l 7100 8038 l +7075 8038 l p ef +7100 8000 m 7075 8000 l 7075 7996 l 7077 7991 l 7078 7988 l 7081 7984 l +7084 7981 l 7087 7978 l 7091 7977 l 7096 7975 l 7100 7975 l 7100 7975 l +7100 8000 l p ef +7100 7975 m 7113 7975 l 7113 8000 l 7113 8025 l 7100 8025 l 7100 8000 l +7100 7975 l p ef +7164 7975 m 7215 7975 l 7215 8025 l 7164 8025 l 7164 7975 l p ef +7266 7975 m 7317 7975 l 7317 8025 l 7266 8025 l 7266 7975 l p ef +7368 7975 m 7419 7975 l 7419 8025 l 7368 8025 l 7368 7975 l p ef +7470 7975 m 7521 7975 l 7521 8025 l 7470 8025 l 7470 7975 l p ef +7572 7975 m 7623 7975 l 7623 8025 l 7572 8025 l 7572 7975 l p ef +7674 7975 m 7725 7975 l 7725 8025 l 7674 8025 l 7674 7975 l p ef +7776 7975 m 7827 7975 l 7827 8025 l 7776 8025 l 7776 7975 l p ef +7878 7975 m 7929 7975 l 7929 8025 l 7878 8025 l 7878 7975 l p ef +7980 7975 m 8031 7975 l 8031 8025 l 7980 8025 l 7980 7975 l p ef +8082 7975 m 8133 7975 l 8133 8025 l 8082 8025 l 8082 7975 l p ef +8184 7975 m 8235 7975 l 8235 8025 l 8184 8025 l 8184 7975 l p ef +8286 7975 m 8337 7975 l 8337 8025 l 8286 8025 l 8286 7975 l p ef +8388 7975 m 8439 7975 l 8439 8025 l 8388 8025 l 8388 7975 l p ef +8490 7975 m 8541 7975 l 8541 8025 l 8490 8025 l 8490 7975 l p ef +8592 7975 m 8643 7975 l 8643 8025 l 8592 8025 l 8592 7975 l p ef +8694 7975 m 8745 7975 l 8745 8025 l 8694 8025 l 8694 7975 l p ef +8796 7975 m 8847 7975 l 8847 8025 l 8796 8025 l 8796 7975 l p ef +8898 7975 m 8949 7975 l 8949 8025 l 8898 8025 l 8898 7975 l p ef +9000 7975 m 9051 7975 l 9051 8025 l 9000 8025 l 9000 7975 l p ef +9102 7975 m 9153 7975 l 9153 8025 l 9102 8025 l 9102 7975 l p ef +9204 7975 m 9255 7975 l 9255 8025 l 9204 8025 l 9204 7975 l p ef +9306 7975 m 9357 7975 l 9357 8025 l 9306 8025 l 9306 7975 l p ef +9408 7975 m 9459 7975 l 9459 8025 l 9408 8025 l 9408 7975 l p ef +9510 7975 m 9561 7975 l 9561 8025 l 9510 8025 l 9510 7975 l p ef +9612 7975 m 9663 7975 l 9663 8025 l 9612 8025 l 9612 7975 l p ef +9714 7975 m 9765 7975 l 9765 8025 l 9714 8025 l 9714 7975 l p ef +9816 7975 m 9867 7975 l 9867 8025 l 9816 8025 l 9816 7975 l p ef +9918 7975 m 9969 7975 l 9969 8025 l 9918 8025 l 9918 7975 l p ef +10020 7975 m 10071 7975 l 10071 8025 l 10020 8025 l 10020 7975 l p ef +10122 7975 m 10173 7975 l 10173 8025 l 10122 8025 l 10122 7975 l p ef +10224 7975 m 10275 7975 l 10275 8025 l 10224 8025 l 10224 7975 l p ef +10326 7975 m 10377 7975 l 10377 8025 l 10326 8025 l 10326 7975 l p ef +10428 7975 m 10479 7975 l 10479 8025 l 10428 8025 l 10428 7975 l p ef +10525 8030 m 10525 8081 l 10475 8081 l 10475 8030 l 10525 8030 l p ef +10525 8132 m 10525 8183 l 10475 8183 l 10475 8132 l 10525 8132 l p ef +10525 8234 m 10525 8285 l 10475 8285 l 10475 8234 l 10525 8234 l p ef +10525 8336 m 10525 8387 l 10475 8387 l 10475 8336 l 10525 8336 l p ef +10525 8438 m 10525 8489 l 10475 8489 l 10475 8438 l 10525 8438 l p ef +10525 8540 m 10525 8591 l 10475 8591 l 10475 8540 l 10525 8540 l p ef +10525 8642 m 10525 8693 l 10475 8693 l 10475 8642 l 10525 8642 l p ef +10525 8744 m 10525 8795 l 10475 8795 l 10475 8744 l 10525 8744 l p ef +10525 8846 m 10525 8897 l 10475 8897 l 10475 8846 l 10525 8846 l p ef +10525 8948 m 10525 8999 l 10475 8999 l 10475 8948 l 10525 8948 l p ef +10525 9050 m 10525 9101 l 10475 9101 l 10475 9050 l 10525 9050 l p ef +10525 9152 m 10525 9203 l 10475 9203 l 10475 9152 l 10525 9152 l p ef +10525 9254 m 10525 9305 l 10475 9305 l 10475 9254 l 10525 9254 l p ef +10525 9356 m 10525 9407 l 10475 9407 l 10475 9356 l 10525 9356 l p ef +10525 9458 m 10525 9500 l 10500 9500 l 10475 9500 l 10475 9458 l 10500 9458 l +10525 9458 l p ef +10500 9500 m 10525 9500 l 10525 9504 l 10523 9509 l 10522 9512 l 10519 9516 l +10516 9519 l 10513 9522 l 10509 9523 l 10504 9525 l 10500 9525 l 10500 9525 l +10500 9500 l p ef +10500 9525 m 10491 9525 l 10491 9500 l 10491 9475 l 10500 9475 l 10500 9500 l +10500 9525 l p ef +10440 9525 m 10389 9525 l 10389 9475 l 10440 9475 l 10440 9525 l p ef +10338 9525 m 10287 9525 l 10287 9475 l 10338 9475 l 10338 9525 l p ef +10236 9525 m 10185 9525 l 10185 9475 l 10236 9475 l 10236 9525 l p ef +10134 9525 m 10083 9525 l 10083 9475 l 10134 9475 l 10134 9525 l p ef +10032 9525 m 9981 9525 l 9981 9475 l 10032 9475 l 10032 9525 l p ef +9930 9525 m 9879 9525 l 9879 9475 l 9930 9475 l 9930 9525 l p ef +9828 9525 m 9777 9525 l 9777 9475 l 9828 9475 l 9828 9525 l p ef +9726 9525 m 9675 9525 l 9675 9475 l 9726 9475 l 9726 9525 l p ef +9624 9525 m 9573 9525 l 9573 9475 l 9624 9475 l 9624 9525 l p ef +9522 9525 m 9471 9525 l 9471 9475 l 9522 9475 l 9522 9525 l p ef +9420 9525 m 9369 9525 l 9369 9475 l 9420 9475 l 9420 9525 l p ef +9318 9525 m 9267 9525 l 9267 9475 l 9318 9475 l 9318 9525 l p ef +9216 9525 m 9165 9525 l 9165 9475 l 9216 9475 l 9216 9525 l p ef +9114 9525 m 9063 9525 l 9063 9475 l 9114 9475 l 9114 9525 l p ef +9012 9525 m 8961 9525 l 8961 9475 l 9012 9475 l 9012 9525 l p ef +8910 9525 m 8859 9525 l 8859 9475 l 8910 9475 l 8910 9525 l p ef +8808 9525 m 8800 9525 l 8800 9500 l 8800 9475 l 8808 9475 l 8808 9500 l +8808 9525 l p ef +8800 9525 m 8749 9525 l 8749 9500 l 8749 9475 l 8800 9475 l 8800 9500 l +8800 9525 l p ef +gs +gs +pum +7276 8974 t +50 0 m 50 -455 l 251 -455 l 292 -455 323 -451 344 -443 ct 365 -435 382 -420 394 -399 ct +407 -379 413 -356 413 -331 ct 413 -299 403 -271 382 -249 ct 361 -227 329 -213 285 -207 ct +301 -199 313 -192 322 -184 ct 339 -168 356 -148 371 -124 ct 451 0 l 375 0 l +315 -95 l 297 -122 283 -143 271 -157 ct 260 -172 250 -182 241 -188 ct 232 -194 223 -198 213 -200 ct +207 -201 195 -202 180 -202 ct 110 -202 l 110 0 l 50 0 l p +110 -254 m 239 -254 l 267 -254 288 -257 304 -263 ct 319 -268 331 -277 339 -290 ct +347 -303 351 -316 351 -331 ct 351 -352 344 -370 328 -384 ct 312 -398 288 -405 254 -405 ct +110 -405 l 110 -254 l p ef +724 -107 m 782 -99 l 773 -66 756 -40 731 -21 ct 707 -2 675 7 637 7 ct 589 7 551 -8 523 -37 ct +494 -67 480 -109 480 -162 ct 480 -218 495 -261 523 -291 ct 552 -322 589 -337 634 -337 ct +678 -337 714 -322 742 -292 ct 770 -262 784 -220 784 -166 ct 784 -163 784 -158 783 -151 ct +538 -151 l 540 -115 550 -87 569 -68 ct 587 -49 610 -39 637 -39 ct 658 -39 675 -44 690 -55 ct +704 -66 716 -83 724 -107 ct p +541 -197 m 725 -197 l 722 -225 715 -245 704 -259 ct 686 -280 663 -291 635 -291 ct +609 -291 587 -283 570 -265 ct 553 -248 543 -226 541 -197 ct p ef +829 -99 m 884 -107 l 887 -85 895 -68 910 -57 ct 924 -45 944 -39 969 -39 ct +995 -39 1014 -44 1026 -55 ct 1038 -65 1045 -77 1045 -91 ct 1045 -104 1039 -114 1028 -121 ct +1021 -126 1002 -132 971 -140 ct 930 -150 902 -159 886 -167 ct 870 -174 858 -185 850 -198 ct +842 -211 838 -226 838 -242 ct 838 -257 841 -270 848 -283 ct 855 -295 864 -306 875 -314 ct +884 -320 896 -326 911 -330 ct 926 -335 942 -337 959 -337 ct 985 -337 1008 -333 1027 -326 ct +1047 -318 1061 -308 1070 -296 ct 1080 -283 1086 -266 1090 -245 ct 1035 -237 l +1033 -254 1025 -267 1013 -277 ct 1002 -286 985 -291 963 -291 ct 937 -291 919 -287 908 -278 ct +897 -270 892 -260 892 -249 ct 892 -241 894 -235 899 -229 ct 903 -223 910 -218 920 -214 ct +926 -212 942 -207 969 -200 ct 1009 -189 1036 -181 1052 -174 ct 1068 -167 1080 -158 1089 -145 ct +1098 -132 1102 -116 1102 -97 ct 1102 -79 1097 -61 1086 -45 ct 1075 -28 1059 -15 1039 -6 ct +1018 3 995 7 969 7 ct 927 7 894 -2 871 -20 ct 849 -37 835 -64 829 -99 ct p ef +1383 -41 m 1362 -24 1342 -11 1323 -4 ct 1304 3 1283 7 1262 7 ct 1225 7 1198 -2 1178 -20 ct +1159 -37 1149 -60 1149 -87 ct 1149 -103 1153 -118 1160 -131 ct 1167 -145 1177 -156 1189 -164 ct +1201 -172 1214 -178 1229 -182 ct 1240 -185 1256 -188 1279 -190 ct 1324 -196 1357 -202 1378 -209 ct +1378 -217 1378 -222 1378 -224 ct 1378 -247 1373 -263 1363 -272 ct 1348 -285 1327 -291 1299 -291 ct +1273 -291 1253 -286 1241 -277 ct 1228 -268 1219 -252 1213 -228 ct 1159 -236 l +1164 -259 1172 -278 1183 -292 ct 1194 -307 1211 -318 1232 -326 ct 1254 -333 1279 -337 1307 -337 ct +1335 -337 1358 -334 1376 -327 ct 1393 -321 1406 -312 1414 -302 ct 1423 -292 1428 -280 1432 -264 ct +1434 -255 1435 -238 1435 -213 ct 1435 -138 l 1435 -87 1436 -54 1438 -40 ct +1440 -26 1445 -13 1452 0 ct 1394 0 l 1388 -12 1384 -26 1383 -41 ct p +1378 -166 m 1358 -157 1327 -150 1287 -145 ct 1264 -141 1248 -138 1238 -133 ct +1229 -129 1221 -123 1216 -115 ct 1211 -107 1208 -99 1208 -89 ct 1208 -74 1214 -62 1225 -52 ct +1237 -42 1253 -37 1275 -37 ct 1296 -37 1315 -41 1332 -51 ct 1349 -60 1361 -73 1369 -89 ct +1375 -102 1378 -121 1378 -145 ct 1378 -166 l p ef +1519 0 m 1519 -330 l 1569 -330 l 1569 -283 l 1579 -299 1593 -312 1610 -322 ct +1627 -332 1647 -337 1669 -337 ct 1693 -337 1713 -332 1729 -322 ct 1744 -312 1755 -297 1762 -279 ct +1788 -318 1822 -337 1863 -337 ct 1896 -337 1921 -328 1939 -310 ct 1956 -292 1965 -264 1965 -226 ct +1965 0 l 1910 0 l 1910 -208 l 1910 -230 1908 -246 1904 -256 ct 1901 -266 1894 -274 1884 -280 ct +1875 -286 1864 -289 1851 -289 ct 1828 -289 1809 -281 1793 -265 ct 1778 -250 1770 -225 1770 -191 ct +1770 0 l 1715 0 l 1715 -214 l 1715 -239 1710 -258 1701 -270 ct 1692 -282 1677 -289 1656 -289 ct +1641 -289 1626 -284 1613 -276 ct 1599 -268 1590 -256 1584 -240 ct 1578 -224 1575 -201 1575 -171 ct +1575 0 l 1519 0 l p ef +2049 126 m 2049 -330 l 2100 -330 l 2100 -287 l 2112 -304 2125 -316 2140 -324 ct +2155 -333 2174 -337 2195 -337 ct 2223 -337 2248 -330 2270 -315 ct 2291 -301 2307 -280 2318 -254 ct +2329 -228 2335 -199 2335 -167 ct 2335 -134 2329 -103 2317 -77 ct 2305 -50 2287 -29 2264 -15 ct +2241 0 2217 7 2191 7 ct 2173 7 2156 3 2141 -5 ct 2126 -13 2114 -23 2105 -35 ct +2105 126 l 2049 126 l p +2099 -163 m 2099 -121 2108 -90 2125 -69 ct 2142 -49 2163 -39 2187 -39 ct 2212 -39 2234 -49 2251 -70 ct +2269 -91 2278 -124 2278 -168 ct 2278 -210 2269 -241 2252 -262 ct 2235 -283 2214 -293 2190 -293 ct +2166 -293 2145 -282 2127 -260 ct 2109 -238 2099 -205 2099 -163 ct p ef +2399 0 m 2399 -455 l 2454 -455 l 2454 0 l 2399 0 l p ef +2765 -107 m 2823 -99 l 2814 -66 2797 -40 2772 -21 ct 2748 -2 2716 7 2678 7 ct +2630 7 2592 -8 2564 -37 ct 2535 -67 2521 -109 2521 -162 ct 2521 -218 2536 -261 2564 -291 ct +2593 -322 2630 -337 2675 -337 ct 2719 -337 2755 -322 2783 -292 ct 2811 -262 2825 -220 2825 -166 ct +2825 -163 2825 -158 2824 -151 ct 2579 -151 l 2581 -115 2591 -87 2610 -68 ct +2628 -49 2651 -39 2678 -39 ct 2699 -39 2716 -44 2731 -55 ct 2745 -66 2757 -83 2765 -107 ct +p +2582 -197 m 2766 -197 l 2763 -225 2756 -245 2745 -259 ct 2727 -280 2704 -291 2676 -291 ct +2650 -291 2628 -283 2611 -265 ct 2594 -248 2584 -226 2582 -197 ct p ef +2890 0 m 2890 -330 l 2940 -330 l 2940 -280 l 2953 -303 2965 -318 2976 -326 ct +2987 -333 2999 -337 3012 -337 ct 3031 -337 3050 -331 3069 -319 ct 3050 -267 l +3036 -275 3023 -279 3009 -279 ct 2997 -279 2986 -276 2976 -268 ct 2966 -261 2959 -251 2955 -238 ct +2949 -218 2946 -196 2946 -173 ct 2946 0 l 2890 0 l p ef +pom +gr +gr +11400 8750 m 10838 8938 l 10838 8563 l 11400 8750 l p ef +10500 8725 m 10950 8725 l 10950 8775 l 10500 8775 l 10500 8725 l p ef +8698 13525 m 8647 13525 l 8647 13475 l 8698 13475 l 8698 13525 l p ef +8596 13525 m 8545 13525 l 8545 13475 l 8596 13475 l 8596 13525 l p ef +8494 13525 m 8443 13525 l 8443 13475 l 8494 13475 l 8494 13525 l p ef +8392 13525 m 8341 13525 l 8341 13475 l 8392 13475 l 8392 13525 l p ef +8290 13525 m 8239 13525 l 8239 13475 l 8290 13475 l 8290 13525 l p ef +8188 13525 m 8137 13525 l 8137 13475 l 8188 13475 l 8188 13525 l p ef +8086 13525 m 8035 13525 l 8035 13475 l 8086 13475 l 8086 13525 l p ef +7984 13525 m 7933 13525 l 7933 13475 l 7984 13475 l 7984 13525 l p ef +7882 13525 m 7831 13525 l 7831 13475 l 7882 13475 l 7882 13525 l p ef +7780 13525 m 7729 13525 l 7729 13475 l 7780 13475 l 7780 13525 l p ef +7678 13525 m 7627 13525 l 7627 13475 l 7678 13475 l 7678 13525 l p ef +7576 13525 m 7525 13525 l 7525 13475 l 7576 13475 l 7576 13525 l p ef +7474 13525 m 7423 13525 l 7423 13475 l 7474 13475 l 7474 13525 l p ef +7372 13525 m 7321 13525 l 7321 13475 l 7372 13475 l 7372 13525 l p ef +7270 13525 m 7219 13525 l 7219 13475 l 7270 13475 l 7270 13525 l p ef +7168 13525 m 7117 13525 l 7117 13475 l 7168 13475 l 7168 13525 l p ef +7075 13466 m 7075 13415 l 7125 13415 l 7125 13466 l 7075 13466 l p ef +7075 13364 m 7075 13313 l 7125 13313 l 7125 13364 l 7075 13364 l p ef +7075 13262 m 7075 13211 l 7125 13211 l 7125 13262 l 7075 13262 l p ef +7075 13160 m 7075 13109 l 7125 13109 l 7125 13160 l 7075 13160 l p ef +7075 13058 m 7075 13007 l 7125 13007 l 7125 13058 l 7075 13058 l p ef +7075 12956 m 7075 12905 l 7125 12905 l 7125 12956 l 7075 12956 l p ef +7075 12854 m 7075 12803 l 7125 12803 l 7125 12854 l 7075 12854 l p ef +7075 12752 m 7075 12701 l 7125 12701 l 7125 12752 l 7075 12752 l p ef +7075 12650 m 7075 12599 l 7125 12599 l 7125 12650 l 7075 12650 l p ef +7075 12548 m 7075 12497 l 7125 12497 l 7125 12548 l 7075 12548 l p ef +7075 12446 m 7075 12395 l 7125 12395 l 7125 12446 l 7075 12446 l p ef +7075 12344 m 7075 12293 l 7125 12293 l 7125 12344 l 7075 12344 l p ef +7075 12242 m 7075 12191 l 7125 12191 l 7125 12242 l 7075 12242 l p ef +7075 12140 m 7075 12089 l 7125 12089 l 7125 12140 l 7075 12140 l p ef +7075 12038 m 7075 12000 l 7100 12000 l 7125 12000 l 7125 12038 l 7100 12038 l +7075 12038 l p ef +7100 12000 m 7075 12000 l 7075 11996 l 7077 11991 l 7078 11988 l 7081 11984 l +7084 11981 l 7087 11978 l 7091 11977 l 7096 11975 l 7100 11975 l 7100 11975 l +7100 12000 l p ef +7100 11975 m 7113 11975 l 7113 12000 l 7113 12025 l 7100 12025 l 7100 12000 l +7100 11975 l p ef +7164 11975 m 7215 11975 l 7215 12025 l 7164 12025 l 7164 11975 l p ef +7266 11975 m 7317 11975 l 7317 12025 l 7266 12025 l 7266 11975 l p ef +7368 11975 m 7419 11975 l 7419 12025 l 7368 12025 l 7368 11975 l p ef +7470 11975 m 7521 11975 l 7521 12025 l 7470 12025 l 7470 11975 l p ef +7572 11975 m 7623 11975 l 7623 12025 l 7572 12025 l 7572 11975 l p ef +7674 11975 m 7725 11975 l 7725 12025 l 7674 12025 l 7674 11975 l p ef +7776 11975 m 7827 11975 l 7827 12025 l 7776 12025 l 7776 11975 l p ef +7878 11975 m 7929 11975 l 7929 12025 l 7878 12025 l 7878 11975 l p ef +7980 11975 m 8031 11975 l 8031 12025 l 7980 12025 l 7980 11975 l p ef +8082 11975 m 8133 11975 l 8133 12025 l 8082 12025 l 8082 11975 l p ef +8184 11975 m 8235 11975 l 8235 12025 l 8184 12025 l 8184 11975 l p ef +8286 11975 m 8337 11975 l 8337 12025 l 8286 12025 l 8286 11975 l p ef +8388 11975 m 8439 11975 l 8439 12025 l 8388 12025 l 8388 11975 l p ef +8490 11975 m 8541 11975 l 8541 12025 l 8490 12025 l 8490 11975 l p ef +8592 11975 m 8643 11975 l 8643 12025 l 8592 12025 l 8592 11975 l p ef +8694 11975 m 8745 11975 l 8745 12025 l 8694 12025 l 8694 11975 l p ef +8796 11975 m 8847 11975 l 8847 12025 l 8796 12025 l 8796 11975 l p ef +8898 11975 m 8949 11975 l 8949 12025 l 8898 12025 l 8898 11975 l p ef +9000 11975 m 9051 11975 l 9051 12025 l 9000 12025 l 9000 11975 l p ef +9102 11975 m 9153 11975 l 9153 12025 l 9102 12025 l 9102 11975 l p ef +9204 11975 m 9255 11975 l 9255 12025 l 9204 12025 l 9204 11975 l p ef +9306 11975 m 9357 11975 l 9357 12025 l 9306 12025 l 9306 11975 l p ef +9408 11975 m 9459 11975 l 9459 12025 l 9408 12025 l 9408 11975 l p ef +9510 11975 m 9561 11975 l 9561 12025 l 9510 12025 l 9510 11975 l p ef +9612 11975 m 9663 11975 l 9663 12025 l 9612 12025 l 9612 11975 l p ef +9714 11975 m 9765 11975 l 9765 12025 l 9714 12025 l 9714 11975 l p ef +9816 11975 m 9867 11975 l 9867 12025 l 9816 12025 l 9816 11975 l p ef +9918 11975 m 9969 11975 l 9969 12025 l 9918 12025 l 9918 11975 l p ef +10020 11975 m 10071 11975 l 10071 12025 l 10020 12025 l 10020 11975 l +p ef +10122 11975 m 10173 11975 l 10173 12025 l 10122 12025 l 10122 11975 l +p ef +10224 11975 m 10275 11975 l 10275 12025 l 10224 12025 l 10224 11975 l +p ef +10326 11975 m 10377 11975 l 10377 12025 l 10326 12025 l 10326 11975 l +p ef +10428 11975 m 10479 11975 l 10479 12025 l 10428 12025 l 10428 11975 l +p ef +10525 12030 m 10525 12081 l 10475 12081 l 10475 12030 l 10525 12030 l +p ef +10525 12132 m 10525 12183 l 10475 12183 l 10475 12132 l 10525 12132 l +p ef +10525 12234 m 10525 12285 l 10475 12285 l 10475 12234 l 10525 12234 l +p ef +10525 12336 m 10525 12387 l 10475 12387 l 10475 12336 l 10525 12336 l +p ef +10525 12438 m 10525 12489 l 10475 12489 l 10475 12438 l 10525 12438 l +p ef +10525 12540 m 10525 12591 l 10475 12591 l 10475 12540 l 10525 12540 l +p ef +10525 12642 m 10525 12693 l 10475 12693 l 10475 12642 l 10525 12642 l +p ef +10525 12744 m 10525 12795 l 10475 12795 l 10475 12744 l 10525 12744 l +p ef +10525 12846 m 10525 12897 l 10475 12897 l 10475 12846 l 10525 12846 l +p ef +10525 12948 m 10525 12999 l 10475 12999 l 10475 12948 l 10525 12948 l +p ef +10525 13050 m 10525 13101 l 10475 13101 l 10475 13050 l 10525 13050 l +p ef +10525 13152 m 10525 13203 l 10475 13203 l 10475 13152 l 10525 13152 l +p ef +10525 13254 m 10525 13305 l 10475 13305 l 10475 13254 l 10525 13254 l +p ef +10525 13356 m 10525 13407 l 10475 13407 l 10475 13356 l 10525 13356 l +p ef +10525 13458 m 10525 13500 l 10500 13500 l 10475 13500 l 10475 13458 l +10500 13458 l 10525 13458 l p ef +10500 13500 m 10525 13500 l 10525 13504 l 10523 13509 l 10522 13512 l +10519 13516 l 10516 13519 l 10513 13522 l 10509 13523 l 10504 13525 l +10500 13525 l 10500 13525 l 10500 13500 l p ef +10500 13525 m 10491 13525 l 10491 13500 l 10491 13475 l 10500 13475 l +10500 13500 l 10500 13525 l p ef +10440 13525 m 10389 13525 l 10389 13475 l 10440 13475 l 10440 13525 l +p ef +10338 13525 m 10287 13525 l 10287 13475 l 10338 13475 l 10338 13525 l +p ef +10236 13525 m 10185 13525 l 10185 13475 l 10236 13475 l 10236 13525 l +p ef +10134 13525 m 10083 13525 l 10083 13475 l 10134 13475 l 10134 13525 l +p ef +10032 13525 m 9981 13525 l 9981 13475 l 10032 13475 l 10032 13525 l +p ef +9930 13525 m 9879 13525 l 9879 13475 l 9930 13475 l 9930 13525 l p ef +9828 13525 m 9777 13525 l 9777 13475 l 9828 13475 l 9828 13525 l p ef +9726 13525 m 9675 13525 l 9675 13475 l 9726 13475 l 9726 13525 l p ef +9624 13525 m 9573 13525 l 9573 13475 l 9624 13475 l 9624 13525 l p ef +9522 13525 m 9471 13525 l 9471 13475 l 9522 13475 l 9522 13525 l p ef +9420 13525 m 9369 13525 l 9369 13475 l 9420 13475 l 9420 13525 l p ef +9318 13525 m 9267 13525 l 9267 13475 l 9318 13475 l 9318 13525 l p ef +9216 13525 m 9165 13525 l 9165 13475 l 9216 13475 l 9216 13525 l p ef +9114 13525 m 9063 13525 l 9063 13475 l 9114 13475 l 9114 13525 l p ef +9012 13525 m 8961 13525 l 8961 13475 l 9012 13475 l 9012 13525 l p ef +8910 13525 m 8859 13525 l 8859 13475 l 8910 13475 l 8910 13525 l p ef +8808 13525 m 8800 13525 l 8800 13500 l 8800 13475 l 8808 13475 l 8808 13500 l +8808 13525 l p ef +8800 13525 m 8749 13525 l 8749 13500 l 8749 13475 l 8800 13475 l 8800 13500 l +8800 13525 l p ef +gs +gs +pum +7276 12970 t +50 0 m 50 -455 l 251 -455 l 292 -455 323 -451 344 -443 ct 365 -435 382 -420 394 -399 ct +407 -379 413 -356 413 -331 ct 413 -299 403 -271 382 -249 ct 361 -227 329 -213 285 -207 ct +301 -199 313 -192 322 -184 ct 339 -168 356 -148 371 -124 ct 451 0 l 375 0 l +315 -95 l 297 -122 283 -143 271 -157 ct 260 -172 250 -182 241 -188 ct 232 -194 223 -198 213 -200 ct +207 -201 195 -202 180 -202 ct 110 -202 l 110 0 l 50 0 l p +110 -254 m 239 -254 l 267 -254 288 -257 304 -263 ct 319 -268 331 -277 339 -290 ct +347 -303 351 -316 351 -331 ct 351 -352 344 -370 328 -384 ct 312 -398 288 -405 254 -405 ct +110 -405 l 110 -254 l p ef +724 -107 m 782 -99 l 773 -66 756 -40 731 -21 ct 707 -2 675 7 637 7 ct 589 7 551 -8 523 -37 ct +494 -67 480 -109 480 -162 ct 480 -218 495 -261 523 -291 ct 552 -322 589 -337 634 -337 ct +678 -337 714 -322 742 -292 ct 770 -262 784 -220 784 -166 ct 784 -163 784 -158 783 -151 ct +538 -151 l 540 -115 550 -87 569 -68 ct 587 -49 610 -39 637 -39 ct 658 -39 675 -44 690 -55 ct +704 -66 716 -83 724 -107 ct p +541 -197 m 725 -197 l 722 -225 715 -245 704 -259 ct 686 -280 663 -291 635 -291 ct +609 -291 587 -283 570 -265 ct 553 -248 543 -226 541 -197 ct p ef +829 -99 m 884 -107 l 887 -85 895 -68 910 -57 ct 924 -45 944 -39 969 -39 ct +995 -39 1014 -44 1026 -55 ct 1038 -65 1045 -77 1045 -91 ct 1045 -104 1039 -114 1028 -121 ct +1021 -126 1002 -132 971 -140 ct 930 -150 902 -159 886 -167 ct 870 -174 858 -185 850 -198 ct +842 -211 838 -226 838 -242 ct 838 -257 841 -270 848 -283 ct 855 -295 864 -306 875 -314 ct +884 -320 896 -326 911 -330 ct 926 -335 942 -337 959 -337 ct 985 -337 1008 -333 1027 -326 ct +1047 -318 1061 -308 1070 -296 ct 1080 -283 1086 -266 1090 -245 ct 1035 -237 l +1033 -254 1025 -267 1013 -277 ct 1002 -286 985 -291 963 -291 ct 937 -291 919 -287 908 -278 ct +897 -270 892 -260 892 -249 ct 892 -241 894 -235 899 -229 ct 903 -223 910 -218 920 -214 ct +926 -212 942 -207 969 -200 ct 1009 -189 1036 -181 1052 -174 ct 1068 -167 1080 -158 1089 -145 ct +1098 -132 1102 -116 1102 -97 ct 1102 -79 1097 -61 1086 -45 ct 1075 -28 1059 -15 1039 -6 ct +1018 3 995 7 969 7 ct 927 7 894 -2 871 -20 ct 849 -37 835 -64 829 -99 ct p ef +1383 -41 m 1362 -24 1342 -11 1323 -4 ct 1304 3 1283 7 1262 7 ct 1225 7 1198 -2 1178 -20 ct +1159 -37 1149 -60 1149 -87 ct 1149 -103 1153 -118 1160 -131 ct 1167 -145 1177 -156 1189 -164 ct +1201 -172 1214 -178 1229 -182 ct 1240 -185 1256 -188 1279 -190 ct 1324 -196 1357 -202 1378 -209 ct +1378 -217 1378 -222 1378 -224 ct 1378 -247 1373 -263 1363 -272 ct 1348 -285 1327 -291 1299 -291 ct +1273 -291 1253 -286 1241 -277 ct 1228 -268 1219 -252 1213 -228 ct 1159 -236 l +1164 -259 1172 -278 1183 -292 ct 1194 -307 1211 -318 1232 -326 ct 1254 -333 1279 -337 1307 -337 ct +1335 -337 1358 -334 1376 -327 ct 1393 -321 1406 -312 1414 -302 ct 1423 -292 1428 -280 1432 -264 ct +1434 -255 1435 -238 1435 -213 ct 1435 -138 l 1435 -87 1436 -54 1438 -40 ct +1440 -26 1445 -13 1452 0 ct 1394 0 l 1388 -12 1384 -26 1383 -41 ct p +1378 -166 m 1358 -157 1327 -150 1287 -145 ct 1264 -141 1248 -138 1238 -133 ct +1229 -129 1221 -123 1216 -115 ct 1211 -107 1208 -99 1208 -89 ct 1208 -74 1214 -62 1225 -52 ct +1237 -42 1253 -37 1275 -37 ct 1296 -37 1315 -41 1332 -51 ct 1349 -60 1361 -73 1369 -89 ct +1375 -102 1378 -121 1378 -145 ct 1378 -166 l p ef +1519 0 m 1519 -330 l 1569 -330 l 1569 -283 l 1579 -299 1593 -312 1610 -322 ct +1627 -332 1647 -337 1669 -337 ct 1693 -337 1713 -332 1729 -322 ct 1744 -312 1755 -297 1762 -279 ct +1788 -318 1822 -337 1863 -337 ct 1896 -337 1921 -328 1939 -310 ct 1956 -292 1965 -264 1965 -226 ct +1965 0 l 1910 0 l 1910 -208 l 1910 -230 1908 -246 1904 -256 ct 1901 -266 1894 -274 1884 -280 ct +1875 -286 1864 -289 1851 -289 ct 1828 -289 1809 -281 1793 -265 ct 1778 -250 1770 -225 1770 -191 ct +1770 0 l 1715 0 l 1715 -214 l 1715 -239 1710 -258 1701 -270 ct 1692 -282 1677 -289 1656 -289 ct +1641 -289 1626 -284 1613 -276 ct 1599 -268 1590 -256 1584 -240 ct 1578 -224 1575 -201 1575 -171 ct +1575 0 l 1519 0 l p ef +2049 126 m 2049 -330 l 2100 -330 l 2100 -287 l 2112 -304 2125 -316 2140 -324 ct +2155 -333 2174 -337 2195 -337 ct 2223 -337 2248 -330 2270 -315 ct 2291 -301 2307 -280 2318 -254 ct +2329 -228 2335 -199 2335 -167 ct 2335 -134 2329 -103 2317 -77 ct 2305 -50 2287 -29 2264 -15 ct +2241 0 2217 7 2191 7 ct 2173 7 2156 3 2141 -5 ct 2126 -13 2114 -23 2105 -35 ct +2105 126 l 2049 126 l p +2099 -163 m 2099 -121 2108 -90 2125 -69 ct 2142 -49 2163 -39 2187 -39 ct 2212 -39 2234 -49 2251 -70 ct +2269 -91 2278 -124 2278 -168 ct 2278 -210 2269 -241 2252 -262 ct 2235 -283 2214 -293 2190 -293 ct +2166 -293 2145 -282 2127 -260 ct 2109 -238 2099 -205 2099 -163 ct p ef +2399 0 m 2399 -455 l 2454 -455 l 2454 0 l 2399 0 l p ef +2765 -107 m 2823 -99 l 2814 -66 2797 -40 2772 -21 ct 2748 -2 2716 7 2678 7 ct +2630 7 2592 -8 2564 -37 ct 2535 -67 2521 -109 2521 -162 ct 2521 -218 2536 -261 2564 -291 ct +2593 -322 2630 -337 2675 -337 ct 2719 -337 2755 -322 2783 -292 ct 2811 -262 2825 -220 2825 -166 ct +2825 -163 2825 -158 2824 -151 ct 2579 -151 l 2581 -115 2591 -87 2610 -68 ct +2628 -49 2651 -39 2678 -39 ct 2699 -39 2716 -44 2731 -55 ct 2745 -66 2757 -83 2765 -107 ct +p +2582 -197 m 2766 -197 l 2763 -225 2756 -245 2745 -259 ct 2727 -280 2704 -291 2676 -291 ct +2650 -291 2628 -283 2611 -265 ct 2594 -248 2584 -226 2582 -197 ct p ef +2890 0 m 2890 -330 l 2940 -330 l 2940 -280 l 2953 -303 2965 -318 2976 -326 ct +2987 -333 2999 -337 3012 -337 ct 3031 -337 3050 -331 3069 -319 ct 3050 -267 l +3036 -275 3023 -279 3009 -279 ct 2997 -279 2986 -276 2976 -268 ct 2966 -261 2959 -251 2955 -238 ct +2949 -218 2946 -196 2946 -173 ct 2946 0 l 2890 0 l p ef +pom +gr +gr +5900 12750 m 6463 12563 l 6463 12938 l 5900 12750 l p ef +7100 12775 m 6350 12775 l 6350 12725 l 7100 12725 l 7100 12775 l p ef +gs +gs +pum +25603 12626 t +52 -1 m 52 -455 l 359 -455 l 359 -401 l 112 -401 l 112 -261 l 326 -261 l +326 -207 l 112 -207 l 112 -1 l 52 -1 l p ef +430 0 m 430 -330 l 480 -330 l 480 -280 l 493 -303 505 -318 516 -326 ct +527 -333 539 -337 552 -337 ct 571 -337 590 -331 609 -319 ct 590 -267 l 576 -275 563 -279 549 -279 ct +537 -279 526 -276 516 -268 ct 506 -261 499 -251 495 -238 ct 489 -218 486 -196 486 -173 ct +486 0 l 430 0 l p ef +622 -165 m 622 -226 639 -271 673 -301 ct 701 -325 736 -337 777 -337 ct 822 -337 859 -322 887 -293 ct +916 -263 931 -222 931 -170 ct 931 -127 924 -94 912 -70 ct 899 -45 880 -27 856 -13 ct +832 0 805 7 777 7 ct 730 7 693 -8 665 -37 ct 636 -67 622 -110 622 -165 ct p +679 -165 m 679 -123 689 -91 707 -70 ct 725 -49 749 -39 777 -39 ct 804 -39 827 -49 846 -71 ct +864 -92 873 -124 873 -167 ct 873 -208 864 -239 845 -260 ct 827 -281 804 -291 777 -291 ct +749 -291 725 -281 707 -260 ct 689 -239 679 -207 679 -165 ct p ef +995 0 m 995 -330 l 1045 -330 l 1045 -283 l 1055 -299 1069 -312 1086 -322 ct +1103 -332 1123 -337 1145 -337 ct 1169 -337 1189 -332 1205 -322 ct 1220 -312 1231 -297 1238 -279 ct +1264 -318 1298 -337 1339 -337 ct 1372 -337 1397 -328 1415 -310 ct 1432 -292 1441 -264 1441 -226 ct +1441 0 l 1386 0 l 1386 -208 l 1386 -230 1384 -246 1380 -256 ct 1377 -266 1370 -274 1360 -280 ct +1351 -286 1340 -289 1327 -289 ct 1304 -289 1285 -281 1269 -265 ct 1254 -250 1246 -225 1246 -191 ct +1246 0 l 1191 0 l 1191 -214 l 1191 -239 1186 -258 1177 -270 ct 1168 -282 1153 -289 1132 -289 ct +1117 -289 1102 -284 1089 -276 ct 1075 -268 1066 -256 1060 -240 ct 1054 -224 1051 -201 1051 -171 ct +1051 0 l 995 0 l p ef +pom +gr +gs +pum +25241 13337 t +42 0 m 42 -330 l 92 -330 l 92 -283 l 116 -319 151 -337 197 -337 ct 217 -337 235 -333 252 -326 ct +268 -319 281 -310 289 -298 ct 297 -287 303 -273 306 -257 ct 308 -247 309 -229 309 -203 ct +309 0 l 254 0 l 254 -200 l 254 -223 251 -240 247 -252 ct 243 -263 235 -272 224 -279 ct +213 -285 200 -289 185 -289 ct 161 -289 141 -281 124 -266 ct 106 -251 98 -222 98 -180 ct +98 0 l 42 0 l p ef +618 -107 m 676 -99 l 667 -66 650 -40 625 -21 ct 601 -2 569 7 531 7 ct 483 7 445 -8 417 -37 ct +388 -67 374 -109 374 -162 ct 374 -218 389 -261 417 -291 ct 446 -322 483 -337 528 -337 ct +572 -337 608 -322 636 -292 ct 664 -262 678 -220 678 -166 ct 678 -163 678 -158 677 -151 ct +432 -151 l 434 -115 444 -87 463 -68 ct 481 -49 504 -39 531 -39 ct 552 -39 569 -44 584 -55 ct +598 -66 610 -83 618 -107 ct p +435 -197 m 619 -197 l 616 -225 609 -245 598 -259 ct 580 -280 557 -291 529 -291 ct +503 -291 481 -283 464 -265 ct 447 -248 437 -226 435 -197 ct p ef +867 -50 m 875 -1 l 859 2 845 4 833 4 ct 812 4 797 1 785 -6 ct 774 -12 766 -20 762 -31 ct +757 -41 755 -63 755 -97 ct 755 -287 l 714 -287 l 714 -330 l 755 -330 l +755 -412 l 811 -445 l 811 -330 l 867 -330 l 867 -287 l 811 -287 l +811 -94 l 811 -78 812 -68 814 -63 ct 816 -58 819 -55 823 -52 ct 828 -49 834 -48 842 -48 ct +848 -48 857 -49 867 -50 ct p ef +984 0 m 883 -330 l 941 -330 l 993 -139 l 1012 -69 l 1013 -72 1019 -95 1030 -137 ct +1082 -330 l 1139 -330 l 1189 -138 l 1205 -75 l 1224 -139 l 1280 -330 l +1335 -330 l 1232 0 l 1174 0 l 1121 -197 l 1109 -253 l 1042 0 l 984 0 l +p ef +1346 -165 m 1346 -226 1363 -271 1397 -301 ct 1425 -325 1460 -337 1501 -337 ct +1546 -337 1583 -322 1611 -293 ct 1640 -263 1655 -222 1655 -170 ct 1655 -127 1648 -94 1636 -70 ct +1623 -45 1604 -27 1580 -13 ct 1556 0 1529 7 1501 7 ct 1454 7 1417 -8 1389 -37 ct +1360 -67 1346 -110 1346 -165 ct p +1403 -165 m 1403 -123 1413 -91 1431 -70 ct 1449 -49 1473 -39 1501 -39 ct 1528 -39 1551 -49 1570 -71 ct +1588 -92 1597 -124 1597 -167 ct 1597 -208 1588 -239 1569 -260 ct 1551 -281 1528 -291 1501 -291 ct +1473 -291 1449 -281 1431 -260 ct 1413 -239 1403 -207 1403 -165 ct p ef +1717 0 m 1717 -330 l 1767 -330 l 1767 -280 l 1780 -303 1792 -318 1803 -326 ct +1814 -333 1826 -337 1839 -337 ct 1858 -337 1877 -331 1896 -319 ct 1877 -267 l +1863 -275 1850 -279 1836 -279 ct 1824 -279 1813 -276 1803 -268 ct 1793 -261 1786 -251 1782 -238 ct +1776 -218 1773 -196 1773 -173 ct 1773 0 l 1717 0 l p ef +1930 0 m 1930 -455 l 1986 -455 l 1986 -196 l 2118 -330 l 2190 -330 l +2064 -207 l 2203 0 l 2134 0 l 2025 -169 l 1986 -131 l 1986 0 l 1930 0 l +p ef +pom +gr +gr +gs +gs +pum +26008 8604 t +165 0 m 165 -401 l 15 -401 l 15 -455 l 375 -455 l 375 -401 l 225 -401 l +225 0 l 165 0 l p ef +343 -165 m 343 -226 360 -271 394 -301 ct 422 -325 457 -337 498 -337 ct 543 -337 580 -322 608 -293 ct +637 -263 652 -222 652 -170 ct 652 -127 645 -94 633 -70 ct 620 -45 601 -27 577 -13 ct +553 0 526 7 498 7 ct 451 7 414 -8 386 -37 ct 357 -67 343 -110 343 -165 ct p +400 -165 m 400 -123 410 -91 428 -70 ct 446 -49 470 -39 498 -39 ct 525 -39 548 -49 567 -71 ct +585 -92 594 -124 594 -167 ct 594 -208 585 -239 566 -260 ct 548 -281 525 -291 498 -291 ct +470 -291 446 -281 428 -260 ct 410 -239 400 -207 400 -165 ct p ef +pom +gr +gs +pum +25241 9315 t +42 0 m 42 -330 l 92 -330 l 92 -283 l 116 -319 151 -337 197 -337 ct 217 -337 235 -333 252 -326 ct +268 -319 281 -310 289 -298 ct 297 -287 303 -273 306 -257 ct 308 -247 309 -229 309 -203 ct +309 0 l 254 0 l 254 -200 l 254 -223 251 -240 247 -252 ct 243 -263 235 -272 224 -279 ct +213 -285 200 -289 185 -289 ct 161 -289 141 -281 124 -266 ct 106 -251 98 -222 98 -180 ct +98 0 l 42 0 l p ef +618 -107 m 676 -99 l 667 -66 650 -40 625 -21 ct 601 -2 569 7 531 7 ct 483 7 445 -8 417 -37 ct +388 -67 374 -109 374 -162 ct 374 -218 389 -261 417 -291 ct 446 -322 483 -337 528 -337 ct +572 -337 608 -322 636 -292 ct 664 -262 678 -220 678 -166 ct 678 -163 678 -158 677 -151 ct +432 -151 l 434 -115 444 -87 463 -68 ct 481 -49 504 -39 531 -39 ct 552 -39 569 -44 584 -55 ct +598 -66 610 -83 618 -107 ct p +435 -197 m 619 -197 l 616 -225 609 -245 598 -259 ct 580 -280 557 -291 529 -291 ct +503 -291 481 -283 464 -265 ct 447 -248 437 -226 435 -197 ct p ef +867 -50 m 875 -1 l 859 2 845 4 833 4 ct 812 4 797 1 785 -6 ct 774 -12 766 -20 762 -31 ct +757 -41 755 -63 755 -97 ct 755 -287 l 714 -287 l 714 -330 l 755 -330 l +755 -412 l 811 -445 l 811 -330 l 867 -330 l 867 -287 l 811 -287 l +811 -94 l 811 -78 812 -68 814 -63 ct 816 -58 819 -55 823 -52 ct 828 -49 834 -48 842 -48 ct +848 -48 857 -49 867 -50 ct p ef +984 0 m 883 -330 l 941 -330 l 993 -139 l 1012 -69 l 1013 -72 1019 -95 1030 -137 ct +1082 -330 l 1139 -330 l 1189 -138 l 1205 -75 l 1224 -139 l 1280 -330 l +1335 -330 l 1232 0 l 1174 0 l 1121 -197 l 1109 -253 l 1042 0 l 984 0 l +p ef +1346 -165 m 1346 -226 1363 -271 1397 -301 ct 1425 -325 1460 -337 1501 -337 ct +1546 -337 1583 -322 1611 -293 ct 1640 -263 1655 -222 1655 -170 ct 1655 -127 1648 -94 1636 -70 ct +1623 -45 1604 -27 1580 -13 ct 1556 0 1529 7 1501 7 ct 1454 7 1417 -8 1389 -37 ct +1360 -67 1346 -110 1346 -165 ct p +1403 -165 m 1403 -123 1413 -91 1431 -70 ct 1449 -49 1473 -39 1501 -39 ct 1528 -39 1551 -49 1570 -71 ct +1588 -92 1597 -124 1597 -167 ct 1597 -208 1588 -239 1569 -260 ct 1551 -281 1528 -291 1501 -291 ct +1473 -291 1449 -281 1431 -260 ct 1413 -239 1403 -207 1403 -165 ct p ef +1717 0 m 1717 -330 l 1767 -330 l 1767 -280 l 1780 -303 1792 -318 1803 -326 ct +1814 -333 1826 -337 1839 -337 ct 1858 -337 1877 -331 1896 -319 ct 1877 -267 l +1863 -275 1850 -279 1836 -279 ct 1824 -279 1813 -276 1803 -268 ct 1793 -261 1786 -251 1782 -238 ct +1776 -218 1773 -196 1773 -173 ct 1773 0 l 1717 0 l p ef +1930 0 m 1930 -455 l 1986 -455 l 1986 -196 l 2118 -330 l 2190 -330 l +2064 -207 l 2203 0 l 2134 0 l 2025 -169 l 1986 -131 l 1986 0 l 1930 0 l +p ef +pom +gr +gr +gs +gs +pum +4551 10959 t +29 -146 m 85 -151 l 88 -128 94 -109 104 -95 ct 114 -80 129 -68 150 -59 ct +170 -51 194 -46 220 -46 ct 242 -46 263 -49 280 -56 ct 298 -63 311 -72 320 -84 ct +328 -96 332 -109 332 -123 ct 332 -137 328 -150 320 -161 ct 312 -171 298 -180 279 -187 ct +267 -192 240 -200 198 -210 ct 156 -220 127 -229 110 -238 ct 89 -249 73 -263 62 -280 ct +51 -297 46 -316 46 -337 ct 46 -360 52 -381 65 -401 ct 78 -421 97 -436 122 -447 ct +147 -457 175 -462 206 -462 ct 240 -462 269 -457 295 -446 ct 321 -435 341 -419 354 -398 ct +368 -377 376 -353 377 -326 ct 319 -322 l 316 -351 305 -372 288 -387 ct 270 -402 243 -409 208 -409 ct +172 -409 145 -402 129 -389 ct 112 -376 104 -360 104 -341 ct 104 -324 110 -311 122 -301 ct +133 -290 163 -279 212 -268 ct 261 -257 295 -247 313 -239 ct 339 -227 359 -211 371 -193 ct +384 -174 390 -153 390 -128 ct 390 -104 383 -81 370 -60 ct 356 -38 336 -22 310 -10 ct +284 2 255 8 222 8 ct 181 8 147 2 119 -10 ct 91 -22 69 -40 53 -64 ct 38 -88 29 -115 29 -146 ct +p ef +680 -41 m 659 -24 639 -11 620 -4 ct 601 3 580 7 559 7 ct 522 7 495 -2 475 -20 ct +456 -37 446 -60 446 -87 ct 446 -103 450 -118 457 -131 ct 464 -145 474 -156 486 -164 ct +498 -172 511 -178 526 -182 ct 537 -185 553 -188 576 -190 ct 621 -196 654 -202 675 -209 ct +675 -217 675 -222 675 -224 ct 675 -247 670 -263 660 -272 ct 645 -285 624 -291 596 -291 ct +570 -291 550 -286 538 -277 ct 525 -268 516 -252 510 -228 ct 456 -236 l 461 -259 469 -278 480 -292 ct +491 -307 508 -318 529 -326 ct 551 -333 576 -337 604 -337 ct 632 -337 655 -334 673 -327 ct +690 -321 703 -312 711 -302 ct 720 -292 725 -280 729 -264 ct 731 -255 732 -238 732 -213 ct +732 -138 l 732 -87 733 -54 735 -40 ct 737 -26 742 -13 749 0 ct 691 0 l 685 -12 681 -26 680 -41 ct +p +675 -166 m 655 -157 624 -150 584 -145 ct 561 -141 545 -138 535 -133 ct 526 -129 518 -123 513 -115 ct +508 -107 505 -99 505 -89 ct 505 -74 511 -62 522 -52 ct 534 -42 550 -37 572 -37 ct +593 -37 612 -41 629 -51 ct 646 -60 658 -73 666 -89 ct 672 -102 675 -121 675 -145 ct +675 -166 l p ef +817 0 m 817 -330 l 867 -330 l 867 -283 l 877 -299 891 -312 908 -322 ct +925 -332 945 -337 967 -337 ct 991 -337 1011 -332 1027 -322 ct 1042 -312 1053 -297 1060 -279 ct +1086 -318 1120 -337 1161 -337 ct 1194 -337 1219 -328 1237 -310 ct 1254 -292 1263 -264 1263 -226 ct +1263 0 l 1208 0 l 1208 -208 l 1208 -230 1206 -246 1202 -256 ct 1199 -266 1192 -274 1182 -280 ct +1173 -286 1162 -289 1149 -289 ct 1126 -289 1107 -281 1091 -265 ct 1076 -250 1068 -225 1068 -191 ct +1068 0 l 1013 0 l 1013 -214 l 1013 -239 1008 -258 999 -270 ct 990 -282 975 -289 954 -289 ct +939 -289 924 -284 911 -276 ct 897 -268 888 -256 882 -240 ct 876 -224 873 -201 873 -171 ct +873 0 l 817 0 l p ef +1571 -107 m 1629 -99 l 1620 -66 1603 -40 1578 -21 ct 1554 -2 1522 7 1484 7 ct +1436 7 1398 -8 1370 -37 ct 1341 -67 1327 -109 1327 -162 ct 1327 -218 1342 -261 1370 -291 ct +1399 -322 1436 -337 1481 -337 ct 1525 -337 1561 -322 1589 -292 ct 1617 -262 1631 -220 1631 -166 ct +1631 -163 1631 -158 1630 -151 ct 1385 -151 l 1387 -115 1397 -87 1416 -68 ct +1434 -49 1457 -39 1484 -39 ct 1505 -39 1522 -44 1537 -55 ct 1551 -66 1563 -83 1571 -107 ct +p +1388 -197 m 1572 -197 l 1569 -225 1562 -245 1551 -259 ct 1533 -280 1510 -291 1482 -291 ct +1456 -291 1434 -283 1417 -265 ct 1400 -248 1390 -226 1388 -197 ct p ef +2090 -121 m 2145 -114 l 2139 -76 2123 -46 2099 -25 ct 2074 -4 2044 7 2008 7 ct +1963 7 1926 -8 1899 -37 ct 1872 -67 1858 -109 1858 -164 ct 1858 -199 1864 -230 1875 -257 ct +1887 -284 1905 -304 1929 -317 ct 1953 -330 1980 -337 2008 -337 ct 2044 -337 2073 -328 2096 -310 ct +2118 -292 2133 -266 2139 -233 ct 2085 -224 l 2080 -247 2071 -263 2058 -274 ct +2045 -286 2029 -291 2010 -291 ct 1982 -291 1959 -281 1942 -261 ct 1924 -241 1915 -209 1915 -165 ct +1915 -121 1924 -89 1941 -69 ct 1958 -49 1980 -39 2007 -39 ct 2029 -39 2047 -46 2062 -59 ct +2077 -72 2086 -93 2090 -121 ct p ef +2192 0 m 2192 -455 l 2247 -455 l 2247 0 l 2192 0 l p ef +2311 -165 m 2311 -226 2328 -271 2362 -301 ct 2390 -325 2425 -337 2466 -337 ct +2511 -337 2548 -322 2576 -293 ct 2605 -263 2620 -222 2620 -170 ct 2620 -127 2613 -94 2601 -70 ct +2588 -45 2569 -27 2545 -13 ct 2521 0 2494 7 2466 7 ct 2419 7 2382 -8 2354 -37 ct +2325 -67 2311 -110 2311 -165 ct p +2368 -165 m 2368 -123 2378 -91 2396 -70 ct 2414 -49 2438 -39 2466 -39 ct 2493 -39 2516 -49 2535 -71 ct +2553 -92 2562 -124 2562 -167 ct 2562 -208 2553 -239 2534 -260 ct 2516 -281 2493 -291 2466 -291 ct +2438 -291 2414 -281 2396 -260 ct 2378 -239 2368 -207 2368 -165 ct p ef +2899 -121 m 2954 -114 l 2948 -76 2932 -46 2908 -25 ct 2883 -4 2853 7 2817 7 ct +2772 7 2735 -8 2708 -37 ct 2681 -67 2667 -109 2667 -164 ct 2667 -199 2673 -230 2684 -257 ct +2696 -284 2714 -304 2738 -317 ct 2762 -330 2789 -337 2817 -337 ct 2853 -337 2882 -328 2905 -310 ct +2927 -292 2942 -266 2948 -233 ct 2894 -224 l 2889 -247 2880 -263 2867 -274 ct +2854 -286 2838 -291 2819 -291 ct 2791 -291 2768 -281 2751 -261 ct 2733 -241 2724 -209 2724 -165 ct +2724 -121 2733 -89 2750 -69 ct 2767 -49 2789 -39 2816 -39 ct 2838 -39 2856 -46 2871 -59 ct +2886 -72 2895 -93 2899 -121 ct p ef +3001 0 m 3001 -455 l 3057 -455 l 3057 -196 l 3189 -330 l 3261 -330 l +3135 -207 l 3274 0 l 3205 0 l 3096 -169 l 3057 -131 l 3057 0 l 3001 0 l +p ef +pom +gr +gr +0 6126 t +pom +count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore +%%PageTrailer +%%Trailer +%%EOF diff --git a/native/codec/libraries/speex/doc/components.odg b/native/codec/libraries/speex/doc/components.odg new file mode 100644 index 0000000..28aa86c Binary files /dev/null and b/native/codec/libraries/speex/doc/components.odg differ diff --git a/native/codec/libraries/speex/doc/draft-herlein-avt-rtp-speex-00.txt b/native/codec/libraries/speex/doc/draft-herlein-avt-rtp-speex-00.txt new file mode 100644 index 0000000..36733e9 --- /dev/null +++ b/native/codec/libraries/speex/doc/draft-herlein-avt-rtp-speex-00.txt @@ -0,0 +1,699 @@ + + + + +Internet Engineering Task Force Greg Herlein +Internet Draft Jean-Marc Valin +draft-herlein-avt-rtp-speex-00.txt Simon Morlat +March 3, 2004 Roger Hardiman +Expires: September 3, 2004 Phil Kerr + + + RTP Payload Format for the Speex Codec + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC 2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six + months and may be updated, replaced, or obsoleted by other + documents at any time. It is inappropriate to use Internet-Drafts + as reference material or to cite them other than as "work in + progress". + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt + + To view the list Internet-Draft Shadow Directories, see + http://www.ietf.org/shadow.html. + + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + +Abstract + + Speex is an open-source voice codec suitable for use in Voice over + IP (VoIP) type applications. This document describes the payload + format for Speex generated bit streams within an RTP packet. Also + included here are the necessary details for the use of Speex with + the Session Description Protocol (SDP) and a preliminary method of + using Speex within H.323 applications. + + +1. Conventions used in this document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [5]. + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 1] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + +2. Overview of the Speex Codec + + Speex is based on the CELP [12] encoding technique with support for + either narrowband (nominal 8kHz), wideband (nominal 16kHz) or + ultra-wideband (nominal 32kHz), and (non-optimal) rates up to 48 kHz + sampling also available. The main characteristics can be summarized + as follows: + + o Free software/open-source + o Integration of wideband and narrowband in the same bit-stream + o Wide range of bit-rates available + o Dynamic bit-rate switching and variable bit-rate (VBR) + o Voice Activity Detection (VAD, integrated with VBR) + o Variable complexity + + +3. RTP payload format for Speex + + For RTP based transportation of Speex encoded audio the standard + RTP header [2] is followed by one or more payload data blocks. + An optional padding terminator may also be used. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | one or more frames of Speex .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | one or more frames of Speex .... | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +3.1 RTP Header + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + The RTP header begins with an octet of fields (V, P, X, and CC) to + support specialized RTP uses (see [8] and [9] for details). For + Speex the following values are used. + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 2] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + + Version (V): 2 bits + This field identifies the version of RTP. The version + used by this specification is two (2). + + Padding (P): 1 bit + If the padding bit is set, the packet contains one or more + additional padding octets at the end which are not part of + the payload. P is set if the total packet size is less than + the MTU. + + Extension (X): 1 bit + If the extension, X, bit is set, the fixed header MUST be + followed by exactly one header extension, with a format defined + in Section 5.3.1. of [8], + + CSRC count (CC): 4 bits + The CSRC count contains the number of CSRC identifiers. + + Marker (M): 1 bit + The M bit indicates if the packet contains comfort noise. This + field is used in conjunction with the cng SDP attribute and is + detailed further in section 5 below. In normal usage this bit + is set if the packet contains comfort noise. + + Payload Type (PT): 7 bits + An RTP profile for a class of applications is expected to assign + a payload type for this format, or a dynamically allocated + payload type SHOULD be chosen which designates the payload as + Speex. + + Sequence number: 16 bits + The sequence number increments by one for each RTP data packet + sent, and may be used by the receiver to detect packet loss and + to restore packet sequence. This field is detailed further in + [2]. + + Timestamp: 32 bits + A timestamp representing the sampling time of the first sample of + the first Speex packet in the RTP packet. The clock frequency + MUST be set to the sample rate of the encoded audio data. + + Speex uses 20 msec frames and a variable sampling rate clock. + The RTP timestamp MUST be in units of 1/X of a second where X + is the sample rate used. Speex uses a nominal 8kHz sampling rate + for narrowband use, a nominal 16kHz sampling rate for wideband use, + and a nominal 32kHz sampling rate for ultra-wideband use. + + SSRC/CSRC identifiers: + These two fields, 32 bits each with one SSRC field and a maximum + of 16 CSRC fields, are as defined in [2]. + + + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 3] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + +3.2 Speex payload + + For the purposes of packetizing the bit stream in RTP, it is only + necessary to consider the sequence of bits as output by the Speex + encoder [11], and present the same sequence to the decoder. The + payload format described here maintains this sequence. + + A typical Speex frame, encoded at the maximum bitrate, is approx. + 110 octets and the total number of Speex frames SHOULD be kept + less than the path MTU to prevent fragmentation. Speex frames MUST + NOT be fragmented across multiple RTP packets, + + An RTP packet MAY contain Speex frames of the same bit rate or of + varying bit rates, since the bit-rate for a frame is conveyed in + band with the signal. + + The encoding and decoding algorithm can change the bit rate at any + 20 msec frame boundary, with the bit rate change notification provided + in-band with the bit stream. Each frame contains both "mode" + (narrowband, wideband or ultra-wideband) and "sub-mode" (bit-rate) + information in the bit stream. No out-of-band notification is + required for the decoder to process changes in the bit rate sent + by the encoder. + + It is RECOMMENDED that values of 8000, 16000 and 32000 be used + for normal internet telephony applications, though the sample + rate is supported at rates as low as 6000 Hz and as high as + 48 kHz. + + The RTP payload MUST be padded to provide an integer number of + octets as the payload length. These padding bits are LSB aligned + in network byte order and consist of a 0 followed by all ones + (until the end of the octet). This padding is only required for + the last frame in the packet, and only to ensure the packet + contents ends on an octet boundary. + + +3.2.1 Example Speex packet + + In the example below we have a single Speex frame with 5 bits + of padding to ensure the packet size falls on an octet boundary. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 4] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. |0 1 1 1 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +3.4 Multiple Speex frames in a RTP packet + + Below is an example of two Speex frames contained within one RTP + packet. The Speex frame length in this example fall on an octet + boundary so there is no padding. + + Speex codecs [11] are able to detect the the bitrate from the + payload and are responsible for detecting the 20 msec boundaries + between each frame. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +4. MIME registration of Speex + + Full definition of the MIME type for Speex will be part of the Ogg + Vorbis MIME type definition application [10]. + + MIME media type name: audio + + MIME subtype: speex + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 5] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + + Optional parameters: + + Required parameters: to be included in the Ogg MIME specification. + + Encoding considerations: + + Security Considerations: + See Section 6 of RFC 3047. + + Interoperability considerations: none + + Published specification: + + Applications which use this media type: + + Additional information: none + + Person & email address to contact for further information: + Greg Herlein + Jean-Marc Valin + + Intended usage: COMMON + + Author/Change controller: + Author: Greg Herlein + Change controller: Greg Herlein + + This transport type signifies that the content is to be interpreted + according to this document if the contents are transmitted over RTP. + Should this transport type appear over a lossless streaming protocol + such as TCP, the content encapsulation should be interpreted as an + Ogg Stream in accordance with RFC 3534, with the exception that the + content of the Ogg Stream may be assumed to be Speex audio and + Speex audio only. + + +5. SDP usage of Speex + + When conveying information by SDP [4], the encoding name MUST be + set to "speex". An example of the media representation in SDP for + offering a single channel of Speex at 8000 samples per second might + be: + + m=audio 8088 RTP/AVP 97 + a=rtpmap:97 speex/8000 + + Note that the RTP payload type code of 97 is defined in this media + definition to be 'mapped' to the speex codec at an 8kHz sampling + frequency using the 'a=rtpmap' line. Any number from 96 to 127 + could have been chosen (the allowed range for dynamic types). + + + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 6] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + + The value of the sampling frequency is typically 8000 for narrow band + operation, 16000 for wide band operation, and 32000 for ultra-wide + band operation. + + If for some reason the offerer has bandwidth limitations, the client + may use the "b=" header, as explained in SDP [4]. The following example + illustrates the case where the offerer cannot receive more than + 10 kbit/s. + + m=audio 8088 RTP/AVP 97 + b=AS:10 + a=rtmap:97 speex/8000 + + In this case, if the remote part agrees, it should configure its + Speex encoder so that it does not use modes that produce more than + 10 kbit/s. Note that the "b=" constraint also applies on all + payload types that may be proposed in the media line ("m="). + + An other way to make recommendations to the remote Speex encoder + is to use its specific parameters via the a=fmtp: directive. The + following parameters are defined for use in this way: + + ptime: duration of each packet in milliseconds. + + sr: actual sample rate in Hz. + + ebw: encoding bandwidth - either 'narrow' or 'wide' or + 'ultra' (corresponds to nominal 8000, 16000, and + 32000 Hz sampling rates). + + vbr: variable bit rate - either 'on' 'off' or 'vad' + (defaults to off). If on, variable bit rate is + enabled. If off, disabled. If set to 'vad' then + constant bit rate is used but silence will be encoded + with special short frames to indicate a lack of voice + for that period. + + cng: comfort noise generation - either 'on' or 'off'. If + off then silence frames will be silent; if 'on' then + those frames will be filled with comfort noise. + + mode: Speex encoding mode. Can be {1,2,3,4,5,6,any} + defaults to 3 in narrowband, 6 in wide and ultra-wide. + + penh: use of perceptual enhancement. 1 indicates + to the decoder that perceptual enhancement is recommended, + 0 indicates that it is not. Defaults to on (1). + + + + + + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 7] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + + Examples: + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=fmtp:97 mode=4 + + This examples illustrate an offerer that wishes to receive + a Speex stream at 8000Hz, but only using speex mode 3. + + The offerer may suggest to the remote decoder to activate + its perceptual enhancement filter like this: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 penh=1 + + Several Speex specific parameters can be given in a single + a=fmtp line provided that they are separated by a semi-colon: + + a=fmtp:97 mode=any;penh=1 + + The offerer may indicate that it wishes to send variable bit rate + frames with comfort noise: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 vbr=on;cng=on + + The "ptime" attribute is used to denote the packetization + interval (ie, how many milliseconds of audio is encoded in a + single RTP packet). Since Speex uses 20 msec frames, ptime values + of multiples of 20 denote multiple Speex frames per packet. + Values of ptime which are not multiples of 20 MUST be ignored + and clients MUST use the default value of 20 instead. + + In the example below the ptime value is set to 40, indicating that + there are 2 frames in each packet. + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=ptime:40 + + Note that the ptime parameter applies to all payloads listed + in the media line and is not used as part of an a=fmtp directive. + + Values of ptime not multiple of 20 msec are meaningless, so the + receiver of such ptime values MUST ignore them. If during the + life of an RTP session the ptime value changes, when there are + multiple Speex frames for example, the SDP value must also reflect + the new value. + + + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 8] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + + Care must be taken when setting the value of ptime so that the + RTP packet size does not exceed the path MTU. + + +6. ITU H.323/H.245 Use of Speex + + Application is underway to make Speex a standard ITU codec. + However, until that is finalized, Speex MAY be used in H.323 [6] by + using a non-standard codec block definition in the H.245 [7] codec + capability negotiations. + + +6.1 NonStandardMessage format + + For Speex use in H.245 [7] based systems, the fields in the + NonStandardMessage should be: + + t35CountryCode = Hex: B5 + t35Extension = Hex: 00 + manufacturerCode = Hex: 0026 + [Length of the Binary Sequence (8 bit number)] + [Binary Sequence consisting of an ASCII string, no NULL terminator] + + The binary sequence is an ascii string merely for ease of use. + The string is not null terminated. The format of this string is + + speex [optional variables] + + The optional variables are identical to those used for the SDP + a=fmtp strings discussed in section 5 above. The string is built + to be all on one line, each key-value pair separated by a + semi-colon. The optional variables MAY be omitted, which causes + the default values to be assumed. They are: + + ebw=narrow;mode=3;vbr=off;cng=off;ptime=20;sr=8000;penh=no; + + The fifth byte of the block is the length of the binary sequence. + + NOTE: this method can result in the advertising of a large number + of Speex 'codecs' based on the number of variables possible. For + most VoIP applications, use of the default binary sequence of + 'speex' is RECOMMENDED to be used in addition to all other options. + This maximizes the chances that two H.323 based applications that + support Speex can find a mutual codec. + + +6.2 RTP Payload Types + + Dynamic payload type codes MUST be negotiated 'out-of-band' + for the assignment of a dynamic payload type from the + range of 96-127. H.323 applications MUST use the H.245 + H2250LogicalChannelParameters encoding to accomplish this. + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 9] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + +7. Security Considerations + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification [2], and any appropriate RTP profile. This implies + that confidentiality of the media streams is achieved by encryption. + Because the data compression used with this payload format is applied + end-to-end, encryption may be performed after compression so there is + no conflict between the two operations. + + A potential denial-of-service threat exists for data encodings using + compression techniques that have non-uniform receiver-end + computational load. The attacker can inject pathological datagrams + into the stream which are complex to decode and cause the receiver to + be overloaded. However, this encoding does not exhibit any + significant non-uniformity. + + As with any IP-based protocol, in some circumstances a receiver may + be overloaded simply by the receipt of too many packets, either + desired or undesired. Network-layer authentication may be used to + discard packets from undesired sources, but the processing cost of + the authentication itself may be too high. + + +8. Normative References + + 1. Bradner, S., "The Internet Standards Process -- Revision 3", BCP + 9, RFC 2026, October 1996. + + 2. Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, "RTP: + A Transport Protocol for real-time applications", RFC 1889, + January 1996. + + 3. Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message Bodies", + RFC 2045, November 1996. + + 4. Handley, M. and V. Jacobson, "SDP: Session Description + Protocol", RFC 2327, April 1998. + + 5. Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + 6. ITU-T Recommendation H.323. "Packet-based Multimedia + Communications Systems," 1998. + + 7. ITU-T Recommendation H.245 (1998), "Control of communications + between Visual Telephone Systems and Terminal Equipment". + + 8. RTP: A transport protocol for real-time applications. Work + in progress, draft-ietf-avt-rtp-new-12.txt. + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 10] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + + 9. RTP Profile for Audio and Video Conferences with Minimal + Control. Work in progress, draft-ietf-avt-profile-new-13.txt. + + 10. L. Walleij, "The application/ogg Media Type", RFC 3534, May + 2003. + + +8.1 Informative References + + 11. Speexenc/speexdec, reference command-line encoder/decoder, + Speex website, http://www.speex.org/ + + 12. CELP, U.S. Federal Standard 1016. National Technical + Information Service (NTIS) website, http://www.ntis.gov/ + + +9. Acknowledgments + + The authors would like to thank Equivalence Pty Ltd of Australia + for their assistance in attempting to standardize the use of Speex + in H.323 applications, and for implementing Speex in their open + source OpenH323 stack. The authors would also like to thank Brian + C. Wiles of StreamComm for his assistance in + developing the proposed standard for Speex use in H.323 + applications. + + The authors would also like to thank the following members of the + Speex and AVT communities for their input: Ross Finlayson, + Federico Montesino Pouzols, Henning Schulzrinne, Magnus Westerlund. + + +10. Author's Address + + Greg Herlein + 2034 Filbert Street + San Francisco, CA + United States 94123 + + + Jean-Marc Valin + Department of Electrical and Computer Engineering + University of Sherbrooke + 2500 blvd UniversitüÃü­üÃé + Sherbrooke, Quebec, Canada, J1K 2R1 + + + Simon MORLAT + 35, av de Vizille App 42 + 38000 GRENOBLE + FRANCE + + + + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 11] +^L +Internet-Draft draft-herlein-avt-rtp-speex-00.txt March 3, 2004 + + + Roger Hardiman + 49 Nettleton Road + Cheltenham + Gloucestershire + GL51 6NR + England + + + Phil Kerr + Centre for Music Technology + University of Glasgow + Glasgow + G12 8LT + Scotland + + +10. Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + +Herlein, Valin, et. al. Expires September 3, 2004 [Page 12] +^L + + diff --git a/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-02.txt b/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-02.txt new file mode 100644 index 0000000..2b25ea6 --- /dev/null +++ b/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-02.txt @@ -0,0 +1,841 @@ + + +AVT Working Group G. Herlein +Internet-Draft S. Morlat +Expires: October 3, 2005 J. Jean-Marc + R. Hardiman + P. Kerr + April 04, 2005 + + + draft-herlein-speex-rtp-profile-02 + RTP Payload Format for the Speex Codec + +Status of this Memo + + This document is an Internet-Draft and is subject to all provisions + of section 3 of RFC 3667. By submitting this Internet-Draft, each + author represents that any applicable patent or other IPR claims of + which he or she is aware have been or will be disclosed, and any of + which he or she become aware will be disclosed, in accordance with + RFC 3668. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as + Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on October 3, 2005. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + Speex is an open-source voice codec suitable for use in Voice over IP + (VoIP) type applications. This document describes the payload format + for Speex generated bit streams within an RTP packet. Also included + here are the necessary details for the use of Speex with the Session + Description Protocol (SDP) and a preliminary method of using Speex + + + +Herlein, et al. Expires October 3, 2005 [Page 1] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + within H.323 applications. + +Table of Contents + + 1. Conventions used in this document . . . . . . . . . . . . . 3 + 2. Overview of the Speex Codec . . . . . . . . . . . . . . . . 3 + 3. RTP payload format for Speex . . . . . . . . . . . . . . . . 3 + 4. RTP Header . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 5. Speex payload . . . . . . . . . . . . . . . . . . . . . . . 5 + 6. Example Speex packet . . . . . . . . . . . . . . . . . . . . 6 + 7. Multiple Speex frames in a RTP packet . . . . . . . . . . . 6 + 8. MIME registration of Speex . . . . . . . . . . . . . . . . . 7 + 9. SDP usage of Speex . . . . . . . . . . . . . . . . . . . . . 8 + 10. ITU H.323/H.245 Use of Speex . . . . . . . . . . . . . . . . 10 + 11. NonStandardMessage format . . . . . . . . . . . . . . . . . 10 + 12. RTP Payload Types . . . . . . . . . . . . . . . . . . . . . 11 + 13. Security Considerations . . . . . . . . . . . . . . . . . . 11 + 14. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . 12 + 15. References . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 15.1 Normative References . . . . . . . . . . . . . . . . . . . 12 + 15.2 Informative References . . . . . . . . . . . . . . . . . . 13 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 13 + Intellectual Property and Copyright Statements . . . . . . . 15 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 3, 2005 [Page 2] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + +1. Conventions used in this document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [1]. + +2. Overview of the Speex Codec + + Speex is based on the CELP [10] encoding technique with support for + either narrowband (nominal 8kHz), wideband (nominal 16kHz) or + ultra-wideband (nominal 32kHz), and (non-optimal) rates up to 48 kHz + sampling also available. The main characteristics can be summarized + as follows: + + o Free software/open-source + o Integration of wideband and narrowband in the same bit-stream + o Wide range of bit-rates available + o Dynamic bit-rate switching and variable bit-rate (VBR) + o Voice Activity Detection (VAD, integrated with VBR) + o Variable complexity + +3. RTP payload format for Speex + + For RTP based transportation of Speex encoded audio the standard RTP + header [2] is followed by one or more payload data blocks. An + optional padding terminator may also be used. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | one or more frames of Speex .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | one or more frames of Speex .... | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +4. RTP Header + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + + + +Herlein, et al. Expires October 3, 2005 [Page 3] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The RTP header begins with an octet of fields (V, P, X, and CC) to + support specialized RTP uses (see [2] and [7] for details). For + Speex the following values are used. + + Version (V): 2 bits + + This field identifies the version of RTP. The version used by this + specification is two [2]. + + Padding (P): 1 bit + + If the padding bit is set, the packet contains one or more additional + padding octets at the end which are not part of the payload. P is + set if the total packet size is less than the MTU. + + Extension (X): 1 bit + + If the extension, X, bit is set, the fixed header MUST be followed by + exactly one header extension, with a format defined in Section 5.3.1. + of [2]. + + CSRC count (CC): 4 bits + + The CSRC count contains the number of CSRC identifiers. + + Marker (M): 1 bit + + The M bit indicates if the packet contains comfort noise. This field + is used in conjunction with the cng SDP attribute and is detailed + further in section 5 below. In normal usage this bit is set if the + packet contains comfort noise. + + Payload Type (PT): 7 bits + + An RTP profile for a class of applications is expected to assign a + payload type for this format, or a dynamically allocated payload type + SHOULD be chosen which designates the payload as Speex. + + Sequence number: 16 bits + + The sequence number increments by one for each RTP data packet sent, + and may be used by the receiver to detect packet loss and to restore + packet sequence. This field is detailed further in [2]. + + + +Herlein, et al. Expires October 3, 2005 [Page 4] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + Timestamp: 32 bits + + A timestamp representing the sampling time of the first sample of the + first Speex packet in the RTP packet. The clock frequency MUST be + set to the sample rate of the encoded audio data. Speex uses 20 msec + frames and a variable sampling rate clock. The RTP timestamp MUST be + in units of 1/X of a second where X is the sample rate used. Speex + uses a nominal 8kHz sampling rate for narrowband use, a nominal 16kHz + sampling rate for wideband use, and a nominal 32kHz sampling rate for + ultra-wideband use. + + SSRC/CSRC identifiers: + + These two fields, 32 bits each with one SSRC field and a maximum of + 16 CSRC fields, are as defined in [2]. + +5. Speex payload + + For the purposes of packetizing the bit stream in RTP, it is only + necessary to consider the sequence of bits as output by the Speex + encoder [9], and present the same sequence to the decoder. The + payload format described here maintains this sequence. + + A typical Speex frame, encoded at the maximum bitrate, is approx. + 110 octets and the total number of Speex frames SHOULD be kept less + than the path MTU to prevent fragmentation. Speex frames MUST NOT be + fragmented across multiple RTP packets, + + An RTP packet MAY contain Speex frames of the same bit rate or of + varying bit rates, since the bit-rate for a frame is conveyed in band + with the signal. + + The encoding and decoding algorithm can change the bit rate at any 20 + msec frame boundary, with the bit rate change notification provided + in-band with the bit stream. Each frame contains both "mode" + (narrowband, wideband or ultra-wideband) and "sub-mode" (bit-rate) + information in the bit stream. No out-of-band notification is + required for the decoder to process changes in the bit rate sent by + the encoder. + + It is RECOMMENDED that values of 8000, 16000 and 32000 be used for + normal internet telephony applications, though the sample rate is + supported at rates as low as 6000 Hz and as high as 48 kHz. + + The RTP payload MUST be padded to provide an integer number of octets + as the payload length. These padding bits are LSB aligned in network + octet order and consist of a 0 followed by all ones (until the end of + the octet). This padding is only required for the last frame in the + + + +Herlein, et al. Expires October 3, 2005 [Page 5] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + packet, and only to ensure the packet contents ends on an octet + boundary. + +6. Example Speex packet + + In the example below we have a single Speex frame with 5 bits of + padding to ensure the packet size falls on an octet boundary. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. |0 1 1 1 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +7. Multiple Speex frames in a RTP packet + + Below is an example of two Speex frames contained within one RTP + packet. The Speex frame length in this example fall on an octet + boundary so there is no padding. + + Speex codecs [9] are able to detect the the bitrate from the payload + and are responsible for detecting the 20 msec boundaries between each + frame. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +Herlein, et al. Expires October 3, 2005 [Page 6] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +8. MIME registration of Speex + + Full definition of the MIME [3] type for Speex will be part of the + Ogg Vorbis MIME type definition application [8]. + + MIME media type name: audio + + MIME subtype: speex + + Optional parameters: + + Required parameters: to be included in the Ogg MIME specification. + + Encoding considerations: + + Security Considerations: + + See Section 6 of RFC 3047. + + Interoperability considerations: none + + Published specification: + + Applications which use this media type: + + Additional information: none + + Person & email address to contact for further information: + + Greg Herlein + Jean-Marc Valin + + Intended usage: COMMON + + + + +Herlein, et al. Expires October 3, 2005 [Page 7] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + Author/Change controller: + + Author: Greg Herlein + Change controller: Greg Herlein + Change controller: IETF AVT Working Group + + This transport type signifies that the content is to be interpreted + according to this document if the contents are transmitted over RTP. + Should this transport type appear over a lossless streaming protocol + such as TCP, the content encapsulation should be interpreted as an + Ogg Stream in accordance with [8], with the exception that the + content of the Ogg Stream may be assumed to be Speex audio and Speex + audio only. + +9. SDP usage of Speex + + When conveying information by SDP [4], the encoding name MUST be set + to "speex". An example of the media representation in SDP for + offering a single channel of Speex at 8000 samples per second might + be: + + m=audio 8088 RTP/AVP 97 + a=rtpmap:97 speex/8000 + + Note that the RTP payload type code of 97 is defined in this media + definition to be 'mapped' to the speex codec at an 8kHz sampling + frequency using the 'a=rtpmap' line. Any number from 96 to 127 could + have been chosen (the allowed range for dynamic types). + + The value of the sampling frequency is typically 8000 for narrow band + operation, 16000 for wide band operation, and 32000 for ultra-wide + band operation. + + If for some reason the offerer has bandwidth limitations, the client + may use the "b=" header, as explained in SDP [4]. The following + example illustrates the case where the offerer cannot receive more + than 10 kbit/s. + + m=audio 8088 RTP/AVP 97 + b=AS:10 + a=rtmap:97 speex/8000 + + In this case, if the remote part agrees, it should configure its + Speex encoder so that it does not use modes that produce more than 10 + kbit/s. Note that the "b=" constraint also applies on all payload + types that may be proposed in the media line ("m="). + + An other way to make recommendations to the remote Speex encoder is + + + +Herlein, et al. Expires October 3, 2005 [Page 8] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + to use its specific parameters via the a=fmtp: directive. The + following parameters are defined for use in this way: + + ptime: duration of each packet in milliseconds. + + sr: actual sample rate in Hz. + + ebw: encoding bandwidth - either 'narrow' or 'wide' or 'ultra' + (corresponds to nominal 8000, 16000, and 32000 Hz sampling rates). + + vbr: variable bit rate - either 'on' 'off' or 'vad' (defaults + to off). If on, variable bit rate is enabled. If off, disabled. + If set to 'vad' then constant bit rate is used but silence will be + encoded with special short frames to indicate a lack of voice for + that period. + + cng: comfort noise generation - either 'on' or 'off'. If off + then silence frames will be silent; if 'on' then those frames will + be filled with comfort noise. + + mode: Speex encoding mode. Can be {1,2,3,4,5,6,any} defaults to + 3 in narrowband, 6 in wide and ultra-wide. + + penh: use of perceptual enhancement. 1 indicates to the decoder + that perceptual enhancement is recommended, 0 indicates that it is + not. Defaults to on (1). + + + Examples: + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=fmtp:97 mode=4 + + This examples illustrate an offerer that wishes to receive a Speex + stream at 8000Hz, but only using speex mode 3. + + The offerer may suggest to the remote decoder to activate its + perceptual enhancement filter like this: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 penh=1 + + Several Speex specific parameters can be given in a single a=fmtp + line provided that they are separated by a semi-colon: + + + + + +Herlein, et al. Expires October 3, 2005 [Page 9] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + a=fmtp:97 mode=any;penh=1 + + The offerer may indicate that it wishes to send variable bit rate + frames with comfort noise: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 vbr=on;cng=on + + The "ptime" attribute is used to denote the packetization interval + (ie, how many milliseconds of audio is encoded in a single RTP + packet). Since Speex uses 20 msec frames, ptime values of multiples + of 20 denote multiple Speex frames per packet. Values of ptime which + are not multiples of 20 MUST be ignored and clients MUST use the + default value of 20 instead. + + In the example below the ptime value is set to 40, indicating that + there are 2 frames in each packet. + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=ptime:40 + + Note that the ptime parameter applies to all payloads listed in the + media line and is not used as part of an a=fmtp directive. + + Values of ptime not multiple of 20 msec are meaningless, so the + receiver of such ptime values MUST ignore them. If during the life + of an RTP session the ptime value changes, when there are multiple + Speex frames for example, the SDP value must also reflect the new + value. + + Care must be taken when setting the value of ptime so that the RTP + packet size does not exceed the path MTU. + +10. ITU H.323/H.245 Use of Speex + + Application is underway to make Speex a standard ITU codec. However, + until that is finalized, Speex MAY be used in H.323 [5] by using a + non-standard codec block definition in the H.245 [6] codec capability + negotiations. + +11. NonStandardMessage format + + For Speex use in H.245 [6] based systems, the fields in the + NonStandardMessage should be: + + + + + +Herlein, et al. Expires October 3, 2005 [Page 10] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + t35CountryCode = Hex: B5 + t35Extension = Hex: 00 + manufacturerCode = Hex: 0026 + [Length of the Binary Sequence (8 bit number)] + [Binary Sequence consisting of an ASCII string, no NULL + terminator] + + The binary sequence is an ascii string merely for ease of use. The + string is not null terminated. The format of this string is + + speex [optional variables] + + The optional variables are identical to those used for the SDP a=fmtp + strings discussed in section 5 above. The string is built to be all + on one line, each key-value pair separated by a semi-colon. The + optional variables MAY be omitted, which causes the default values to + be assumed. They are: + + ebw=narrow;mode=3;vbr=off;cng=off;ptime=20;sr=8000;penh=no; + + The fifth octet of the block is the length of the binary sequence. + + NOTE: this method can result in the advertising of a large number of + Speex 'codecs' based on the number of variables possible. For most + VoIP applications, use of the default binary sequence of 'speex' is + RECOMMENDED to be used in addition to all other options. This + maximizes the chances that two H.323 based applications that support + Speex can find a mutual codec. + +12. RTP Payload Types + + Dynamic payload type codes MUST be negotiated 'out-of-band' for the + assignment of a dynamic payload type from the range of 96-127. H.323 + applications MUST use the H.245 H2250LogicalChannelParameters + encoding to accomplish this. + +13. Security Considerations + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification [2], and any appropriate RTP profile. This implies + that confidentiality of the media streams is achieved by encryption. + Because the data compression used with this payload format is applied + end-to-end, encryption may be performed after compression so there is + no conflict between the two operations. + + A potential denial-of-service threat exists for data encodings using + compression techniques that have non-uniform receiver-end + + + +Herlein, et al. Expires October 3, 2005 [Page 11] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + computational load. The attacker can inject pathological datagrams + into the stream which are complex to decode and cause the receiver to + be overloaded. However, this encoding does not exhibit any + significant non-uniformity. + + As with any IP-based protocol, in some circumstances a receiver may + be overloaded simply by the receipt of too many packets, either + desired or undesired. Network-layer authentication may be used to + discard packets from undesired sources, but the processing cost of + the authentication itself may be too high. + +14. Acknowledgments + + The authors would like to thank Equivalence Pty Ltd of Australia for + their assistance in attempting to standardize the use of Speex in + H.323 applications, and for implementing Speex in their open source + OpenH323 stack. The authors would also like to thank Brian C. Wiles + of StreamComm for his assistance in developing + the proposed standard for Speex use in H.323 applications. + + The authors would also like to thank the following members of the + Speex and AVT communities for their input: Ross Finlayson, Federico + Montesino Pouzols, Henning Schulzrinne, Magnus Westerlund. + +15. References + +15.1 Normative References + + [1] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", RFC 2119. + + [2] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, + "RTP: A Transport Protocol for real-time applications", RFC + 3550. + + [3] "Multipurpose Internet Mail Extensions (MIME) Part One: Format + of Internet Message Bodies", RFC 2045. + + [4] Jacobson, V. and M. Handley, "SDP: Session Description + Protocol", RFC 2327. + + [5] "Packet-based Multimedia Communications Systems", ITU-T + Recommendation H.323. + + [6] "Control of communications between Visual Telephone Systems and + Terminal Equipment", ITU-T Recommendation H.245. + + [7] Schulzrinne, H. and S. Casner, "RTP Profile for Audio and Video + + + +Herlein, et al. Expires October 3, 2005 [Page 12] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + Conferences with Minimal Control.", RFC 3551. + + [8] Walleij, L., "The application/ogg Media Type", RFC 3534. + +15.2 Informative References + + [9] "Speexenc/speexdec, reference command-line encoder/decoder", + Speex website http://www.speex.org/. + + [10] "CELP, U.S. Federal Standard 1016.", National Technical + Information Service (NTIS) website http://www.ntis.gov/. + + +Authors' Addresses + + Greg Herlein + 2034 Filbert Street + San Francisco, California 94123 + United States + + EMail: gherlein@herlein.com + + + Simon Morlat + 35, av de Vizille App 42 + Grenoble 38000 + France + + EMail: simon.morlat@linphone.org + + + Jean-Marc Valin + Department of Electrical and Computer Engineering + University of Sherbrooke + 2500 blvd Universite + Sherbrooke, Quebec J1K 2R1 + Canada + + EMail: jean-marc.valin@hermes.usherb.ca + + + Roger Hardiman + 49 Nettleton Road + Cheltenham, Gloucestershire GL51 6NR + England + + EMail: roger@freebsd.org + + + + +Herlein, et al. Expires October 3, 2005 [Page 13] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + + Phil Kerr + England + + EMail: phil@plus24.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 3, 2005 [Page 14] + +Internet-Draft draft-herlein-speex-rtp-profile-02 April 2005 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + +Disclaimer of Validity + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Copyright Statement + + Copyright (C) The Internet Society (2005). This document is subject + to the rights, licenses and restrictions contained in BCP 78, and + except as set forth therein, the authors retain all their rights. + + +Acknowledgment + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + +Herlein, et al. Expires October 3, 2005 [Page 15] + + diff --git a/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-03.txt b/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-03.txt new file mode 100644 index 0000000..d1ad4b3 --- /dev/null +++ b/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-03.txt @@ -0,0 +1,1232 @@ + + +AVT Working Group G. Herlein +Internet-Draft S. Morlat +Expires: July 2, 2005 J. Jean-Marc + R. Hardiman + P. Kerr + January 01, 2005 + + + draft-herlein-speex-rtp-profile-03 + RTP Payload Format for the Speex Codec + +Status of this Memo + + This document is an Internet-Draft and is subject to all provisions + of section 3 of RFC 3667. By submitting this Internet-Draft, each + author represents that any applicable patent or other IPR claims of + which he or she is aware have been or will be disclosed, and any of + which he or she become aware will be disclosed, in accordance with + RFC 3668. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as + Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on July 2, 2005. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + Speex is an open-source voice codec suitable for use in Voice over IP + (VoIP) type applications. This document describes the payload format + for Speex generated bit streams within an RTP packet. Also included + here are the necessary details for the use of Speex with the Session + Description Protocol (SDP) and a preliminary method of using Speex + + + +Herlein, et al. Expires July 2, 2005 [Page 1] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + + within H.323 applications. + +Table of Contents + + 1. Conventions used in this document . . . . . . . . . . . . . 3 + 2. Overview of the Speex Codec . . . . . . . . . . . . . . . . 4 + 3. RTP payload format for Speex . . . . . . . . . . . . . . . . 5 + 4. RTP Header . . . . . . . . . . . . . . . . . . . . . . . . . 6 + 5. Speex payload . . . . . . . . . . . . . . . . . . . . . . . 8 + 6. Example Speex packet . . . . . . . . . . . . . . . . . . . . 9 + 7. Multiple Speex frames in a RTP packet . . . . . . . . . . . 10 + 8. MIME registration of Speex . . . . . . . . . . . . . . . . . 11 + 9. SDP usage of Speex . . . . . . . . . . . . . . . . . . . . . 12 + 10. ITU H.323/H.245 Use of Speex . . . . . . . . . . . . . . . . 15 + 11. NonStandardMessage format . . . . . . . . . . . . . . . . . 16 + 12. RTP Payload Types . . . . . . . . . . . . . . . . . . . . . 17 + 13. Security Considerations . . . . . . . . . . . . . . . . . . 18 + 14. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . 19 + 15. References . . . . . . . . . . . . . . . . . . . . . . . . . 20 + 15.1 Normative References . . . . . . . . . . . . . . . . . . . 20 + 15.2 Informative References . . . . . . . . . . . . . . . . . . 20 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 20 + Intellectual Property and Copyright Statements . . . . . . . 22 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 2] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +1. Conventions used in this document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [1]. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 3] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +2. Overview of the Speex Codec + + Speex is based on the CELP [10] encoding technique with support for + either narrowband (nominal 8kHz), wideband (nominal 16kHz) or + ultra-wideband (nominal 32kHz), and (non-optimal) rates up to 48 kHz + sampling also available. The main characteristics can be summarized + as follows: + + o Free software/open-source + o Integration of wideband and narrowband in the same bit-stream + o Wide range of bit-rates available + o Dynamic bit-rate switching and variable bit-rate (VBR) + o Voice Activity Detection (VAD, integrated with VBR) + o Variable complexity + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 4] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +3. RTP payload format for Speex + + For RTP based transportation of Speex encoded audio the standard RTP + header [2] is followed by one or more payload data blocks. An + optional padding terminator may also be used. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | one or more frames of Speex .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | one or more frames of Speex .... | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 5] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +4. RTP Header + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The RTP header begins with an octet of fields (V, P, X, and CC) to + support specialized RTP uses (see [2] and [7] for details). For + Speex the following values are used. + + Version (V): 2 bits + + This field identifies the version of RTP. The version used by this + specification is two [2]. + + Padding (P): 1 bit + + If the padding bit is set, the packet contains one or more additional + padding octets at the end which are not part of the payload. P is + set if the total packet size is less than the MTU. + + Extension (X): 1 bit + + If the extension, X, bit is set, the fixed header MUST be followed by + exactly one header extension, with a format defined in Section 5.3.1. + of [2]. + + CSRC count (CC): 4 bits + + The CSRC count contains the number of CSRC identifiers. + + Marker (M): 1 bit + + The M bit indicates if the packet contains comfort noise. This field + is used in conjunction with the cng SDP attribute and is detailed + further in section 5 below. In normal usage this bit is set if the + packet contains comfort noise. + + Payload Type (PT): 7 bits + + + +Herlein, et al. Expires July 2, 2005 [Page 6] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + + An RTP profile for a class of applications is expected to assign a + payload type for this format, or a dynamically allocated payload type + SHOULD be chosen which designates the payload as Speex. + + Sequence number: 16 bits + + The sequence number increments by one for each RTP data packet sent, + and may be used by the receiver to detect packet loss and to restore + packet sequence. This field is detailed further in [2]. + + Timestamp: 32 bits + + A timestamp representing the sampling time of the first sample of the + first Speex packet in the RTP packet. The clock frequency MUST be + set to the sample rate of the encoded audio data. Speex uses 20 msec + frames and a variable sampling rate clock. The RTP timestamp MUST be + in units of 1/X of a second where X is the sample rate used. Speex + uses a nominal 8kHz sampling rate for narrowband use, a nominal 16kHz + sampling rate for wideband use, and a nominal 32kHz sampling rate for + ultra-wideband use. + + SSRC/CSRC identifiers: + + These two fields, 32 bits each with one SSRC field and a maximum of + 16 CSRC fields, are as defined in [2]. + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 7] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +5. Speex payload + + For the purposes of packetizing the bit stream in RTP, it is only + necessary to consider the sequence of bits as output by the Speex + encoder [9], and present the same sequence to the decoder. The + payload format described here maintains this sequence. + + A typical Speex frame, encoded at the maximum bitrate, is approx. + 110 octets and the total number of Speex frames SHOULD be kept less + than the path MTU to prevent fragmentation. Speex frames MUST NOT be + fragmented across multiple RTP packets, + + An RTP packet MAY contain Speex frames of the same bit rate or of + varying bit rates, since the bit-rate for a frame is conveyed in band + with the signal. + + The encoding and decoding algorithm can change the bit rate at any 20 + msec frame boundary, with the bit rate change notification provided + in-band with the bit stream. Each frame contains both "mode" + (narrowband, wideband or ultra-wideband) and "sub-mode" (bit-rate) + information in the bit stream. No out-of-band notification is + required for the decoder to process changes in the bit rate sent by + the encoder. + + It is RECOMMENDED that values of 8000, 16000 and 32000 be used for + normal internet telephony applications, though the sample rate is + supported at rates as low as 6000 Hz and as high as 48 kHz. + + The RTP payload MUST be padded to provide an integer number of octets + as the payload length. These padding bits are LSB aligned in network + octet order and consist of a 0 followed by all ones (until the end of + the octet). This padding is only required for the last frame in the + packet, and only to ensure the packet contents ends on an octet + boundary. + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 8] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +6. Example Speex packet + + In the example below we have a single Speex frame with 5 bits of + padding to ensure the packet size falls on an octet boundary. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. |0 1 1 1 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 9] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +7. Multiple Speex frames in a RTP packet + + Below is an example of two Speex frames contained within one RTP + packet. The Speex frame length in this example fall on an octet + boundary so there is no padding. + + Speex codecs [9] are able to detect the the bitrate from the payload + and are responsible for detecting the 20 msec boundaries between each + frame. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 10] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +8. MIME registration of Speex + + Full definition of the MIME [3] type for Speex will be part of the + Ogg Vorbis MIME type definition application [8]. + + MIME media type name: audio + + MIME subtype: speex + + Optional parameters: + + Required parameters: to be included in the Ogg MIME specification. + + Encoding considerations: + + Security Considerations: + + See Section 6 of RFC 3047. + + Interoperability considerations: none + + Published specification: + + Applications which use this media type: + + Additional information: none + + Person & email address to contact for further information: + + Greg Herlein + Jean-Marc Valin + + Intended usage: COMMON + + Author/Change controller: + + Author: Greg Herlein + Change controller: Greg Herlein + Change controller: IETF AVT Working Group + + This transport type signifies that the content is to be interpreted + according to this document if the contents are transmitted over RTP. + Should this transport type appear over a lossless streaming protocol + such as TCP, the content encapsulation should be interpreted as an + Ogg Stream in accordance with [8], with the exception that the + content of the Ogg Stream may be assumed to be Speex audio and Speex + audio only. + + + + +Herlein, et al. Expires July 2, 2005 [Page 11] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +9. SDP usage of Speex + + When conveying information by SDP [4], the encoding name MUST be set + to "speex". An example of the media representation in SDP for + offering a single channel of Speex at 8000 samples per second might + be: + + m=audio 8088 RTP/AVP 97 + a=rtpmap:97 speex/8000 + + Note that the RTP payload type code of 97 is defined in this media + definition to be 'mapped' to the speex codec at an 8kHz sampling + frequency using the 'a=rtpmap' line. Any number from 96 to 127 could + have been chosen (the allowed range for dynamic types). + + The value of the sampling frequency is typically 8000 for narrow band + operation, 16000 for wide band operation, and 32000 for ultra-wide + band operation. + + If for some reason the offerer has bandwidth limitations, the client + may use the "b=" header, as explained in SDP [4]. The following + example illustrates the case where the offerer cannot receive more + than 10 kbit/s. + + m=audio 8088 RTP/AVP 97 + b=AS:10 + a=rtmap:97 speex/8000 + + In this case, if the remote part agrees, it should configure its + Speex encoder so that it does not use modes that produce more than 10 + kbit/s. Note that the "b=" constraint also applies on all payload + types that may be proposed in the media line ("m="). + + An other way to make recommendations to the remote Speex encoder is + to use its specific parameters via the a=fmtp: directive. The + following parameters are defined for use in this way: + + ptime: duration of each packet in milliseconds. + + sr: actual sample rate in Hz. + + ebw: encoding bandwidth - either 'narrow' or 'wide' or 'ultra' + (corresponds to nominal 8000, 16000, and 32000 Hz sampling rates). + + vbr: variable bit rate - either 'on' 'off' or 'vad' (defaults + to off). If on, variable bit rate is enabled. If off, disabled. + If set to 'vad' then constant bit rate is used but silence will be + encoded with special short frames to indicate a lack of voice for + + + +Herlein, et al. Expires July 2, 2005 [Page 12] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + + that period. + + cng: comfort noise generation - either 'on' or 'off'. If off + then silence frames will be silent; if 'on' then those frames will + be filled with comfort noise. + + mode: Speex encoding mode. Can be {1,2,3,4,5,6,any} defaults to + 3 in narrowband, 6 in wide and ultra-wide. + + penh: use of perceptual enhancement. 1 indicates to the decoder + that perceptual enhancement is recommended, 0 indicates that it is + not. Defaults to on (1). + + + Examples: + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=fmtp:97 mode=4 + + This examples illustrate an offerer that wishes to receive a Speex + stream at 8000Hz, but only using speex mode 3. + + The offerer may suggest to the remote decoder to activate its + perceptual enhancement filter like this: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 penh=1 + + Several Speex specific parameters can be given in a single a=fmtp + line provided that they are separated by a semi-colon: + + a=fmtp:97 mode=any;penh=1 + + The offerer may indicate that it wishes to send variable bit rate + frames with comfort noise: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 vbr=on;cng=on + + The "ptime" attribute is used to denote the packetization interval + (ie, how many milliseconds of audio is encoded in a single RTP + packet). Since Speex uses 20 msec frames, ptime values of multiples + of 20 denote multiple Speex frames per packet. Values of ptime which + are not multiples of 20 MUST be ignored and clients MUST use the + default value of 20 instead. + + + +Herlein, et al. Expires July 2, 2005 [Page 13] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + + In the example below the ptime value is set to 40, indicating that + there are 2 frames in each packet. + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=ptime:40 + + Note that the ptime parameter applies to all payloads listed in the + media line and is not used as part of an a=fmtp directive. + + Values of ptime not multiple of 20 msec are meaningless, so the + receiver of such ptime values MUST ignore them. If during the life + of an RTP session the ptime value changes, when there are multiple + Speex frames for example, the SDP value must also reflect the new + value. + + Care must be taken when setting the value of ptime so that the RTP + packet size does not exceed the path MTU. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 14] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +10. ITU H.323/H.245 Use of Speex + + Application is underway to make Speex a standard ITU codec. However, + until that is finalized, Speex MAY be used in H.323 [5] by using a + non-standard codec block definition in the H.245 [6] codec capability + negotiations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 15] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +11. NonStandardMessage format + + For Speex use in H.245 [6] based systems, the fields in the + NonStandardMessage should be: + + t35CountryCode = Hex: B5 + t35Extension = Hex: 00 + manufacturerCode = Hex: 0026 + [Length of the Binary Sequence (8 bit number)] + [Binary Sequence consisting of an ASCII string, no NULL + terminator] + + The binary sequence is an ascii string merely for ease of use. The + string is not null terminated. The format of this string is + + speex [optional variables] + + The optional variables are identical to those used for the SDP a=fmtp + strings discussed in section 5 above. The string is built to be all + on one line, each key-value pair separated by a semi-colon. The + optional variables MAY be omitted, which causes the default values to + be assumed. They are: + + ebw=narrow;mode=3;vbr=off;cng=off;ptime=20;sr=8000;penh=no; + + The fifth octet of the block is the length of the binary sequence. + + NOTE: this method can result in the advertising of a large number of + Speex 'codecs' based on the number of variables possible. For most + VoIP applications, use of the default binary sequence of 'speex' is + RECOMMENDED to be used in addition to all other options. This + maximizes the chances that two H.323 based applications that support + Speex can find a mutual codec. + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 16] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +12. RTP Payload Types + + Dynamic payload type codes MUST be negotiated 'out-of-band' for the + assignment of a dynamic payload type from the range of 96-127. H.323 + applications MUST use the H.245 H2250LogicalChannelParameters + encoding to accomplish this. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 17] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +13. Security Considerations + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification [2], and any appropriate RTP profile. This implies + that confidentiality of the media streams is achieved by encryption. + Because the data compression used with this payload format is applied + end-to-end, encryption may be performed after compression so there is + no conflict between the two operations. + + A potential denial-of-service threat exists for data encodings using + compression techniques that have non-uniform receiver-end + computational load. The attacker can inject pathological datagrams + into the stream which are complex to decode and cause the receiver to + be overloaded. However, this encoding does not exhibit any + significant non-uniformity. + + As with any IP-based protocol, in some circumstances a receiver may + be overloaded simply by the receipt of too many packets, either + desired or undesired. Network-layer authentication may be used to + discard packets from undesired sources, but the processing cost of + the authentication itself may be too high. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 18] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +14. Acknowledgments + + The authors would like to thank Equivalence Pty Ltd of Australia for + their assistance in attempting to standardize the use of Speex in + H.323 applications, and for implementing Speex in their open source + OpenH323 stack. The authors would also like to thank Brian C. Wiles + of StreamComm for his assistance in developing + the proposed standard for Speex use in H.323 applications. + + The authors would also like to thank the following members of the + Speex and AVT communities for their input: Ross Finlayson, Federico + Montesino Pouzols, Henning Schulzrinne, Magnus Westerlund. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 19] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +15. References + +15.1 Normative References + + [1] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", RFC 2119. + + [2] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, + "RTP: A Transport Protocol for real-time applications", RFC + 3550. + + [3] "Multipurpose Internet Mail Extensions (MIME) Part One: Format + of Internet Message Bodies", RFC 2045. + + [4] Jacobson, V. and M. Handley, "SDP: Session Description + Protocol", RFC 2327. + + [5] "Packet-based Multimedia Communications Systems", ITU-T + Recommendation H.323. + + [6] "Control of communications between Visual Telephone Systems and + Terminal Equipment", ITU-T Recommendation H.245. + + [7] Schulzrinne, H. and S. Casner, "RTP Profile for Audio and Video + Conferences with Minimal Control.", RFC 3551. + + [8] Walleij, L., "The application/ogg Media Type", RFC 3534. + +15.2 Informative References + + [9] "Speexenc/speexdec, reference command-line encoder/decoder", + Speex website http://www.speex.org/. + + [10] "CELP, U.S. Federal Standard 1016.", National Technical + Information Service (NTIS) website http://www.ntis.gov/. + + +Authors' Addresses + + Greg Herlein + 2034 Filbert Street + San Francisco, California 94123 + United States + + EMail: gherlein@herlein.com + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 20] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + + Simon Morlat + 35, av de Vizille App 42 + Grenoble 38000 + France + + EMail: simon.morlat@linphone.org + + + Jean-Marc Valin + Department of Electrical and Computer Engineering + University of Sherbrooke + 2500 blvd Universite + Sherbrooke, Quebec J1K 2R1 + Canada + + EMail: jean-marc.valin@hermes.usherb.ca + + + Roger Hardiman + 49 Nettleton Road + Cheltenham, Gloucestershire GL51 6NR + England + + EMail: roger@freebsd.org + + + Phil Kerr + England + + EMail: phil@plus24.com + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires July 2, 2005 [Page 21] + +Internet-Draft draft-herlein-speex-rtp-profile-03 January 2005 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + +Disclaimer of Validity + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Copyright Statement + + Copyright (C) The Internet Society (2005). This document is subject + to the rights, licenses and restrictions contained in BCP 78, and + except as set forth therein, the authors retain all their rights. + + +Acknowledgment + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + +Herlein, et al. Expires July 2, 2005 [Page 22] + diff --git a/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-03.xml b/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-03.xml new file mode 100644 index 0000000..709efcd --- /dev/null +++ b/native/codec/libraries/speex/doc/draft-herlein-speex-rtp-profile-03.xml @@ -0,0 +1,815 @@ + + + + + + + +draft-herlein-speex-rtp-profile-03 + + + +
    +gherlein@herlein.com + +2034 Filbert Street +San Francisco +California +94123 +United States + +
    +
    + + +
    +simon.morlat@linphone.org + +35, av de Vizille App 42 +Grenoble +38000 +France + +
    +
    + + +
    +jean-marc.valin@hermes.usherb.ca + +Department of Electrical and Computer Engineering +University of Sherbrooke +2500 blvd Universite +Sherbrooke +Quebec +J1K 2R1 +Canada + +
    +
    + + +
    +roger@freebsd.org + +49 Nettleton Road +Cheltenham +Gloucestershire +GL51 6NR +England + +
    +
    + + + +
    +phil@plus24.com + +England + +
    +
    + + + +General +AVT Working Group +I-D + +Internet-Draft +Speex +RTP + + +Speex is an open-source voice codec suitable for use in Voice over +IP (VoIP) type applications. This document describes the payload +format for Speex generated bit streams within an RTP packet. Also +included here are the necessary details for the use of Speex with +the Session Description Protocol (SDP) and a preliminary method of +using Speex within H.323 applications. + + +
    + + + +
    + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this +document are to be interpreted as described in RFC 2119 . + +
    + +
    + + +Speex is based on the CELP encoding technique with support for +either narrowband (nominal 8kHz), wideband (nominal 16kHz) or +ultra-wideband (nominal 32kHz), and (non-optimal) rates up to 48 kHz +sampling also available. The main characteristics can be summarized +as follows: + + + + +Free software/open-source +Integration of wideband and narrowband in the same bit-stream +Wide range of bit-rates available +Dynamic bit-rate switching and variable bit-rate (VBR) +Voice Activity Detection (VAD, integrated with VBR) +Variable complexity + + + +
    + +
    + + +For RTP based transportation of Speex encoded audio the standard +RTP header [2] is followed by one or more payload data blocks. +An optional padding terminator may also be used. + + + +
    + +
    + + + + +The RTP header begins with an octet of fields (V, P, X, and CC) to +support specialized RTP uses (see and for details). For +Speex the following values are used. + + +Version (V): 2 bits + This field identifies the version of RTP. The version + used by this specification is two . + + +Padding (P): 1 bit + If the padding bit is set, the packet contains one or more + additional padding octets at the end which are not part of + the payload. P is set if the total packet size is less than + the MTU. + + +Extension (X): 1 bit + If the extension, X, bit is set, the fixed header MUST be + followed by exactly one header extension, with a format defined + in Section 5.3.1. of . + + +CSRC count (CC): 4 bits + The CSRC count contains the number of CSRC identifiers. + + +Marker (M): 1 bit + The M bit indicates if the packet contains comfort noise. This + field is used in conjunction with the cng SDP attribute and is + detailed further in section 5 below. In normal usage this bit + is set if the packet contains comfort noise. + + +Payload Type (PT): 7 bits + An RTP profile for a class of applications is expected to assign + a payload type for this format, or a dynamically allocated + payload type SHOULD be chosen which designates the payload as + Speex. + + +Sequence number: 16 bits + The sequence number increments by one for each RTP data packet + sent, and may be used by the receiver to detect packet loss and + to restore packet sequence. This field is detailed further in + . + + +Timestamp: 32 bits + A timestamp representing the sampling time of the first sample of + the first Speex packet in the RTP packet. The clock frequency + MUST be set to the sample rate of the encoded audio data. + + Speex uses 20 msec frames and a variable sampling rate clock. + The RTP timestamp MUST be in units of 1/X of a second where X + is the sample rate used. Speex uses a nominal 8kHz sampling rate + for narrowband use, a nominal 16kHz sampling rate for wideband use, + and a nominal 32kHz sampling rate for ultra-wideband use. + + +SSRC/CSRC identifiers: + These two fields, 32 bits each with one SSRC field and a maximum + of 16 CSRC fields, are as defined in . + + +
    + +
    + + +For the purposes of packetizing the bit stream in RTP, it is only +necessary to consider the sequence of bits as output by the Speex +encoder , and present the same sequence to the decoder. The +payload format described here maintains this sequence. + + + +A typical Speex frame, encoded at the maximum bitrate, is approx. +110 octets and the total number of Speex frames SHOULD be kept +less than the path MTU to prevent fragmentation. Speex frames MUST +NOT be fragmented across multiple RTP packets, + + + +An RTP packet MAY contain Speex frames of the same bit rate or of +varying bit rates, since the bit-rate for a frame is conveyed in +band with the signal. + + + +The encoding and decoding algorithm can change the bit rate at any +20 msec frame boundary, with the bit rate change notification provided +in-band with the bit stream. Each frame contains both "mode" +(narrowband, wideband or ultra-wideband) and "sub-mode" (bit-rate) +information in the bit stream. No out-of-band notification is +required for the decoder to process changes in the bit rate sent +by the encoder. + + + +It is RECOMMENDED that values of 8000, 16000 and 32000 be used +for normal internet telephony applications, though the sample +rate is supported at rates as low as 6000 Hz and as high as +48 kHz. + + + +The RTP payload MUST be padded to provide an integer number of +octets as the payload length. These padding bits are LSB aligned +in network octet order and consist of a 0 followed by all ones +(until the end of the octet). This padding is only required for +the last frame in the packet, and only to ensure the packet +contents ends on an octet boundary. + + +
    + +
    + + +In the example below we have a single Speex frame with 5 bits +of padding to ensure the packet size falls on an octet boundary. + + + + +
    + +
    + + +Below is an example of two Speex frames contained within one RTP +packet. The Speex frame length in this example fall on an octet +boundary so there is no padding. + + + +Speex codecs are able to detect the the bitrate from the +payload and are responsible for detecting the 20 msec boundaries +between each frame. + + + + +
    + +
    + + +Full definition of the MIME type for Speex will be part of the Ogg +Vorbis MIME type definition application . + + +MIME media type name: audio + +MIME subtype: speex + +Optional parameters: + +Required parameters: to be included in the Ogg MIME specification. + +Encoding considerations: + +Security Considerations: +See Section 6 of RFC 3047. + +Interoperability considerations: none + +Published specification: + +Applications which use this media type: + +Additional information: none + +Person & email address to contact for further information: + +Greg Herlein <gherlein@herlein.com> +Jean-Marc Valin <jean-marc.valin@hermes.usherb.ca> + + + +Intended usage: COMMON + +Author/Change controller: + + + +Author: Greg Herlein <gherlein@herlein.com> +Change controller: Greg Herlein <gherlein@herlein.com> +Change controller: IETF AVT Working Group + + + + +This transport type signifies that the content is to be interpreted +according to this document if the contents are transmitted over RTP. +Should this transport type appear over a lossless streaming protocol +such as TCP, the content encapsulation should be interpreted as an +Ogg Stream in accordance with , with the exception that the +content of the Ogg Stream may be assumed to be Speex audio and +Speex audio only. + + +
    + +
    + + +When conveying information by SDP , the encoding name MUST be +set to "speex". An example of the media representation in SDP for +offering a single channel of Speex at 8000 samples per second might +be: + + + + +m=audio 8088 RTP/AVP 97 +a=rtpmap:97 speex/8000 + + + +Note that the RTP payload type code of 97 is defined in this media +definition to be 'mapped' to the speex codec at an 8kHz sampling +frequency using the 'a=rtpmap' line. Any number from 96 to 127 +could have been chosen (the allowed range for dynamic types). + + + +The value of the sampling frequency is typically 8000 for narrow band +operation, 16000 for wide band operation, and 32000 for ultra-wide +band operation. + + + +If for some reason the offerer has bandwidth limitations, the client +may use the "b=" header, as explained in SDP . The following example +illustrates the case where the offerer cannot receive more than +10 kbit/s. + + + + +m=audio 8088 RTP/AVP 97 +b=AS:10 +a=rtmap:97 speex/8000 + + + +In this case, if the remote part agrees, it should configure its +Speex encoder so that it does not use modes that produce more than +10 kbit/s. Note that the "b=" constraint also applies on all +payload types that may be proposed in the media line ("m="). + + + +An other way to make recommendations to the remote Speex encoder +is to use its specific parameters via the a=fmtp: directive. The +following parameters are defined for use in this way: + + + + +ptime: duration of each packet in milliseconds. + +sr: actual sample rate in Hz. + +ebw: encoding bandwidth - either 'narrow' or 'wide' or + 'ultra' (corresponds to nominal 8000, 16000, and + 32000 Hz sampling rates). + +vbr: variable bit rate - either 'on' 'off' or 'vad' + (defaults to off). If on, variable bit rate is + enabled. If off, disabled. If set to 'vad' then + constant bit rate is used but silence will be encoded + with special short frames to indicate a lack of voice + for that period. + +cng: comfort noise generation - either 'on' or 'off'. If + off then silence frames will be silent; if 'on' then + those frames will be filled with comfort noise. + +mode: Speex encoding mode. Can be {1,2,3,4,5,6,any} + defaults to 3 in narrowband, 6 in wide and ultra-wide. + +penh: use of perceptual enhancement. 1 indicates + to the decoder that perceptual enhancement is recommended, + 0 indicates that it is not. Defaults to on (1). + + +Examples: + + + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=fmtp:97 mode=4 + + + +This examples illustrate an offerer that wishes to receive +a Speex stream at 8000Hz, but only using speex mode 3. + + + +The offerer may suggest to the remote decoder to activate +its perceptual enhancement filter like this: + + + + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 penh=1 + + + +Several Speex specific parameters can be given in a single +a=fmtp line provided that they are separated by a semi-colon: + + + + + a=fmtp:97 mode=any;penh=1 + + + +The offerer may indicate that it wishes to send variable bit rate +frames with comfort noise: + + + + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 vbr=on;cng=on + + + +The "ptime" attribute is used to denote the packetization +interval (ie, how many milliseconds of audio is encoded in a +single RTP packet). Since Speex uses 20 msec frames, ptime values +of multiples of 20 denote multiple Speex frames per packet. +Values of ptime which are not multiples of 20 MUST be ignored +and clients MUST use the default value of 20 instead. + + + +In the example below the ptime value is set to 40, indicating that +there are 2 frames in each packet. + + + + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=ptime:40 + + + +Note that the ptime parameter applies to all payloads listed +in the media line and is not used as part of an a=fmtp directive. + + + +Values of ptime not multiple of 20 msec are meaningless, so the +receiver of such ptime values MUST ignore them. If during the +life of an RTP session the ptime value changes, when there are +multiple Speex frames for example, the SDP value must also reflect +the new value. + + + +Care must be taken when setting the value of ptime so that the +RTP packet size does not exceed the path MTU. + + +
    +
    + + +Application is underway to make Speex a standard ITU codec. +However, until that is finalized, Speex MAY be used in H.323 by +using a non-standard codec block definition in the H.245 codec +capability negotiations. + + +
    + +
    + + +For Speex use in H.245 based systems, the fields in the +NonStandardMessage should be: + + + + +t35CountryCode = Hex: B5 +t35Extension = Hex: 00 +manufacturerCode = Hex: 0026 +[Length of the Binary Sequence (8 bit number)] +[Binary Sequence consisting of an ASCII string, no NULL terminator] + + + +The binary sequence is an ascii string merely for ease of use. +The string is not null terminated. The format of this string is + + + + +speex [optional variables] + + + +The optional variables are identical to those used for the SDP +a=fmtp strings discussed in section 5 above. The string is built +to be all on one line, each key-value pair separated by a +semi-colon. The optional variables MAY be omitted, which causes +the default values to be assumed. They are: + + + + +ebw=narrow;mode=3;vbr=off;cng=off;ptime=20;sr=8000;penh=no; + + + +The fifth octet of the block is the length of the binary sequence. + + + +NOTE: this method can result in the advertising of a large number +of Speex 'codecs' based on the number of variables possible. For +most VoIP applications, use of the default binary sequence of +'speex' is RECOMMENDED to be used in addition to all other options. +This maximizes the chances that two H.323 based applications that +support Speex can find a mutual codec. + + +
    + +
    + + +Dynamic payload type codes MUST be negotiated 'out-of-band' +for the assignment of a dynamic payload type from the +range of 96-127. H.323 applications MUST use the H.245 +H2250LogicalChannelParameters encoding to accomplish this. + + +
    + +
    + + +RTP packets using the payload format defined in this specification +are subject to the security considerations discussed in the RTP +specification , and any appropriate RTP profile. This implies +that confidentiality of the media streams is achieved by encryption. +Because the data compression used with this payload format is applied +end-to-end, encryption may be performed after compression so there is +no conflict between the two operations. + + + +A potential denial-of-service threat exists for data encodings using +compression techniques that have non-uniform receiver-end +computational load. The attacker can inject pathological datagrams +into the stream which are complex to decode and cause the receiver to +be overloaded. However, this encoding does not exhibit any +significant non-uniformity. + + + +As with any IP-based protocol, in some circumstances a receiver may +be overloaded simply by the receipt of too many packets, either +desired or undesired. Network-layer authentication may be used to +discard packets from undesired sources, but the processing cost of +the authentication itself may be too high. + + +
    + +
    + + +The authors would like to thank Equivalence Pty Ltd of Australia +for their assistance in attempting to standardize the use of Speex +in H.323 applications, and for implementing Speex in their open +source OpenH323 stack. The authors would also like to thank Brian +C. Wiles <brian@streamcomm.com> of StreamComm for his assistance in +developing the proposed standard for Speex use in H.323 +applications. + + + +The authors would also like to thank the following members of the +Speex and AVT communities for their input: Ross Finlayson, +Federico Montesino Pouzols, Henning Schulzrinne, Magnus Westerlund. + +
    + +
    + + + + + + + +Key words for use in RFCs to Indicate Requirement Levels + + + + + + + +RTP: A Transport Protocol for real-time applications + + + + + + + + + + +Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies + + + + + + + + +SDP: Session Description Protocol + + + + + + + + + +Packet-based Multimedia Communications Systems + + + + + + + + +Control of communications between Visual Telephone Systems and Terminal Equipment + + + + + + + + +RTP Profile for Audio and Video Conferences with Minimal Control. + + + + + + + + + +The application/ogg Media Type + + + + + + + + + + + + +Speexenc/speexdec, reference command-line encoder/decoder + + + + + + +CELP, U.S. Federal Standard 1016. + + + + + + + + +
    diff --git a/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-00.txt b/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-00.txt new file mode 100644 index 0000000..53facab --- /dev/null +++ b/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-00.txt @@ -0,0 +1,784 @@ + + + +AVT Working Group G. Herlein +Internet-Draft S. Morlat +Expires: April 15, 2006 J. Jean-Marc + R. Hardiman + P. Kerr + October 12, 2005 + + + draft-ietf-avt-rtp-speex-00 + RTP Payload Format for the Speex Codec + +Status of this Memo + + By submitting this Internet-Draft, each author represents that any + applicable patent or other IPR claims of which he or she is aware + have been or will be disclosed, and any of which he or she becomes + aware will be disclosed, in accordance with Section 6 of BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on April 15, 2006. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + Speex is an open-source voice codec suitable for use in Voice over IP + (VoIP) type applications. This document describes the payload format + for Speex generated bit streams within an RTP packet. Also included + here are the necessary details for the use of Speex with the Session + Description Protocol (SDP). + + + + +Herlein, et al. Expires April 15, 2006 [Page 1] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + +Editors Note + + All references to RFC XXXX are to be replaced by references to the + RFC number of this memo, when published. + +Table of Contents + + 1. Conventions used in this document . . . . . . . . . . . . . 3 + 2. Overview of the Speex Codec . . . . . . . . . . . . . . . . 3 + 3. RTP payload format for Speex . . . . . . . . . . . . . . . . 3 + 4. RTP Header . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 5. Speex payload . . . . . . . . . . . . . . . . . . . . . . . 5 + 6. Example Speex packet . . . . . . . . . . . . . . . . . . . . 6 + 7. Multiple Speex frames in a RTP packet . . . . . . . . . . . 6 + 8. MIME registration of Speex . . . . . . . . . . . . . . . . . 7 + 9. SDP usage of Speex . . . . . . . . . . . . . . . . . . . . . 8 + 10. ITU H.323 Use of Speex . . . . . . . . . . . . . . . . . . . 10 + 11. Security Considerations . . . . . . . . . . . . . . . . . . 10 + 12. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . 11 + 13. References . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 13.1 Normative References . . . . . . . . . . . . . . . . . . 11 + 13.2 Informative References . . . . . . . . . . . . . . . . . 12 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 12 + Intellectual Property and Copyright Statements . . . . . . . 14 + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires April 15, 2006 [Page 2] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + +1. Conventions used in this document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [1]. + +2. Overview of the Speex Codec + + Speex is based on the CELP [8] encoding technique with support for + either narrowband (nominal 8kHz), wideband (nominal 16kHz) or ultra- + wideband (nominal 32kHz), and (non-optimal) rates up to 48 kHz + sampling also available. The main characteristics can be summarized + as follows: + + o Free software/open-source + o Integration of wideband and narrowband in the same bit-stream + o Wide range of bit-rates available + o Dynamic bit-rate switching and variable bit-rate (VBR) + o Voice Activity Detection (VAD, integrated with VBR) + o Variable complexity + +3. RTP payload format for Speex + + For RTP based transportation of Speex encoded audio the standard RTP + header [2] is followed by one or more payload data blocks. An + optional padding terminator may also be used. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | one or more frames of Speex .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | one or more frames of Speex .... | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +4. RTP Header + + + + + + + + + + + + +Herlein, et al. Expires April 15, 2006 [Page 3] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The RTP header begins with an octet of fields (V, P, X, and CC) to + support specialized RTP uses (see [2] and [5] for details). For + Speex the following values are used. + + Version (V): 2 bits + + This field identifies the version of RTP. The version used by this + specification is two [2]. + + Padding (P): 1 bit + + If the padding bit is set, the packet contains one or more additional + padding octets at the end which are not part of the payload. + + Extension (X): 1 bit + + If the extension, X, bit is set, the fixed header MUST be followed by + exactly one header extension, with a format defined in Section 5.3.1. + of [2]. + + CSRC count (CC): 4 bits + + The CSRC count contains the number of CSRC identifiers. + + Marker (M): 1 bit + + The M bit indicates if the packet contains comfort noise. This field + is used in conjunction with the cng SDP attribute and conforms to + Section 4.1. of [5]. + + Payload Type (PT): 7 bits + + An RTP profile for a class of applications is expected to assign a + payload type for this format, or a dynamically allocated payload type + SHOULD be chosen which designates the payload as Speex. + + + +Herlein, et al. Expires April 15, 2006 [Page 4] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + Sequence number: 16 bits + + The sequence number increments by one for each RTP data packet sent, + and may be used by the receiver to detect packet loss and to restore + packet sequence. This field is detailed further in [2]. + + Timestamp: 32 bits + + A timestamp representing the sampling time of the first sample of the + first Speex packet in the RTP packet. The clock frequency MUST be + set to the sample rate of the encoded audio data. Speex uses 20 msec + frames and a variable sampling rate clock. The RTP timestamp MUST be + in units of 1/X of a second where X is the sample rate used. Speex + uses a nominal 8kHz sampling rate for narrowband use, a nominal 16kHz + sampling rate for wideband use, and a nominal 32kHz sampling rate for + ultra-wideband use. + + SSRC/CSRC identifiers: + + These two fields, 32 bits each with one SSRC field and a maximum of + 16 CSRC fields, are as defined in [2]. + +5. Speex payload + + For the purposes of packetizing the bit stream in RTP, it is only + necessary to consider the sequence of bits as output by the Speex + encoder [7], and present the same sequence to the decoder. The + payload format described here maintains this sequence. + + A typical Speex frame, encoded at the maximum bitrate, is approx. 110 + octets and the total number of Speex frames SHOULD be kept less than + the path MTU to prevent fragmentation. Speex frames MUST NOT be + fragmented across multiple RTP packets, + + An RTP packet MAY contain Speex frames of the same bit rate or of + varying bit rates, since the bit-rate for a frame is conveyed in band + with the signal. + + The encoding and decoding algorithm can change the bit rate at any 20 + msec frame boundary, with the bit rate change notification provided + in-band with the bit stream. Each frame contains both "mode" + (narrowband, wideband or ultra-wideband) and "sub-mode" (bit-rate) + information in the bit stream. No out-of-band notification is + required for the decoder to process changes in the bit rate sent by + the encoder. + + It is RECOMMENDED that values of 8000, 16000 and 32000 be used for + normal internet telephony applications, though the sample rate is + + + +Herlein, et al. Expires April 15, 2006 [Page 5] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + supported at rates as low as 6000 Hz and as high as 48 kHz. + + The RTP payload MUST be padded to provide an integer number of octets + as the payload length. These padding bits are LSB aligned in network + octet order and consist of a 0 followed by all ones (until the end of + the octet). This padding is only required for the last frame in the + packet, and only to ensure the packet contents ends on an octet + boundary. + +6. Example Speex packet + + In the example below we have a single Speex frame with 5 bits of + padding to ensure the packet size falls on an octet boundary. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. |0 1 1 1 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +7. Multiple Speex frames in a RTP packet + + Below is an example of two Speex frames contained within one RTP + packet. The Speex frame length in this example fall on an octet + boundary so there is no padding. + + Speex codecs [7] are able to detect the bitrate from the payload and + are responsible for detecting the 20 msec boundaries between each + frame. + + + + + +Herlein, et al. Expires April 15, 2006 [Page 6] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +8. MIME registration of Speex + + Full definition of the MIME [3] type for Speex will be part of the + Ogg Vorbis MIME type definition application [6]. + + MIME media type name: audio + + MIME subtype: speex + + Optional parameters: + + Required parameters: to be included in the Ogg MIME specification. + + Encoding considerations: + + This type is only defined for transfer via HTTP as specified in RFC + XXXX. + + Security Considerations: + + See Section 6 of RFC 3047. + + Interoperability considerations: none + + Published specification: + + Applications which use this media type: + + + +Herlein, et al. Expires April 15, 2006 [Page 7] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + Additional information: none + + Person & email address to contact for further information: + + Greg Herlein + Jean-Marc Valin + + Intended usage: COMMON + + Author/Change controller: + + Author: Greg Herlein + Change controller: Greg Herlein + Change controller: IETF AVT Working Group + + This transport type signifies that the content is to be interpreted + according to this document if the contents are transmitted over RTP. + Should this transport type appear over a lossless streaming protocol + such as TCP, the content encapsulation should be interpreted as an + Ogg Stream in accordance with [6], with the exception that the + content of the Ogg Stream may be assumed to be Speex audio and Speex + audio only. + +9. SDP usage of Speex + + When conveying information by SDP [4], the encoding name MUST be set + to "speex". An example of the media representation in SDP for + offering a single channel of Speex at 8000 samples per second might + be: + + m=audio 8088 RTP/AVP 97 + a=rtpmap:97 speex/8000 + + Note that the RTP payload type code of 97 is defined in this media + definition to be 'mapped' to the speex codec at an 8kHz sampling + frequency using the 'a=rtpmap' line. Any number from 96 to 127 could + have been chosen (the allowed range for dynamic types). + + The value of the sampling frequency is typically 8000 for narrow band + operation, 16000 for wide band operation, and 32000 for ultra-wide + band operation. + + If for some reason the offerer has bandwidth limitations, the client + may use the "b=" header, as explained in SDP [4]. The following + example illustrates the case where the offerer cannot receive more + than 10 kbit/s. + + + + + +Herlein, et al. Expires April 15, 2006 [Page 8] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + m=audio 8088 RTP/AVP 97 + b=AS:10 + a=rtmap:97 speex/8000 + + In this case, if the remote part agrees, it should configure its + Speex encoder so that it does not use modes that produce more than 10 + kbit/s. Note that the "b=" constraint also applies on all payload + types that may be proposed in the media line ("m="). + + An other way to make recommendations to the remote Speex encoder is + to use its specific parameters via the a=fmtp: directive. The + following parameters are defined for use in this way: + + ptime: duration of each packet in milliseconds. + + sr: actual sample rate in Hz. + + ebw: encoding bandwidth - either 'narrow' or 'wide' or 'ultra' + (corresponds to nominal 8000, 16000, and 32000 Hz sampling rates). + + vbr: variable bit rate - either 'on' 'off' or 'vad' (defaults + to off). If on, variable bit rate is enabled. If off, disabled. + If set to 'vad' then constant bit rate is used but silence will be + encoded with special short frames to indicate a lack of voice for + that period. + + cng: comfort noise generation - either 'on' or 'off'. If off + then silence frames will be silent; if 'on' then those frames will + be filled with comfort noise. + + mode: Speex encoding mode. Can be {1,2,3,4,5,6,any} defaults to + 3 in narrowband, 6 in wide and ultra-wide. + + + Examples: + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=fmtp:97 mode=4 + + This examples illustrate an offerer that wishes to receive a Speex + stream at 8000Hz, but only using speex mode 4. + + Several Speex specific parameters can be given in a single a=fmtp + line provided that they are separated by a semi-colon: + + + + + + +Herlein, et al. Expires April 15, 2006 [Page 9] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + a=fmtp:97 mode=any;mode=1 + + The offerer may indicate that it wishes to send variable bit rate + frames with comfort noise: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 vbr=on;cng=on + + The "ptime" attribute is used to denote the packetization interval + (ie, how many milliseconds of audio is encoded in a single RTP + packet). Since Speex uses 20 msec frames, ptime values of multiples + of 20 denote multiple Speex frames per packet. Values of ptime which + are not multiples of 20 MUST be ignored and clients MUST use the + default value of 20 instead. + + In the example below the ptime value is set to 40, indicating that + there are 2 frames in each packet. + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=ptime:40 + + Note that the ptime parameter applies to all payloads listed in the + media line and is not used as part of an a=fmtp directive. + + Values of ptime not multiple of 20 msec are meaningless, so the + receiver of such ptime values MUST ignore them. If during the life + of an RTP session the ptime value changes, when there are multiple + Speex frames for example, the SDP value must also reflect the new + value. + + Care must be taken when setting the value of ptime so that the RTP + packet size does not exceed the path MTU. + +10. ITU H.323 Use of Speex + + It is outside the scope of this document to cover the use of Speex + and H.323, more details may be found on the Speex website [9]. + +11. Security Considerations + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification [2], and any appropriate RTP profile. This implies + that confidentiality of the media streams is achieved by encryption. + Because the data compression used with this payload format is applied + end-to-end, encryption may be performed after compression so there is + + + +Herlein, et al. Expires April 15, 2006 [Page 10] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + no conflict between the two operations. + + A potential denial-of-service threat exists for data encodings using + compression techniques that have non-uniform receiver-end + computational load. The attacker can inject pathological datagrams + into the stream which are complex to decode and cause the receiver to + be overloaded. However, this encoding does not exhibit any + significant non-uniformity. + + As with any IP-based protocol, in some circumstances a receiver may + be overloaded simply by the receipt of too many packets, either + desired or undesired. Network-layer authentication may be used to + discard packets from undesired sources, but the processing cost of + the authentication itself may be too high. + +12. Acknowledgments + + The authors would like to thank Equivalence Pty Ltd of Australia for + their assistance in attempting to standardize the use of Speex in + H.323 applications, and for implementing Speex in their open source + OpenH323 stack. The authors would also like to thank Brian C. Wiles + of StreamComm for his assistance in developing + the proposed standard for Speex use in H.323 applications. + + The authors would also like to thank the following members of the + Speex and AVT communities for their input: Ross Finlayson, Federico + Montesino Pouzols, Henning Schulzrinne, Magnus Westerlund. + +13. References + +13.1 Normative References + + [1] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", RFC 2119. + + [2] Schulzrinne, H., Casner, S., Frederick, R., and V. Jacobson, + "RTP: A Transport Protocol for real-time applications", + RFC 3550. + + [3] "Multipurpose Internet Mail Extensions (MIME) Part One: Format + of Internet Message Bodies", RFC 2045. + + [4] Jacobson, V. and M. Handley, "SDP: Session Description + Protocol", RFC 2327. + + [5] Schulzrinne, H. and S. Casner, "RTP Profile for Audio and Video + Conferences with Minimal Control.", RFC 3551. + + + + +Herlein, et al. Expires April 15, 2006 [Page 11] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + [6] Walleij, L., "The application/ogg Media Type", RFC 3534. + +13.2 Informative References + + [7] "Speexenc/speexdec, reference command-line encoder/decoder", + Speex website http://www.speex.org/. + + [8] "CELP, U.S. Federal Standard 1016.", National Technical + Information Service (NTIS) website http://www.ntis.gov/. + + [9] "ITU H.323/H.245 Use of Speex", Speex + website http://www.speex.org/itu/. + + +Authors' Addresses + + Greg Herlein + 2034 Filbert Street + San Francisco, California 94123 + United States + + Email: gherlein@herlein.com + + + Simon Morlat + 35, av de Vizille App 42 + Grenoble 38000 + France + + Email: simon.morlat@linphone.org + + + Jean-Marc Valin + Department of Electrical and Computer Engineering + University of Sherbrooke + 2500 blvd Universite + Sherbrooke, Quebec J1K 2R1 + Canada + + Email: jean-marc.valin@usherbrooke.ca + + + + + + + + + + + +Herlein, et al. Expires April 15, 2006 [Page 12] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + + Roger Hardiman + 49 Nettleton Road + Cheltenham, Gloucestershire GL51 6NR + England + + Email: roger@freebsd.org + + + Phil Kerr + England + + Email: phil@plus24.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires April 15, 2006 [Page 13] + +Internet-Draft draft-ietf-avt-rtp-speex-00 October 2005 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + +Disclaimer of Validity + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Copyright Statement + + Copyright (C) The Internet Society (2005). This document is subject + to the rights, licenses and restrictions contained in BCP 78, and + except as set forth therein, the authors retain all their rights. + + +Acknowledgment + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + +Herlein, et al. Expires April 15, 2006 [Page 14] + diff --git a/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-01-tmp.txt b/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-01-tmp.txt new file mode 100644 index 0000000..1410b85 --- /dev/null +++ b/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-01-tmp.txt @@ -0,0 +1,1008 @@ + + + +AVT G. Herlein +Internet-Draft +Intended status: Standards Track J. Valin +Expires: October 24, 2007 University of Sherbrooke + A. Heggestad + April 22, 2007 + + + RTP Payload Format for the Speex Codec + draft-ietf-avt-rtp-speex-01 (non-final) + +Status of this Memo + + By submitting this Internet-Draft, each author represents that any + applicable patent or other IPR claims of which he or she is aware + have been or will be disclosed, and any of which he or she becomes + aware will be disclosed, in accordance with Section 6 of BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on October 24, 2007. + +Copyright Notice + + Copyright (C) The Internet Society (2007). + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 1] + +Internet-Draft Speex April 2007 + + +Abstract + + Speex is an open-source voice codec suitable for use in Voice over IP + (VoIP) type applications. This document describes the payload format + for Speex generated bit streams within an RTP packet. Also included + here are the necessary details for the use of Speex with the Session + Description Protocol (SDP). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 2] + +Internet-Draft Speex April 2007 + + +Editors Note + + All references to RFC XXXX are to be replaced by references to the + RFC number of this memo, when published. + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 3. RTP usage for Speex . . . . . . . . . . . . . . . . . . . . . 6 + 3.1. RTP Speex Header Fields . . . . . . . . . . . . . . . . . 6 + 3.2. RTP payload format for Speex . . . . . . . . . . . . . . . 6 + 3.3. Speex payload . . . . . . . . . . . . . . . . . . . . . . 6 + 3.4. Example Speex packet . . . . . . . . . . . . . . . . . . . 7 + 3.5. Multiple Speex frames in a RTP packet . . . . . . . . . . 7 + 4. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 9 + 4.1. Media Type Registration . . . . . . . . . . . . . . . . . 9 + 4.1.1. Registration of media type audio/speex . . . . . . . . 9 + 5. SDP usage of Speex . . . . . . . . . . . . . . . . . . . . . . 11 + 6. Security Considerations . . . . . . . . . . . . . . . . . . . 14 + 7. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 15 + 8. References . . . . . . . . . . . . . . . . . . . . . . . . . . 16 + 8.1. Normative References . . . . . . . . . . . . . . . . . . . 16 + 8.2. Informative References . . . . . . . . . . . . . . . . . . 16 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 17 + Intellectual Property and Copyright Statements . . . . . . . . . . 18 + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 3] + +Internet-Draft Speex April 2007 + + +1. Introduction + + Speex is based on the CELP [CELP] encoding technique with support for + either narrowband (nominal 8kHz), wideband (nominal 16kHz) or ultra- + wideband (nominal 32kHz). The main characteristics can be summarized + as follows: + + o Free software/open-source + + o Integration of wideband and narrowband in the same bit-stream + + o Wide range of bit-rates available + + o Dynamic bit-rate switching and variable bit-rate (VBR) + + o Voice Activity Detection (VAD, integrated with VBR) + + o Variable complexity + + To be compliant with this specification, implementations MUST support + 8 kHz sampling rate (narrowband)" and SHOULD support 8 kbps bitrate. + The sampling rate MUST be 8, 16 or 32 kHz. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 4] + +Internet-Draft Speex April 2007 + + +2. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC2119 [RFC2119] and + indicate requirement levels for compliant RTP implementations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 5] + +Internet-Draft Speex April 2007 + + +3. RTP usage for Speex + +3.1. RTP Speex Header Fields + + The RTP header is defined in the RTP specification [RFC3550]. This + section defines how fields in the RTP header are used. + + Payload Type (PT): The assignment of an RTP payload type for this + packet format is outside the scope of this document; it is + specified by the RTP profile under which this payload format is + used, or signaled dynamically out-of-band (e.g., using SDP). + + Marker (M) bit: The M bit is set to one to indicate that the RTP + packet payload contains at least one complete frame + + Extension (X) bit: Defined by the RTP profile used. + + Timestamp: A 32-bit word that corresponds to the sampling instant + for the first frame in the RTP packet. + +3.2. RTP payload format for Speex + + The RTP payload for Speex has the format shown in Figure 1. No + additional header fields specific to this payload format are + required. For RTP based transportation of Speex encoded audio the + standard RTP header [RFC3550] is followed by one or more payload data + blocks. An optional padding terminator may also be used. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | one or more frames of Speex .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | one or more frames of Speex .... | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 1: RTP payload for Speex + +3.3. Speex payload + + For the purposes of packetizing the bit stream in RTP, it is only + necessary to consider the sequence of bits as output by the Speex + encoder [speexenc], and present the same sequence to the decoder. + The payload format described here maintains this sequence. + + A typical Speex frame, encoded at the maximum bitrate, is approx. 110 + + + +Herlein, et al. Expires October 24, 2007 [Page 6] + +Internet-Draft Speex April 2007 + + + octets and the total number of Speex frames SHOULD be kept less than + the path MTU to prevent fragmentation. Speex frames MUST NOT be + fragmented across multiple RTP packets, + + An RTP packet MAY contain Speex frames of the same bit rate or of + varying bit rates, since the bit-rate for a frame is conveyed in band + with the signal. + + The encoding and decoding algorithm can change the bit rate at any 20 + msec frame boundary, with the bit rate change notification provided + in-band with the bit stream. Each frame contains both "mode" + (narrowband, wideband or ultra-wideband) and "sub-mode" (bit-rate) + information in the bit stream. No out-of-band notification is + required for the decoder to process changes in the bit rate sent by + the encoder. + + Sampling rate values of 8000, 16000 or 32000 Hz MUST be used. Any + other sampling rates MUST NOT be used. + + The RTP payload MUST be padded to provide an integer number of octets + as the payload length. These padding bits are LSB aligned in network + octet order and consist of a 0 followed by all ones (until the end of + the octet). This padding is only required for the last frame in the + packet, and only to ensure the packet contents ends on an octet + boundary. + +3.4. Example Speex packet + + In the example below we have a single Speex frame with 5 bits of + padding to ensure the packet size falls on an octet boundary. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. |0 1 1 1 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +3.5. Multiple Speex frames in a RTP packet + + Below is an example of two Speex frames contained within one RTP + packet. The Speex frame length in this example fall on an octet + boundary so there is no padding. + + Speex codecs [speexenc] are able to detect the bitrate from the + + + +Herlein, et al. Expires October 24, 2007 [Page 7] + +Internet-Draft Speex April 2007 + + + payload and are responsible for detecting the 20 msec boundaries + between each frame. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | ..speex frame 1.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex frame 1.. | ..speex frame 2.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex frame 2.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 8] + +Internet-Draft Speex April 2007 + + +4. IANA Considerations + + This document defines the Speex media type. + +4.1. Media Type Registration + + This section describes the media types and names associated with this + payload format. The section registers the media types, as per + RFC4288 [RFC4288] + +4.1.1. Registration of media type audio/speex + + Media type name: audio + + Media subtype name: speex + + Required parameters: + + None + + Optional parameters: + + ptime: see RFC 4566. SHOULD be a multiple of 20 msec. + + maxptime: see RFC 4566. SHOULD be a multiple of 20 msec. + + Encoding considerations: + + This media type is framed and binary, see section 4.8 in + [RFC4288]. + + Security considerations: See Section 6 + + Interoperability considerations: + + None. + + Published specification: RFC XXXX [This RFC]. + + Applications which use this media type: + + Audio streaming and conferencing applications. + + Additional information: none + + Person and email address to contact for further information : + + + + + +Herlein, et al. Expires October 24, 2007 [Page 9] + +Internet-Draft Speex April 2007 + + + Alfred E. Heggestad: aeh@db.org + + Intended usage: COMMON + + Restrictions on usage: + + This media type depends on RTP framing, and hence is only defined + for transfer via RTP [RFC3550]. Transport within other framing + protocols is not defined at this time. + + Author: Alfred E. Heggestad + + Change controller: + + IETF Audio/Video Transport working group delegated from the IESG. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 10] + +Internet-Draft Speex April 2007 + + +5. SDP usage of Speex + + When conveying information by SDP [RFC4566], the encoding name MUST + be set to "speex". An example of the media representation in SDP for + offering a single channel of Speex at 8000 samples per second might + be: + + m=audio 8088 RTP/AVP 97 + a=rtpmap:97 speex/8000 + + Note that the RTP payload type code of 97 is defined in this media + definition to be 'mapped' to the speex codec at an 8kHz sampling + frequency using the 'a=rtpmap' line. Any number from 96 to 127 could + have been chosen (the allowed range for dynamic types). + + The value of the sampling frequency is typically 8000 for narrow band + operation, 16000 for wide band operation, and 32000 for ultra-wide + band operation. + + If for some reason the offerer has bandwidth limitations, the client + may use the "b=" header, as explained in SDP [RFC4566]. The + following example illustrates the case where the offerer cannot + receive more than 10 kbit/s. + + m=audio 8088 RTP/AVP 97 + b=AS:10 + a=rtmap:97 speex/8000 + + In this case, if the remote part agrees, it should configure its + Speex encoder so that it does not use modes that produce more than 10 + kbit/s. Note that the "b=" constraint also applies on all payload + types that may be proposed in the media line ("m="). + + An other way to make recommendations to the remote Speex encoder is + to use its specific parameters via the a=fmtp: directive. The + following parameters are defined for use in this way: + + ptime: duration of each packet in milliseconds. + + + sr: actual sample rate in Hz. + + + ebw: encoding bandwidth - either 'narrow' or 'wide' or 'ultra' + (corresponds to nominal 8000, 16000, and 32000 Hz sampling rates). + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 11] + +Internet-Draft Speex April 2007 + + + vbr: variable bit rate - either 'on' 'off' or 'vad' (defaults to + off). If on, variable bit rate is enabled. If off, disabled. If + set to 'vad' then constant bit rate is used but silence will be + encoded with special short frames to indicate a lack of voice for + that period. + + + cng: comfort noise generation - either 'on' or 'off'. If off then + silence frames will be silent; if 'on' then those frames will be + filled with comfort noise. + + + mode: Speex encoding mode. Can be {1,2,3,4,5,6,any} defaults to 3 + in narrowband, 6 in wide and ultra-wide. + + + Examples: + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=fmtp:97 mode=4 + + This examples illustrate an offerer that wishes to receive a Speex + stream at 8000Hz, but only using speex mode 4. + + Several Speex specific parameters can be given in a single a=fmtp + line provided that they are separated by a semi-colon: + + a=fmtp:97 mode=any;mode=1 + + The offerer may indicate that it wishes to send variable bit rate + frames with comfort noise: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 vbr=on;cng=on + + The "ptime" attribute is used to denote the packetization interval + (ie, how many milliseconds of audio is encoded in a single RTP + packet). Since Speex uses 20 msec frames, ptime values of multiples + of 20 denote multiple Speex frames per packet. Values of ptime which + are not multiples of 20 MUST be ignored and clients MUST use the + default value of 20 instead. + + Implementations SHOULD support ptime of 20 msec (i.e. one frame per + packet) + + In the example below the ptime value is set to 40, indicating that + + + +Herlein, et al. Expires October 24, 2007 [Page 12] + +Internet-Draft Speex April 2007 + + + there are 2 frames in each packet. + + m=audio 8008 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=ptime:40 + + Note that the ptime parameter applies to all payloads listed in the + media line and is not used as part of an a=fmtp directive. + + Values of ptime not multiple of 20 msec are meaningless, so the + receiver of such ptime values MUST ignore them. If during the life + of an RTP session the ptime value changes, when there are multiple + Speex frames for example, the SDP value must also reflect the new + value. + + Care must be taken when setting the value of ptime so that the RTP + packet size does not exceed the path MTU. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 13] + +Internet-Draft Speex April 2007 + + +6. Security Considerations + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification [RFC3550], and any appropriate RTP profile. This + implies that confidentiality of the media streams is achieved by + encryption. Because the data compression used with this payload + format is applied end-to-end, encryption may be performed after + compression so there is no conflict between the two operations. + + A potential denial-of-service threat exists for data encodings using + compression techniques that have non-uniform receiver-end + computational load. The attacker can inject pathological datagrams + into the stream which are complex to decode and cause the receiver to + be overloaded. However, this encoding does not exhibit any + significant non-uniformity. + + As with any IP-based protocol, in some circumstances a receiver may + be overloaded simply by the receipt of too many packets, either + desired or undesired. Network-layer authentication may be used to + discard packets from undesired sources, but the processing cost of + the authentication itself may be too high. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 14] + +Internet-Draft Speex April 2007 + + +7. Acknowledgements + + The authors would like to thank Equivalence Pty Ltd of Australia for + their assistance in attempting to standardize the use of Speex in + H.323 applications, and for implementing Speex in their open source + OpenH323 stack. The authors would also like to thank Brian C. Wiles + of StreamComm for his assistance in developing + the proposed standard for Speex use in H.323 applications. + + The authors would also like to thank the following members of the + Speex and AVT communities for their input: Ross Finlayson, Federico + Montesino Pouzols, Henning Schulzrinne, Magnus Westerlund. + + Thanks to former authors of this document; Simon Morlat, Roger + Hardiman, Phil Kerr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 15] + +Internet-Draft Speex April 2007 + + +8. References + +8.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3550] Schulzrinne, H., Casner, S., Frederick, R., and V. + Jacobson, "RTP: A Transport Protocol for Real-Time + Applications", STD 64, RFC 3550, July 2003. + + [RFC4566] Handley, M., Jacobson, V., and C. Perkins, "SDP: Session + Description Protocol", RFC 4566, July 2006. + +8.2. Informative References + + [CELP] "CELP, U.S. Federal Standard 1016.", National Technical + Information Service (NTIS) website http://www.ntis.gov/. + + [RFC4288] Freed, N. and J. Klensin, "Media Type Specifications and + Registration Procedures", BCP 13, RFC 4288, December 2005. + + [speexenc] + Valin, J., "Speexenc/speexdec, reference command-line + encoder/decoder", Speex website http://www.speex.org/. + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 16] + +Internet-Draft Speex April 2007 + + +Authors' Addresses + + Greg Herlein + 2034 Filbert Street + San Francisco, California 94123 + United States + + Email: gherlein@herlein.com + + + Jean-Marc Valin + University of Sherbrooke + Department of Electrical and Computer Engineering + University of Sherbrooke + 2500 blvd Universite + Sherbrooke, Quebec J1K 2R1 + Canada + + Email: jean-marc.valin@usherbrooke.ca + + + Alfred E. Heggestad + Biskop J. Nilssonsgt. 20a + Oslo 0659 + Norway + + Email: aeh@db.org + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires October 24, 2007 [Page 17] + +Internet-Draft Speex April 2007 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + +Acknowledgment + + Funding for the RFC Editor function is provided by the IETF + Administrative Support Activity (IASA). + + + + + +Herlein, et al. Expires October 24, 2007 [Page 18] + diff --git a/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-05-tmp.txt b/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-05-tmp.txt new file mode 100644 index 0000000..70c8007 --- /dev/null +++ b/native/codec/libraries/speex/doc/draft-ietf-avt-rtp-speex-05-tmp.txt @@ -0,0 +1,1288 @@ + + + +AVT G. Herlein +Internet-Draft +Intended status: Standards Track J. Valin +Expires: August 19, 2008 CSIRO + A. Heggestad + Creytiv.com + A. Moizard + Antisip + February 16, 2008 + + + RTP Payload Format for the Speex Codec + draft-ietf-avt-rtp-speex-05 + +Status of this Memo + + By submitting this Internet-Draft, each author represents that any + applicable patent or other IPR claims of which he or she is aware + have been or will be disclosed, and any of which he or she becomes + aware will be disclosed, in accordance with Section 6 of BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on August 19, 2008. + +Copyright Notice + + Copyright (C) The IETF Trust (2008). + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 1] + +Internet-Draft Speex February 2008 + + +Abstract + + Speex is an open-source voice codec suitable for use in Voice over IP + (VoIP) type applications. This document describes the payload format + for Speex generated bit streams within an RTP packet. Also included + here are the necessary details for the use of Speex with the Session + Description Protocol (SDP). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 2] + +Internet-Draft Speex February 2008 + + +Editors Note + + All references to RFC XXXX are to be replaced by references to the + RFC number of this memo, when published. + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 3. RTP usage for Speex . . . . . . . . . . . . . . . . . . . . . 6 + 3.1. RTP Speex Header Fields . . . . . . . . . . . . . . . . . 6 + 3.2. RTP payload format for Speex . . . . . . . . . . . . . . . 6 + 3.3. Speex payload . . . . . . . . . . . . . . . . . . . . . . 6 + 3.4. Example Speex packet . . . . . . . . . . . . . . . . . . . 7 + 3.5. Multiple Speex frames in a RTP packet . . . . . . . . . . 7 + 4. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 9 + 4.1. Media Type Registration . . . . . . . . . . . . . . . . . 9 + 4.1.1. Registration of media type audio/speex . . . . . . . . 9 + 5. SDP usage of Speex . . . . . . . . . . . . . . . . . . . . . . 12 + 5.1. Example supporting all modes, prefer mode 4 . . . . . . . 15 + 5.2. Example supporting only mode 3 and 5 . . . . . . . . . . . 15 + 5.3. Example with Variable Bit Rate and Comfort Noise . . . . . 15 + 5.4. Example with Voice Activity Detection . . . . . . . . . . 15 + 5.5. Example with Multiple sampling rates . . . . . . . . . . . 15 + 5.6. Example with ptime and Multiple Speex frames . . . . . . . 16 + 5.7. Example with Complete Offer/Answer exchange . . . . . . . 16 + 6. Implementation Guidelines . . . . . . . . . . . . . . . . . . 17 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 18 + 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 19 + 9. Copying conditions . . . . . . . . . . . . . . . . . . . . . . 20 + 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 21 + 10.1. Normative References . . . . . . . . . . . . . . . . . . . 21 + 10.2. Informative References . . . . . . . . . . . . . . . . . . 21 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 22 + Intellectual Property and Copyright Statements . . . . . . . . . . 23 + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 3] + +Internet-Draft Speex February 2008 + + +1. Introduction + + Speex is based on the CELP [CELP] encoding technique with support for + either narrowband (nominal 8kHz), wideband (nominal 16kHz) or ultra- + wideband (nominal 32kHz). The main characteristics can be summarized + as follows: + + o Free software/open-source + + o Integration of wideband and narrowband in the same bit-stream + + o Wide range of bit-rates available + + o Dynamic bit-rate switching and variable bit-rate (VBR) + + o Voice Activity Detection (VAD, integrated with VBR) + + o Variable complexity + + The Speex codec supports a wide range of bit-rates from 2.15 kbit/s + to 44 kbit/s. In some cases however, it may not be possible for an + implementation to include support for all rates (e.g. because of + bandwidth, RAM or CPU constraints). In those cases, to be compliant + with this specification, implementations MUST support at least + narrowband (8 kHz) encoding and decoding at 8 kbit/s bit-rate + (narrowband mode 3). Support for narrowband at 15 kbit/s (narrowband + mode 5) is RECOMMENDED and support for wideband at 27.8 kbit/s + (wideband mode 8) is also RECOMMENDED. The sampling rate MUST be 8, + 16 or 32 kHz. + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 4] + +Internet-Draft Speex February 2008 + + +2. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC2119 [RFC2119] and + indicate requirement levels for compliant RTP implementations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 5] + +Internet-Draft Speex February 2008 + + +3. RTP usage for Speex + +3.1. RTP Speex Header Fields + + The RTP header is defined in the RTP specification [RFC3550]. This + section defines how fields in the RTP header are used. + + Payload Type (PT): The assignment of an RTP payload type for this + packet format is outside the scope of this document; it is + specified by the RTP profile under which this payload format is + used, or signaled dynamically out-of-band (e.g., using SDP). + + Marker (M) bit: The M bit is set to one on the first packet sent + after a silence period, during which packets have not been + transmitted contiguously. + + Extension (X) bit: Defined by the RTP profile used. + + Timestamp: A 32-bit word that corresponds to the sampling instant + for the first frame in the RTP packet. + +3.2. RTP payload format for Speex + + The RTP payload for Speex has the format shown in Figure 1. No + additional header fields specific to this payload format are + required. For RTP based transportation of Speex encoded audio the + standard RTP header [RFC3550] is followed by one or more payload data + blocks. An optional padding terminator may also be used. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | one or more frames of Speex .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | one or more frames of Speex .... | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 1: RTP payload for Speex + +3.3. Speex payload + + For the purposes of packetizing the bit stream in RTP, it is only + necessary to consider the sequence of bits as output by the Speex + encoder [speex_manual], and present the same sequence to the decoder. + The payload format described here maintains this sequence. + + + + +Herlein, et al. Expires August 19, 2008 [Page 6] + +Internet-Draft Speex February 2008 + + + A typical Speex frame, encoded at the maximum bitrate, is approx. 110 + octets and the total number of Speex frames SHOULD be kept less than + the path MTU to prevent fragmentation. Speex frames MUST NOT be + fragmented across multiple RTP packets, + + An RTP packet MAY contain Speex frames of the same bit rate or of + varying bit rates, since the bit-rate for a frame is conveyed in band + with the signal. + + The encoding and decoding algorithm can change the bit rate at any 20 + msec frame boundary, with the bit rate change notification provided + in-band with the bit stream. Each frame contains both sampling rate + (narrowband, wideband or ultra-wideband) and "mode" (bit-rate) + information in the bit stream. No out-of-band notification is + required for the decoder to process changes in the bit rate sent by + the encoder. + + The sampling rate MUST be either 8000 Hz, 16000 Hz, or 32000 Hz. + + The RTP payload MUST be padded to provide an integer number of octets + as the payload length. These padding bits are LSB aligned in network + octet order and consist of a 0 followed by all ones (until the end of + the octet). This padding is only required for the last frame in the + packet, and only to ensure the packet contents ends on an octet + boundary. + +3.4. Example Speex packet + + In the example below we have a single Speex frame with 5 bits of + padding to ensure the packet size falls on an octet boundary. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | ..speex data.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex data.. |0 1 1 1 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +3.5. Multiple Speex frames in a RTP packet + + Below is an example of two Speex frames contained within one RTP + packet. The Speex frame length in this example fall on an octet + boundary so there is no padding. + + The Speex decoder [speex_manual] can detect the bitrate from the + + + +Herlein, et al. Expires August 19, 2008 [Page 7] + +Internet-Draft Speex February 2008 + + + payload and is responsible for detecting the 20 msec boundaries + between each frame. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP Header | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | ..speex frame 1.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex frame 1.. | ..speex frame 2.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..speex frame 2.. | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 8] + +Internet-Draft Speex February 2008 + + +4. IANA Considerations + + This document defines the Speex media type. + +4.1. Media Type Registration + + This section describes the media types and names associated with this + payload format. The section registers the media types, as per + RFC4288 [RFC4288] + +4.1.1. Registration of media type audio/speex + + Media type name: audio + + Media subtype name: speex + + Required parameters: + + rate: RTP timestamp clock rate, which is equal to the sampling + rate in Hz. The sampling rate MUST be either 8000, 16000, or + 32000. + + Optional parameters: + + ptime: SHOULD be a multiple of 20 msec [RFC4566] + + maxptime: SHOULD be a multiple of 20 msec [RFC4566] + + vbr: variable bit rate - either 'on' 'off' or 'vad' (defaults to + off). If on, variable bit rate is enabled. If off, disabled. If + set to 'vad' then constant bit rate is used but silence will be + encoded with special short frames to indicate a lack of voice for + that period. + + + cng: comfort noise generation - either 'on' or 'off'. If off then + silence frames will be silent; if 'on' then those frames will be + filled with comfort noise. + + + mode: List supported Speex decoding modes. The valid modes are + different for narrowband and wideband, and are defined as follows: + + * {1,2,3,4,5,6,7,8,any} for narrowband + + * {0,1,2,3,4,5,6,7,8,9,10,any} for wideband and ultra-wideband + + Several 'mode' parameters can be provided. In this case, the + + + +Herlein, et al. Expires August 19, 2008 [Page 9] + +Internet-Draft Speex February 2008 + + + remote party SHOULD configure its encoder using the first + supported mode provided. When 'any' is used, the offerer + indicates that it supports all decoding modes. If the 'mode' + parameter is not provided, the mode value is considered to be + equivalent to 'mode=3;mode=any' in narrowband and + 'mode=8;mode=any' in wideband and ultra-wideband. Note that each + Speex frame does contains the mode (or bit-rate) that should be + used to decode it. Thus application MUST be able to decode any + Speex frame unless the SDP clearly specify that some modes are not + supported. (e.g., by not including 'mode=any') + + Encoding considerations: + + This media type is framed and binary, see section 4.8 in + [RFC4288]. + + Security considerations: See Section 6 + + Interoperability considerations: + + None. + + Published specification: + + RFC XXXX [RFC Editor: please replace by the RFC number of this + memo, when published] + + Applications which use this media type: + + Audio streaming and conferencing applications. + + Additional information: none + + Person and email address to contact for further information : + + Alfred E. Heggestad: aeh@db.org + + Intended usage: COMMON + + Restrictions on usage: + + This media type depends on RTP framing, and hence is only defined + for transfer via RTP [RFC3550]. Transport within other framing + protocols is not defined at this time. + + Author: Alfred E. Heggestad + + Change controller: + + + +Herlein, et al. Expires August 19, 2008 [Page 10] + +Internet-Draft Speex February 2008 + + + IETF Audio/Video Transport working group delegated from the IESG. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 11] + +Internet-Draft Speex February 2008 + + +5. SDP usage of Speex + + The information carried in the media type specification has a + specific mapping to fields in the Session Description Protocol (SDP) + [RFC4566], which is commonly used to describe RTP sessions. When SDP + is used to specify sessions employing the Speex codec, the mapping is + as follows: + + o The media type ("audio") goes in SDP "m=" as the media name. + + o The media subtype ("speex") goes in SDP "a=rtpmap" as the encoding + name. The required parameter "rate" also goes in "a=rtpmap" as + the clock rate. + + o The parameters "ptime" and "maxptime" go in the SDP "a=ptime" and + "a=maxptime" attributes, respectively. + + o Any remaining parameters go in the SDP "a=fmtp" attribute by + copying them directly from the media type string as a semicolon + separated list of parameter=value pairs. + + The tables below include the equivalence between modes and bitrates + for narrowband, wideband and ultra-wideband. Also, the corresponding + "Speex quality" setting (see SPEEX_SET_QUALITY in The Speex Codec + Manual [speex_manual]) is included as an indication. + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 12] + +Internet-Draft Speex February 2008 + + + +------+---------------+-------------+ + | mode | Speex quality | bitrate | + +------+---------------+-------------+ + | 1 | 0 | 2.15 kbit/s | + | | | | + | 2 | 2 | 5.95 kbit/s | + | | | | + | 3 | 3 or 4 | 8.00 kbit/s | + | | | | + | 4 | 5 or 6 | 11.0 kbit/s | + | | | | + | 5 | 7 or 8 | 15.0 kbit/s | + | | | | + | 6 | 9 | 18.2 kbit/s | + | | | | + | 7 | 10 | 24.6 kbit/s | + | | | | + | 8 | 1 | 3.95 kbit/s | + +------+---------------+-------------+ + + Mode vs Bitrate table for narrowband + + Table 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 13] + +Internet-Draft Speex February 2008 + + + +------+---------------+------------------+------------------------+ + | mode | Speex quality | wideband bitrate | ultra wideband bitrate | + +------+---------------+------------------+------------------------+ + | 0 | 0 | 3.95 kbit/s | 5.75 kbit/s | + | | | | | + | 1 | 1 | 5.75 kbit/s | 7.55 kbit/s | + | | | | | + | 2 | 2 | 7.75 kbit/s | 9.55 kbit/s | + | | | | | + | 3 | 3 | 9.80 kbit/s | 11.6 kbit/s | + | | | | | + | 4 | 4 | 12.8 kbit/s | 14.6 kbit/s | + | | | | | + | 5 | 5 | 16.8 kbit/s | 18.6 kbit/s | + | | | | | + | 6 | 6 | 20.6 kbit/s | 22.4 kbit/s | + | | | | | + | 7 | 7 | 23.8 kbit/s | 25.6 kbit/s | + | | | | | + | 8 | 8 | 27.8 kbit/s | 29.6 kbit/s | + | | | | | + | 9 | 9 | 34.2 kbit/s | 36.0 kbit/s | + | | | | | + | 10 | 10 | 42.2 kbit/s | 44.0 kbit/s | + +------+---------------+------------------+------------------------+ + + Mode vs Bitrate table for wideband and ultra-wideband + + Table 2 + + The Speex parameters indicate the decoding capabilities of the agent, + and what the agent prefers to receive. + + The Speex parameters in an SDP Offer/Answer exchange are completely + orthogonal, and there is no relationship between the SDP Offer and + the Answer. + + Several Speex specific parameters can be given in a single a=fmtp + line provided that they are separated by a semi-colon: + + a=fmtp:97 mode=1;mode=any;vbr=on + + Some example SDP session descriptions utilizing Speex encodings + follow. + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 14] + +Internet-Draft Speex February 2008 + + +5.1. Example supporting all modes, prefer mode 4 + + The offerer indicates that it wishes to receive a Speex stream at + 8000Hz, and wishes to receive Speex 'mode 4'. It is important to + understand that any other mode might still be sent by remote party: + the device might have bandwidth limitation or might only be able to + send 'mode=3'. Thus, application that support all decoding modes + SHOULD include 'mode=any' as shown in the example below: + + m=audio 8088 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=fmtp:97 mode=4;mode=any + +5.2. Example supporting only mode 3 and 5 + + The offerer indicates the mode he wishes to receive (Speex 'mode 3'). + This offer indicates mode 3 and mode 5 are supported and that no + other modes are supported. The remote party MUST NOT configure its + encoder using another Speex mode. + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 mode=3;mode=5 + +5.3. Example with Variable Bit Rate and Comfort Noise + + The offerer indicates that it wishes to receive variable bit rate + frames with comfort noise: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 vbr=on;cng=on + +5.4. Example with Voice Activity Detection + + The offerer indicates that it wishes to use silence suppression. In + this case vbr=vad parameter will be used: + + m=audio 8088 RTP/AVP 97 + a=rtmap:97 speex/8000 + a=fmtp:97 vbr=vad + +5.5. Example with Multiple sampling rates + + The offerer indicates that it wishes to receive Speex audio at 16000 + Hz with mode 10 (42.2 kbit/s), alternatively Speex audio at 8000 Hz + with mode 7 (24.6 kbit/s). The offerer supports decoding all modes. + + + + +Herlein, et al. Expires August 19, 2008 [Page 15] + +Internet-Draft Speex February 2008 + + + m=audio 8088 RTP/AVP 97 98 + a=rtmap:97 speex/16000 + a=fmtp:97 mode=10;mode=any + a=rtmap:98 speex/8000 + a=fmtp:98 mode=7;mode=any + +5.6. Example with ptime and Multiple Speex frames + + The "ptime" attribute is used to denote the packetization interval + (ie, how many milliseconds of audio is encoded in a single RTP + packet). Since Speex uses 20 msec frames, ptime values of multiples + of 20 denote multiple Speex frames per packet. Values of ptime which + are not multiples of 20 MUST be rounded up to the first multiple of + 20 above the ptime value. + + In the example below the ptime value is set to 40, indicating that + there are 2 frames in each packet. + + m=audio 8088 RTP/AVP 97 + a=rtpmap:97 speex/8000 + a=ptime:40 + + Note that the ptime parameter applies to all payloads listed in the + media line and is not used as part of an a=fmtp directive. + + Care must be taken when setting the value of ptime so that the RTP + packet size does not exceed the path MTU. + +5.7. Example with Complete Offer/Answer exchange + + The offerer indicates that it wishes to receive Speex audio at 16000 + Hz, alternatively Speex audio at 8000 Hz. The offerer does support + ALL modes because no mode is specified. + + m=audio 8088 RTP/AVP 97 98 + a=rtmap:97 speex/16000 + a=rtmap:98 speex/8000 + + The answerer indicates that it wishes to receive Speex audio at 8000 + Hz, which is the only sampling rate it supports. The answerer does + support ALL modes because no mode is specified. + + m=audio 8088 RTP/AVP 99 + a=rtmap:99 speex/8000 + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 16] + +Internet-Draft Speex February 2008 + + +6. Implementation Guidelines + + Implementations that supports Speex are responsible for correctly + decoding incoming Speex frames. + + Each Speex frame does contains all needed informations to decode + itself. In particular, the 'mode' and 'ptime' values proposed in the + SDP contents MUST NOT be used for decoding: those values are not + needed to properly decode a RTP Speex stream. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 17] + +Internet-Draft Speex February 2008 + + +7. Security Considerations + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification [RFC3550], and any appropriate RTP profile. This + implies that confidentiality of the media streams is achieved by + encryption. Because the data compression used with this payload + format is applied end-to-end, encryption may be performed after + compression so there is no conflict between the two operations. + + A potential denial-of-service threat exists for data encodings using + compression techniques that have non-uniform receiver-end + computational load. The attacker can inject pathological datagrams + into the stream which are complex to decode and cause the receiver to + be overloaded. However, this encoding does not exhibit any + significant non-uniformity. + + As with any IP-based protocol, in some circumstances a receiver may + be overloaded simply by the receipt of too many packets, either + desired or undesired. Network-layer authentication may be used to + discard packets from undesired sources, but the processing cost of + the authentication itself may be too high. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 18] + +Internet-Draft Speex February 2008 + + +8. Acknowledgements + + The authors would like to thank Equivalence Pty Ltd of Australia for + their assistance in attempting to standardize the use of Speex in + H.323 applications, and for implementing Speex in their open source + OpenH323 stack. The authors would also like to thank Brian C. Wiles + of StreamComm for his assistance in developing + the proposed standard for Speex use in H.323 applications. + + The authors would also like to thank the following members of the + Speex and AVT communities for their input: Ross Finlayson, Federico + Montesino Pouzols, Henning Schulzrinne, Magnus Westerlund, Colin + Perkins, Ivo Emanuel Goncalves. + + Thanks to former authors of this document; Simon Morlat, Roger + Hardiman, Phil Kerr. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 19] + +Internet-Draft Speex February 2008 + + +9. Copying conditions + + The authors agree to grant third parties the irrevocable right to + copy, use and distribute the work, with or without modification, in + any medium, without royalty, provided that, unless separate + permission is granted, redistributed modified works do not contain + misleading author, version, name of work, or endorsement information. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 20] + +Internet-Draft Speex February 2008 + + +10. References + +10.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3550] Schulzrinne, H., Casner, S., Frederick, R., and V. + Jacobson, "RTP: A Transport Protocol for Real-Time + Applications", STD 64, RFC 3550, July 2003. + + [RFC4566] Handley, M., Jacobson, V., and C. Perkins, "SDP: Session + Description Protocol", RFC 4566, July 2006. + +10.2. Informative References + + [CELP] "CELP, U.S. Federal Standard 1016.", National Technical + Information Service (NTIS) website http://www.ntis.gov/. + + [RFC4288] Freed, N. and J. Klensin, "Media Type Specifications and + Registration Procedures", BCP 13, RFC 4288, December 2005. + + [speex_manual] + Valin, J., "The Speex Codec Manual", Speex + website http://www.speex.org/docs/. + + + + + + + + + + + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 21] + +Internet-Draft Speex February 2008 + + +Authors' Addresses + + Greg Herlein + 2034 Filbert Street + San Francisco, California 94123 + United States + + Email: gherlein@herlein.com + + + Jean-Marc Valin + CSIRO + PO Box 76 + Epping, NSW 1710 + Australia + + Email: jean-marc.valin@usherbrooke.ca + + + Alfred E. Heggestad + Creytiv.com + Biskop J. Nilssonsgt. 20a + Oslo 0659 + Norway + + Email: aeh@db.org + + + Aymeric Moizard + Antisip + 4 Quai Perrache + Lyon 69002 + France + + Email: jack@atosc.org + + + + + + + + + + + + + + + + +Herlein, et al. Expires August 19, 2008 [Page 22] + +Internet-Draft Speex February 2008 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2008). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + +Acknowledgment + + Funding for the RFC Editor function is provided by the IETF + Administrative Support Activity (IASA). + + + + + +Herlein, et al. Expires August 19, 2008 [Page 23] + diff --git a/native/codec/libraries/speex/doc/echo_path.eps b/native/codec/libraries/speex/doc/echo_path.eps new file mode 100644 index 0000000..c5a458c --- /dev/null +++ b/native/codec/libraries/speex/doc/echo_path.eps @@ -0,0 +1,1298 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 0 0 415 235 +%%Pages: 0 +%%Creator: Sun Microsystems, Inc. +%%Title: none +%%CreationDate: none +%%LanguageLevel: 2 +%%EndComments +%%BeginProlog +%%BeginResource: procset SDRes-Prolog 1.0 0 +/b4_inc_state save def +/dict_count countdictstack def +/op_count count 1 sub def +userdict begin +0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath +/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if +/bdef {bind def} bind def +/c {setgray} bdef +/l {neg lineto} bdef +/rl {neg rlineto} bdef +/lc {setlinecap} bdef +/lj {setlinejoin} bdef +/lw {setlinewidth} bdef +/ml {setmiterlimit} bdef +/ld {setdash} bdef +/m {neg moveto} bdef +/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef +/r {rotate} bdef +/t {neg translate} bdef +/s {scale} bdef +/sw {show} bdef +/gs {gsave} bdef +/gr {grestore} bdef +/f {findfont dup length dict begin +{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def +currentdict end /NFont exch definefont pop /NFont findfont} bdef +/p {closepath} bdef +/sf {scalefont setfont} bdef +/ef {eofill}bdef +/pc {closepath stroke}bdef +/ps {stroke}bdef +/pum {matrix currentmatrix}bdef +/pom {setmatrix}bdef +/bs {/aString exch def /nXOfs exch def /nWidth exch def currentpoint nXOfs 0 rmoveto pum nWidth aString stringwidth pop div 1 scale aString show pom moveto} bdef +%%EndResource +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%EndPageSetup +pum +0.02836 0.02836 s +0 -8286 t +/tm matrix currentmatrix def +tm setmatrix +-3900 -8857 t +1 1 s +0.000 c 10000 12000 m 9581 12419 l 9413 12084 l 10000 12000 l p ef +6989 13478 m 9586 12179 l 9609 12224 l 7011 13522 l 6989 13478 l p ef +0.996 c 8500 13800 m 7500 13800 l 7500 11800 l 9500 11800 l 9500 13800 l +8500 13800 l p ef +50 lw 1 lj 0.000 c 8500 13800 m 7500 13800 l 7500 11800 l 9500 11800 l +9500 13800 l 8500 13800 l pc +gs +gs +pum +8080 12960 t +103 -334 m 103 -334 103 -334 8 -334 ct 8 -334 8 -334 8 -323 ct 31 -318 34 -314 34 -294 ct +34 -294 34 -294 34 -42 ct 34 -21 30 -16 8 -12 ct 8 -12 8 -12 8 0 ct 8 0 8 0 127 0 ct +127 0 127 0 127 -12 ct 109 -14 103 -22 103 -40 ct 103 -40 103 -40 103 -172 ct 103 -174 106 -179 111 -184 ct +122 -195 134 -201 145 -201 ct 163 -201 171 -188 171 -160 ct 171 -160 171 -160 171 -40 ct +171 -22 165 -14 148 -12 ct 148 -12 148 -12 148 0 ct 148 0 148 0 264 0 ct 264 0 264 0 264 -12 ct +246 -13 240 -21 240 -42 ct 240 -42 240 -42 240 -164 ct 240 -207 213 -234 173 -234 ct +147 -234 128 -224 103 -195 ct 103 -195 103 -195 103 -334 ct p ef +pom +gr +gs +pum +8351 12960 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +8516 12960 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +8766 12960 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +14100 16000 m 13824 16000 13600 15776 13600 15500 ct 13600 15224 13824 15000 14100 15000 ct +14376 15000 14600 15224 14600 15500 ct 14600 15776 14376 16000 14100 16000 ct +pc +gs +gs +pum +13954 15668 t +121 -141 m 15 -141 l 15 -108 l 121 -108 l 121 0 l 153 0 l 153 -108 l +259 -108 l 259 -141 l 153 -141 l 153 -250 l 121 -250 l 121 -141 l +p ef +pom +gr +gr +8500 16000 m 8224 16000 8000 15776 8000 15500 ct 8000 15224 8224 15000 8500 15000 ct +8776 15000 9000 15224 9000 15500 ct 9000 15776 8776 16000 8500 16000 ct pc +8500 15000 m 8313 14438 l 8688 14438 l 8500 15000 l p ef +8525 13800 m 8525 14550 l 8475 14550 l 8475 13800 l 8525 13800 l p ef +9000 15500 m 9563 15313 l 9563 15688 l 9000 15500 l p ef +13600 15525 m 9450 15525 l 9450 15475 l 13600 15475 l 13600 15525 l +p ef +14100 13800 m 13100 13800 l 13100 11800 l 15100 11800 l 15100 13800 l +14100 13800 l pc +gs +gs +pum +13663 12960 t +103 -334 m 103 -334 103 -334 8 -334 ct 8 -334 8 -334 8 -323 ct 31 -318 34 -314 34 -294 ct +34 -294 34 -294 34 -42 ct 34 -21 30 -16 8 -12 ct 8 -12 8 -12 8 0 ct 8 0 8 0 127 0 ct +127 0 127 0 127 -12 ct 109 -14 103 -22 103 -40 ct 103 -40 103 -40 103 -172 ct 103 -174 106 -179 111 -184 ct +122 -195 134 -201 145 -201 ct 163 -201 171 -188 171 -160 ct 171 -160 171 -160 171 -40 ct +171 -22 165 -14 148 -12 ct 148 -12 148 -12 148 0 ct 148 0 148 0 264 0 ct 264 0 264 0 264 -12 ct +246 -13 240 -21 240 -42 ct 240 -42 240 -42 240 -164 ct 240 -207 213 -234 173 -234 ct +147 -234 128 -224 103 -195 ct 103 -195 103 -195 103 -334 ct p ef +pom +gr +gs +pum +13934 12960 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +14099 12960 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +14349 12960 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +14100 15000 m 13913 14438 l 14288 14438 l 14100 15000 l p ef +14125 13800 m 14125 14550 l 14075 14550 l 14075 13800 l 14125 13800 l +p ef +5900 15500 m 6463 15313 l 6463 15688 l 5900 15500 l p ef +8000 15525 m 6350 15525 l 6350 15475 l 8000 15475 l 8000 15525 l p ef +8500 11800 m 8313 11238 l 8688 11238 l 8500 11800 l p ef +5600 10575 m 8500 10575 l 8500 10600 l 8500 10625 l 5600 10625 l 5600 10600 l +5600 10575 l p ef +8500 10600 m 8500 10575 l 8504 10575 l 8509 10577 l 8512 10578 l 8516 10581 l +8519 10584 l 8522 10587 l 8523 10591 l 8525 10596 l 8525 10600 l 8525 10600 l +8500 10600 l p ef +8525 10600 m 8525 11350 l 8500 11350 l 8475 11350 l 8475 10600 l 8500 10600 l +8525 10600 l p ef +14600 15500 m 15163 15313 l 15163 15688 l 14600 15500 l p ef +15900 15525 m 15050 15525 l 15050 15475 l 15900 15475 l 15900 15525 l +p ef +14100 11800 m 13913 11238 l 14288 11238 l 14100 11800 l p ef +5600 10575 m 14100 10575 l 14100 10600 l 14100 10625 l 5600 10625 l +5600 10600 l 5600 10575 l p ef +14100 10600 m 14100 10575 l 14104 10575 l 14109 10577 l 14112 10578 l +14116 10581 l 14119 10584 l 14122 10587 l 14123 10591 l 14125 10596 l +14125 10600 l 14125 10600 l 14100 10600 l p ef +14125 10600 m 14125 11350 l 14100 11350 l 14075 11350 l 14075 10600 l +14100 10600 l 14125 10600 l p ef +7000 15500 m 7000 13500 l ps +gs +gs +pum +16150 15536 t +10 -200 m 16 -200 20 -200 25 -200 ct 44 -200 49 -192 56 -146 ct 61 -112 67 -37 67 -8 ct +67 6 68 9 72 9 ct 84 9 130 -43 180 -114 ct 198 -138 210 -170 210 -189 ct 210 -205 198 -218 183 -218 ct +172 -218 165 -212 165 -201 ct 165 -193 167 -188 176 -180 ct 183 -174 185 -170 185 -165 ct +185 -142 153 -87 118 -50 ct 118 -50 118 -50 102 -35 ct 99 -104 96 -130 89 -167 ct +80 -217 80 -218 75 -218 ct 73 -218 69 -217 65 -216 ct 56 -214 29 -209 10 -206 ct +10 -206 10 -206 10 -200 ct p ef +pom +gr +gs +pum +16370 15536 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +16535 15536 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +16785 15536 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +9747 15298 t +229 -55 m 202 -24 197 -20 188 -20 ct 183 -20 179 -24 179 -30 ct 179 -37 195 -97 211 -152 ct +225 -197 235 -237 260 -336 ct 260 -336 260 -336 258 -338 ct 232 -333 214 -330 182 -327 ct +182 -327 182 -327 182 -318 ct 209 -318 213 -316 213 -306 ct 213 -299 212 -296 206 -271 ct +206 -271 206 -271 184 -190 ct 180 -210 171 -218 152 -218 ct 87 -218 7 -125 7 -51 ct +7 -16 27 5 59 5 ct 93 5 115 -11 148 -60 ct 143 -35 142 -27 142 -16 ct 142 -3 150 6 163 6 ct +183 6 209 -14 235 -50 ct 235 -50 235 -50 229 -55 ct p +154 -207 m 168 -207 176 -198 176 -180 ct 176 -104 124 -19 79 -19 ct 62 -19 50 -32 50 -51 ct +50 -92 75 -149 108 -183 ct 122 -198 140 -207 154 -207 ct p ef +pom +gr +gs +pum +9997 15298 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +10162 15298 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +10412 15298 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +4561 10747 t +199 -55 m 195 -51 192 -48 188 -42 ct 176 -27 170 -22 165 -22 ct 158 -22 153 -29 150 -42 ct +149 -46 148 -49 148 -51 ct 135 -101 130 -123 130 -131 ct 152 -169 169 -190 178 -190 ct +181 -190 185 -189 190 -186 ct 196 -183 200 -182 204 -182 ct 214 -182 221 -189 221 -200 ct +221 -210 212 -218 201 -218 ct 179 -218 160 -200 126 -147 ct 126 -147 126 -147 121 -175 ct +114 -208 108 -218 95 -218 ct 84 -218 67 -214 37 -204 ct 37 -204 37 -204 32 -202 ct +32 -202 32 -202 34 -194 ct 52 -199 57 -200 61 -200 ct 74 -200 77 -195 83 -166 ct +83 -166 83 -166 98 -105 ct 98 -105 98 -105 57 -47 ct 47 -33 38 -24 32 -24 ct 29 -24 24 -25 19 -28 ct +13 -32 7 -33 3 -33 ct -6 -33 -13 -26 -13 -16 ct -13 -3 -3 5 11 5 ct 27 5 33 1 57 -30 ct +71 -45 81 -59 102 -87 ct 102 -87 102 -87 117 -28 ct 123 -3 129 5 145 5 ct 164 5 177 -7 206 -51 ct +206 -51 206 -51 199 -55 ct p ef +pom +gr +gs +pum +4781 10747 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +4946 10747 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +5196 10747 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +4932 15694 t +177 -54 m 141 -25 126 -17 105 -17 ct 77 -17 58 -35 58 -62 ct 58 -69 59 -77 63 -92 ct +63 -92 63 -92 77 -94 ct 151 -105 204 -142 204 -185 ct 204 -206 189 -218 164 -218 ct +93 -218 15 -137 15 -63 ct 15 -23 42 5 81 5 ct 116 5 154 -15 183 -48 ct 183 -48 183 -48 177 -54 ct +p +75 -125 m 92 -169 128 -207 154 -207 ct 164 -207 171 -199 171 -188 ct 171 -172 162 -155 146 -140 ct +128 -123 109 -114 67 -103 ct 67 -103 67 -103 75 -125 ct p ef +pom +gr +gs +pum +5152 15694 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +5317 15694 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +5567 15694 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +8954 15959 t +121 -141 m 15 -141 l 15 -108 l 121 -108 l 121 0 l 153 0 l 153 -108 l +259 -108 l 259 -141 l 153 -141 l 153 -250 l 121 -250 l 121 -141 l +p ef +pom +gr +gr +gs +gs +pum +8848 15033 t +19 -127 m 19 -96 l 138 -96 l 138 -127 l 19 -127 l p ef +pom +gr +gr +gs +gs +pum +8080 12705 t +45 -147 m 114 -290 l 183 -147 l 216 -147 l 128 -327 l 99 -327 l 12 -147 l +45 -147 l p ef +pom +gr +gr +0.996 c 12400 9601 m 12394 11602 l 11895 11099 l 11897 10099 l 12400 9601 l +p ef +0.000 c 12400 9601 m 12394 11602 l 11895 11099 l 11897 10099 l 12400 9601 l +pc +0.996 c 11397 10599 m 11398 10099 l 11898 10100 l 11895 11100 l 11395 11099 l +11397 10599 l p ef +0.000 c 11397 10599 m 11398 10099 l 11898 10100 l 11895 11100 l 11395 11099 l +11397 10599 l pc +0.996 c 11900 16000 m 11624 16000 11400 15776 11400 15500 ct 11400 15224 11624 15000 11900 15000 ct +12176 15000 12400 15224 12400 15500 ct 12400 15776 12176 16000 11900 16000 ct +p ef +0.000 c 11900 16000 m 11624 16000 11400 15776 11400 15500 ct 11400 15224 11624 15000 11900 15000 ct +12176 15000 12400 15224 12400 15500 ct 12400 15776 12176 16000 11900 16000 ct +pc +12400 15000 m 12400 16000 l ps +gs +gs +pum +14880 16144 t +8 -196 m 11 -198 15 -198 21 -198 ct 34 -198 39 -191 39 -166 ct 39 -166 39 -166 39 -44 ct +39 -15 33 -8 9 -8 ct 9 -8 9 -8 9 0 ct 9 0 9 0 111 0 ct 111 0 111 0 111 -8 ct 87 -8 79 -14 79 -32 ct +79 -32 79 -32 79 -171 ct 103 -194 113 -200 129 -200 ct 153 -200 165 -184 165 -152 ct +165 -152 165 -152 165 -48 ct 165 -17 158 -8 134 -8 ct 134 -8 134 -8 134 0 ct 134 0 134 0 235 0 ct +235 0 235 0 235 -7 ct 211 -10 205 -16 205 -40 ct 205 -40 205 -40 205 -153 ct 205 -199 184 -227 148 -227 ct +126 -227 111 -219 78 -187 ct 78 -187 78 -187 78 -226 ct 78 -226 78 -226 75 -227 ct +51 -218 34 -213 8 -205 ct 8 -205 8 -205 8 -196 ct p ef +448 -81 m 424 -43 403 -29 372 -29 ct 345 -29 324 -43 310 -72 ct 301 -90 298 -107 297 -137 ct +297 -137 297 -137 446 -137 ct 442 -169 437 -183 425 -199 ct 411 -217 388 -227 363 -227 ct +339 -227 316 -218 298 -201 ct 275 -181 262 -146 262 -106 ct 262 -37 297 5 353 5 ct +399 5 435 -24 455 -78 ct 455 -78 455 -78 448 -81 ct p +298 -153 m 303 -191 320 -209 349 -209 ct 379 -209 390 -196 397 -153 ct 397 -153 397 -153 298 -153 ct +p ef +684 -32 m 676 -26 670 -23 663 -23 ct 652 -23 648 -30 648 -52 ct 648 -52 648 -52 648 -148 ct +648 -173 646 -188 638 -200 ct 628 -218 607 -227 578 -227 ct 533 -227 497 -203 497 -171 ct +497 -160 507 -150 518 -150 ct 530 -150 540 -160 540 -171 ct 540 -173 539 -175 539 -179 ct +538 -183 537 -187 537 -191 ct 537 -204 553 -215 572 -215 ct 596 -215 609 -201 609 -174 ct +609 -174 609 -174 609 -144 ct 534 -113 526 -109 505 -90 ct 495 -81 488 -64 488 -48 ct +488 -17 509 5 539 5 ct 560 5 580 -5 609 -31 ct 612 -5 621 5 640 5 ct 657 5 667 -1 684 -20 ct +684 -20 684 -20 684 -32 ct p +609 -61 m 609 -45 607 -41 596 -35 ct 585 -28 571 -24 561 -24 ct 544 -24 531 -40 531 -62 ct +531 -62 531 -62 531 -63 ct 531 -92 550 -110 609 -132 ct 609 -132 609 -132 609 -61 ct +p ef +693 -192 m 700 -194 705 -194 710 -194 ct 722 -194 727 -186 727 -164 ct 727 -164 727 -164 727 -41 ct +727 -17 723 -13 692 -7 ct 692 -7 692 -7 692 0 ct 692 0 692 0 809 0 ct 809 0 809 0 809 -8 ct +776 -8 767 -15 767 -44 ct 767 -44 767 -44 767 -155 ct 767 -171 788 -196 801 -196 ct +804 -196 809 -193 814 -188 ct 822 -182 827 -179 833 -179 ct 845 -179 852 -187 852 -201 ct +852 -217 842 -227 826 -227 ct 805 -227 791 -216 767 -181 ct 767 -181 767 -181 767 -226 ct +767 -226 767 -226 765 -227 ct 739 -216 722 -210 693 -200 ct 693 -200 693 -200 693 -192 ct +p ef +1176 -81 m 1152 -43 1131 -29 1100 -29 ct 1073 -29 1052 -43 1038 -72 ct 1029 -90 1026 -107 1025 -137 ct +1025 -137 1025 -137 1174 -137 ct 1170 -169 1165 -183 1153 -199 ct 1139 -217 1116 -227 1091 -227 ct +1067 -227 1044 -218 1026 -201 ct 1003 -181 990 -146 990 -106 ct 990 -37 1025 5 1081 5 ct +1127 5 1163 -24 1183 -78 ct 1183 -78 1183 -78 1176 -81 ct p +1026 -153 m 1031 -191 1048 -209 1077 -209 ct 1107 -209 1118 -196 1125 -153 ct +1125 -153 1125 -153 1026 -153 ct p ef +1206 -196 m 1209 -198 1213 -198 1219 -198 ct 1232 -198 1237 -191 1237 -166 ct +1237 -166 1237 -166 1237 -44 ct 1237 -15 1231 -8 1207 -8 ct 1207 -8 1207 -8 1207 0 ct +1207 0 1207 0 1309 0 ct 1309 0 1309 0 1309 -8 ct 1285 -8 1277 -14 1277 -32 ct 1277 -32 1277 -32 1277 -171 ct +1301 -194 1311 -200 1327 -200 ct 1351 -200 1363 -184 1363 -152 ct 1363 -152 1363 -152 1363 -48 ct +1363 -17 1356 -8 1332 -8 ct 1332 -8 1332 -8 1332 0 ct 1332 0 1332 0 1433 0 ct 1433 0 1433 0 1433 -7 ct +1409 -10 1403 -16 1403 -40 ct 1403 -40 1403 -40 1403 -153 ct 1403 -199 1382 -227 1346 -227 ct +1324 -227 1309 -219 1276 -187 ct 1276 -187 1276 -187 1276 -226 ct 1276 -226 1276 -226 1273 -227 ct +1249 -218 1232 -213 1206 -205 ct 1206 -205 1206 -205 1206 -196 ct p ef +1615 5 m 1615 5 1615 5 1686 -21 ct 1686 -21 1686 -21 1686 -28 ct 1677 -28 1676 -28 1675 -28 ct +1657 -28 1653 -33 1653 -56 ct 1653 -56 1653 -56 1653 -336 ct 1653 -336 1653 -336 1651 -337 ct +1628 -329 1611 -324 1580 -315 ct 1580 -315 1580 -315 1580 -308 ct 1584 -308 1586 -308 1590 -308 ct +1608 -308 1613 -303 1613 -283 ct 1613 -283 1613 -283 1613 -206 ct 1594 -222 1581 -227 1562 -227 ct +1506 -227 1461 -171 1461 -101 ct 1461 -38 1497 5 1551 5 ct 1578 5 1596 -5 1613 -28 ct +1613 -28 1613 -28 1613 4 ct 1613 4 1613 4 1615 5 ct p +1613 -50 m 1613 -47 1609 -41 1604 -35 ct 1596 -26 1584 -21 1570 -21 ct 1529 -21 1503 -60 1503 -121 ct +1503 -177 1526 -213 1563 -213 ct 1589 -213 1613 -190 1613 -164 ct 1613 -164 1613 -164 1613 -50 ct +p ef +1973 -155 m 1973 -155 1973 -155 1971 -222 ct 1971 -222 1971 -222 1965 -222 ct +1965 -222 1965 -222 1964 -221 ct 1960 -218 1959 -217 1957 -217 ct 1955 -217 1950 -218 1944 -221 ct +1934 -225 1923 -227 1911 -227 ct 1872 -227 1845 -202 1845 -166 ct 1845 -138 1860 -118 1901 -95 ct +1901 -95 1901 -95 1929 -78 ct 1946 -69 1955 -57 1955 -41 ct 1955 -20 1939 -6 1914 -6 ct +1898 -6 1883 -12 1874 -23 ct 1864 -35 1859 -47 1853 -75 ct 1853 -75 1853 -75 1845 -75 ct +1845 -75 1845 -75 1845 2 ct 1845 2 1845 2 1851 2 ct 1855 -3 1857 -4 1863 -4 ct +1867 -4 1874 -3 1885 0 ct 1898 3 1912 5 1920 5 ct 1957 5 1988 -24 1988 -58 ct 1988 -83 1977 -99 1948 -117 ct +1948 -117 1948 -117 1896 -148 ct 1882 -156 1875 -169 1875 -182 ct 1875 -202 1890 -216 1912 -216 ct +1940 -216 1954 -199 1965 -155 ct 1965 -155 1965 -155 1973 -155 ct p ef +2019 -195 m 2024 -195 2027 -195 2031 -195 ct 2048 -195 2051 -190 2051 -167 ct +2051 -167 2051 -167 2051 65 ct 2051 90 2046 96 2017 99 ct 2017 99 2017 99 2017 107 ct +2017 107 2017 107 2135 107 ct 2135 107 2135 107 2135 98 ct 2098 98 2092 93 2092 61 ct +2092 61 2092 61 2092 -16 ct 2109 0 2121 5 2141 5 ct 2198 5 2243 -50 2243 -122 ct +2243 -183 2209 -227 2162 -227 ct 2135 -227 2113 -215 2092 -189 ct 2092 -189 2092 -189 2092 -226 ct +2092 -226 2092 -226 2089 -227 ct 2063 -217 2046 -210 2019 -202 ct 2019 -202 2019 -202 2019 -195 ct +p +2092 -165 m 2092 -180 2119 -197 2141 -197 ct 2177 -197 2201 -160 2201 -103 ct +2201 -48 2177 -11 2142 -11 ct 2120 -11 2092 -29 2092 -44 ct 2092 -44 2092 -44 2092 -165 ct +p ef +2463 -81 m 2439 -43 2418 -29 2387 -29 ct 2360 -29 2339 -43 2325 -72 ct 2316 -90 2313 -107 2312 -137 ct +2312 -137 2312 -137 2461 -137 ct 2457 -169 2452 -183 2440 -199 ct 2426 -217 2403 -227 2378 -227 ct +2354 -227 2331 -218 2313 -201 ct 2290 -181 2277 -146 2277 -106 ct 2277 -37 2312 5 2368 5 ct +2414 5 2450 -24 2470 -78 ct 2470 -78 2470 -78 2463 -81 ct p +2313 -153 m 2318 -191 2335 -209 2364 -209 ct 2394 -209 2405 -196 2412 -153 ct +2412 -153 2412 -153 2313 -153 ct p ef +2683 -81 m 2659 -43 2638 -29 2607 -29 ct 2580 -29 2559 -43 2545 -72 ct 2536 -90 2533 -107 2532 -137 ct +2532 -137 2532 -137 2681 -137 ct 2677 -169 2672 -183 2660 -199 ct 2646 -217 2623 -227 2598 -227 ct +2574 -227 2551 -218 2533 -201 ct 2510 -181 2497 -146 2497 -106 ct 2497 -37 2532 5 2588 5 ct +2634 5 2670 -24 2690 -78 ct 2690 -78 2690 -78 2683 -81 ct p +2533 -153 m 2538 -191 2555 -209 2584 -209 ct 2614 -209 2625 -196 2632 -153 ct +2632 -153 2632 -153 2533 -153 ct p ef +2898 -77 m 2874 -42 2857 -31 2829 -31 ct 2785 -31 2754 -70 2754 -127 ct 2754 -178 2781 -213 2820 -213 ct +2838 -213 2844 -207 2849 -189 ct 2849 -189 2849 -189 2852 -178 ct 2856 -164 2864 -155 2874 -155 ct +2887 -155 2898 -164 2898 -176 ct 2898 -204 2864 -227 2823 -227 ct 2799 -227 2775 -217 2755 -199 ct +2731 -178 2717 -144 2717 -105 ct 2717 -41 2755 5 2809 5 ct 2831 5 2850 -3 2868 -18 ct +2881 -30 2890 -43 2904 -72 ct 2904 -72 2904 -72 2898 -77 ct p ef +3001 -169 m 3021 -192 3036 -200 3055 -200 ct 3079 -200 3091 -182 3091 -148 ct +3091 -148 3091 -148 3091 -50 ct 3091 -16 3086 -10 3058 -7 ct 3058 -7 3058 -7 3058 0 ct +3058 0 3058 0 3161 0 ct 3161 0 3161 0 3161 -7 ct 3135 -12 3132 -16 3132 -50 ct +3132 -50 3132 -50 3132 -148 ct 3132 -200 3111 -227 3072 -227 ct 3044 -227 3023 -215 3001 -185 ct +3001 -185 3001 -185 3001 -336 ct 3001 -336 3001 -336 2999 -337 ct 2982 -331 2970 -327 2943 -319 ct +2943 -319 2943 -319 2930 -315 ct 2930 -315 2930 -315 2930 -308 ct 2932 -308 2933 -308 2936 -308 ct +2956 -308 2960 -304 2960 -283 ct 2960 -283 2960 -283 2960 -50 ct 2960 -15 2957 -11 2929 -7 ct +2929 -7 2929 -7 2929 0 ct 2929 0 2929 0 3034 0 ct 3034 0 3034 0 3034 -7 ct 3006 -10 3001 -16 3001 -50 ct +3001 -50 3001 -50 3001 -169 ct p ef +pom +gr +gs +pum +15519 16745 t +214 -32 m 206 -26 200 -23 193 -23 ct 182 -23 178 -30 178 -52 ct 178 -52 178 -52 178 -148 ct +178 -173 176 -188 168 -200 ct 158 -218 137 -227 108 -227 ct 63 -227 27 -203 27 -171 ct +27 -160 37 -150 48 -150 ct 60 -150 70 -160 70 -171 ct 70 -173 69 -175 69 -179 ct +68 -183 67 -187 67 -191 ct 67 -204 83 -215 102 -215 ct 126 -215 139 -201 139 -174 ct +139 -174 139 -174 139 -144 ct 64 -113 56 -109 35 -90 ct 25 -81 18 -64 18 -48 ct +18 -17 39 5 69 5 ct 90 5 110 -5 139 -31 ct 142 -5 151 5 170 5 ct 187 5 197 -1 214 -20 ct +214 -20 214 -20 214 -32 ct p +139 -61 m 139 -45 137 -41 126 -35 ct 115 -28 101 -24 91 -24 ct 74 -24 61 -40 61 -62 ct +61 -62 61 -62 61 -63 ct 61 -92 80 -110 139 -132 ct 139 -132 139 -132 139 -61 ct +p ef +228 -196 m 231 -198 235 -198 241 -198 ct 254 -198 259 -191 259 -166 ct 259 -166 259 -166 259 -44 ct +259 -15 253 -8 229 -8 ct 229 -8 229 -8 229 0 ct 229 0 229 0 331 0 ct 331 0 331 0 331 -8 ct +307 -8 299 -14 299 -32 ct 299 -32 299 -32 299 -171 ct 323 -194 333 -200 349 -200 ct +373 -200 385 -184 385 -152 ct 385 -152 385 -152 385 -48 ct 385 -17 378 -8 354 -8 ct +354 -8 354 -8 354 0 ct 354 0 354 0 455 0 ct 455 0 455 0 455 -7 ct 431 -10 425 -16 425 -40 ct +425 -40 425 -40 425 -153 ct 425 -199 404 -227 368 -227 ct 346 -227 331 -219 298 -187 ct +298 -187 298 -187 298 -226 ct 298 -226 298 -226 295 -227 ct 271 -218 254 -213 228 -205 ct +228 -205 228 -205 228 -196 ct p ef +637 5 m 637 5 637 5 708 -21 ct 708 -21 708 -21 708 -28 ct 699 -28 698 -28 697 -28 ct +679 -28 675 -33 675 -56 ct 675 -56 675 -56 675 -336 ct 675 -336 675 -336 673 -337 ct +650 -329 633 -324 602 -315 ct 602 -315 602 -315 602 -308 ct 606 -308 608 -308 612 -308 ct +630 -308 635 -303 635 -283 ct 635 -283 635 -283 635 -206 ct 616 -222 603 -227 584 -227 ct +528 -227 483 -171 483 -101 ct 483 -38 519 5 573 5 ct 600 5 618 -5 635 -28 ct 635 -28 635 -28 635 4 ct +635 4 635 4 637 5 ct p +635 -50 m 635 -47 631 -41 626 -35 ct 618 -26 606 -21 592 -21 ct 551 -21 525 -60 525 -121 ct +525 -177 548 -213 585 -213 ct 611 -213 635 -190 635 -164 ct 635 -164 635 -164 635 -50 ct +p ef +850 -196 m 853 -198 857 -198 863 -198 ct 876 -198 881 -191 881 -166 ct 881 -166 881 -166 881 -44 ct +881 -15 875 -8 851 -8 ct 851 -8 851 -8 851 0 ct 851 0 851 0 953 0 ct 953 0 953 0 953 -8 ct +929 -8 921 -14 921 -32 ct 921 -32 921 -32 921 -171 ct 945 -194 955 -200 971 -200 ct +995 -200 1007 -184 1007 -152 ct 1007 -152 1007 -152 1007 -48 ct 1007 -17 1000 -8 976 -8 ct +976 -8 976 -8 976 0 ct 976 0 976 0 1077 0 ct 1077 0 1077 0 1077 -7 ct 1053 -10 1047 -16 1047 -40 ct +1047 -40 1047 -40 1047 -153 ct 1047 -199 1026 -227 990 -227 ct 968 -227 953 -219 920 -187 ct +920 -187 920 -187 920 -226 ct 920 -226 920 -226 917 -227 ct 893 -218 876 -213 850 -205 ct +850 -205 850 -205 850 -196 ct p ef +1213 -227 m 1150 -227 1106 -180 1106 -112 ct 1106 -45 1151 5 1212 5 ct 1273 5 1320 -47 1320 -115 ct +1320 -180 1275 -227 1213 -227 ct p +1207 -213 m 1247 -213 1276 -166 1276 -98 ct 1276 -42 1254 -9 1218 -9 ct 1199 -9 1181 -21 1171 -40 ct +1157 -66 1150 -101 1150 -136 ct 1150 -183 1172 -213 1207 -213 ct p ef +1427 -227 m 1427 -227 1427 -227 1352 -200 ct 1352 -200 1352 -200 1352 -192 ct +1352 -192 1352 -192 1356 -193 ct 1361 -194 1368 -194 1372 -194 ct 1384 -194 1388 -186 1388 -164 ct +1388 -164 1388 -164 1388 -49 ct 1388 -14 1383 -8 1350 -8 ct 1350 -8 1350 -8 1350 0 ct +1350 0 1350 0 1464 0 ct 1464 0 1464 0 1464 -8 ct 1433 -8 1429 -15 1429 -50 ct 1429 -50 1429 -50 1429 -225 ct +1429 -225 1429 -225 1427 -227 ct p +1404 -337 m 1391 -337 1380 -326 1380 -312 ct 1380 -298 1390 -287 1404 -287 ct +1418 -287 1429 -298 1429 -312 ct 1429 -326 1418 -337 1404 -337 ct p ef +1635 -155 m 1635 -155 1635 -155 1633 -222 ct 1633 -222 1633 -222 1627 -222 ct +1627 -222 1627 -222 1626 -221 ct 1622 -218 1621 -217 1619 -217 ct 1617 -217 1612 -218 1606 -221 ct +1596 -225 1585 -227 1573 -227 ct 1534 -227 1507 -202 1507 -166 ct 1507 -138 1522 -118 1563 -95 ct +1563 -95 1563 -95 1591 -78 ct 1608 -69 1617 -57 1617 -41 ct 1617 -20 1601 -6 1576 -6 ct +1560 -6 1545 -12 1536 -23 ct 1526 -35 1521 -47 1515 -75 ct 1515 -75 1515 -75 1507 -75 ct +1507 -75 1507 -75 1507 2 ct 1507 2 1507 2 1513 2 ct 1517 -3 1519 -4 1525 -4 ct +1529 -4 1536 -3 1547 0 ct 1560 3 1574 5 1582 5 ct 1619 5 1650 -24 1650 -58 ct 1650 -83 1639 -99 1610 -117 ct +1610 -117 1610 -117 1558 -148 ct 1544 -156 1537 -169 1537 -182 ct 1537 -202 1552 -216 1574 -216 ct +1602 -216 1616 -199 1627 -155 ct 1627 -155 1627 -155 1635 -155 ct p ef +1874 -81 m 1850 -43 1829 -29 1798 -29 ct 1771 -29 1750 -43 1736 -72 ct 1727 -90 1724 -107 1723 -137 ct +1723 -137 1723 -137 1872 -137 ct 1868 -169 1863 -183 1851 -199 ct 1837 -217 1814 -227 1789 -227 ct +1765 -227 1742 -218 1724 -201 ct 1701 -181 1688 -146 1688 -106 ct 1688 -37 1723 5 1779 5 ct +1825 5 1861 -24 1881 -78 ct 1881 -78 1881 -78 1874 -81 ct p +1724 -153 m 1729 -191 1746 -209 1775 -209 ct 1805 -209 1816 -196 1823 -153 ct +1823 -153 1823 -153 1724 -153 ct p ef +pom +gr +gr +gs +gs +pum +5435 10350 t +150 -222 m 150 -222 150 -222 90 -222 ct 90 -222 90 -222 90 -279 ct 90 -308 99 -323 118 -323 ct +128 -323 135 -318 143 -304 ct 151 -291 157 -286 165 -286 ct 176 -286 185 -295 185 -306 ct +185 -324 164 -337 135 -337 ct 105 -337 79 -324 67 -301 ct 54 -279 50 -261 50 -222 ct +50 -222 50 -222 10 -222 ct 10 -222 10 -222 10 -206 ct 10 -206 10 -206 50 -206 ct +50 -206 50 -206 50 -51 ct 50 -14 45 -8 10 -8 ct 10 -8 10 -8 10 0 ct 10 0 10 0 136 0 ct +136 0 136 0 136 -8 ct 96 -8 91 -13 91 -51 ct 91 -51 91 -51 91 -206 ct 91 -206 91 -206 150 -206 ct +150 -206 150 -206 150 -222 ct p ef +375 -32 m 367 -26 361 -23 354 -23 ct 343 -23 339 -30 339 -52 ct 339 -52 339 -52 339 -148 ct +339 -173 337 -188 329 -200 ct 319 -218 298 -227 269 -227 ct 224 -227 188 -203 188 -171 ct +188 -160 198 -150 209 -150 ct 221 -150 231 -160 231 -171 ct 231 -173 230 -175 230 -179 ct +229 -183 228 -187 228 -191 ct 228 -204 244 -215 263 -215 ct 287 -215 300 -201 300 -174 ct +300 -174 300 -174 300 -144 ct 225 -113 217 -109 196 -90 ct 186 -81 179 -64 179 -48 ct +179 -17 200 5 230 5 ct 251 5 271 -5 300 -31 ct 303 -5 312 5 331 5 ct 348 5 358 -1 375 -20 ct +375 -20 375 -20 375 -32 ct p +300 -61 m 300 -45 298 -41 287 -35 ct 276 -28 262 -24 252 -24 ct 235 -24 222 -40 222 -62 ct +222 -62 222 -62 222 -63 ct 222 -92 241 -110 300 -132 ct 300 -132 300 -132 300 -61 ct +p ef +384 -192 m 391 -194 396 -194 401 -194 ct 413 -194 418 -186 418 -164 ct 418 -164 418 -164 418 -41 ct +418 -17 414 -13 383 -7 ct 383 -7 383 -7 383 0 ct 383 0 383 0 500 0 ct 500 0 500 0 500 -8 ct +467 -8 458 -15 458 -44 ct 458 -44 458 -44 458 -155 ct 458 -171 479 -196 492 -196 ct +495 -196 500 -193 505 -188 ct 513 -182 518 -179 524 -179 ct 536 -179 543 -187 543 -201 ct +543 -217 533 -227 517 -227 ct 496 -227 482 -216 458 -181 ct 458 -181 458 -181 458 -226 ct +458 -226 458 -226 456 -227 ct 430 -216 413 -210 384 -200 ct 384 -200 384 -200 384 -192 ct +p ef +867 -81 m 843 -43 822 -29 791 -29 ct 764 -29 743 -43 729 -72 ct 720 -90 717 -107 716 -137 ct +716 -137 716 -137 865 -137 ct 861 -169 856 -183 844 -199 ct 830 -217 807 -227 782 -227 ct +758 -227 735 -218 717 -201 ct 694 -181 681 -146 681 -106 ct 681 -37 716 5 772 5 ct +818 5 854 -24 874 -78 ct 874 -78 874 -78 867 -81 ct p +717 -153 m 722 -191 739 -209 768 -209 ct 798 -209 809 -196 816 -153 ct 816 -153 816 -153 717 -153 ct +p ef +897 -196 m 900 -198 904 -198 910 -198 ct 923 -198 928 -191 928 -166 ct 928 -166 928 -166 928 -44 ct +928 -15 922 -8 898 -8 ct 898 -8 898 -8 898 0 ct 898 0 898 0 1000 0 ct 1000 0 1000 0 1000 -8 ct +976 -8 968 -14 968 -32 ct 968 -32 968 -32 968 -171 ct 992 -194 1002 -200 1018 -200 ct +1042 -200 1054 -184 1054 -152 ct 1054 -152 1054 -152 1054 -48 ct 1054 -17 1047 -8 1023 -8 ct +1023 -8 1023 -8 1023 0 ct 1023 0 1023 0 1124 0 ct 1124 0 1124 0 1124 -7 ct 1100 -10 1094 -16 1094 -40 ct +1094 -40 1094 -40 1094 -153 ct 1094 -199 1073 -227 1037 -227 ct 1015 -227 1000 -219 967 -187 ct +967 -187 967 -187 967 -226 ct 967 -226 967 -226 964 -227 ct 940 -218 923 -213 897 -205 ct +897 -205 897 -205 897 -196 ct p ef +1306 5 m 1306 5 1306 5 1377 -21 ct 1377 -21 1377 -21 1377 -28 ct 1368 -28 1367 -28 1366 -28 ct +1348 -28 1344 -33 1344 -56 ct 1344 -56 1344 -56 1344 -336 ct 1344 -336 1344 -336 1342 -337 ct +1319 -329 1302 -324 1271 -315 ct 1271 -315 1271 -315 1271 -308 ct 1275 -308 1277 -308 1281 -308 ct +1299 -308 1304 -303 1304 -283 ct 1304 -283 1304 -283 1304 -206 ct 1285 -222 1272 -227 1253 -227 ct +1197 -227 1152 -171 1152 -101 ct 1152 -38 1188 5 1242 5 ct 1269 5 1287 -5 1304 -28 ct +1304 -28 1304 -28 1304 4 ct 1304 4 1304 4 1306 5 ct p +1304 -50 m 1304 -47 1300 -41 1295 -35 ct 1287 -26 1275 -21 1261 -21 ct 1220 -21 1194 -60 1194 -121 ct +1194 -177 1217 -213 1254 -213 ct 1280 -213 1304 -190 1304 -164 ct 1304 -164 1304 -164 1304 -50 ct +p ef +1664 -155 m 1664 -155 1664 -155 1662 -222 ct 1662 -222 1662 -222 1656 -222 ct +1656 -222 1656 -222 1655 -221 ct 1651 -218 1650 -217 1648 -217 ct 1646 -217 1641 -218 1635 -221 ct +1625 -225 1614 -227 1602 -227 ct 1563 -227 1536 -202 1536 -166 ct 1536 -138 1551 -118 1592 -95 ct +1592 -95 1592 -95 1620 -78 ct 1637 -69 1646 -57 1646 -41 ct 1646 -20 1630 -6 1605 -6 ct +1589 -6 1574 -12 1565 -23 ct 1555 -35 1550 -47 1544 -75 ct 1544 -75 1544 -75 1536 -75 ct +1536 -75 1536 -75 1536 2 ct 1536 2 1536 2 1542 2 ct 1546 -3 1548 -4 1554 -4 ct +1558 -4 1565 -3 1576 0 ct 1589 3 1603 5 1611 5 ct 1648 5 1679 -24 1679 -58 ct 1679 -83 1668 -99 1639 -117 ct +1639 -117 1639 -117 1587 -148 ct 1573 -156 1566 -169 1566 -182 ct 1566 -202 1581 -216 1603 -216 ct +1631 -216 1645 -199 1656 -155 ct 1656 -155 1656 -155 1664 -155 ct p ef +1710 -195 m 1715 -195 1718 -195 1722 -195 ct 1739 -195 1742 -190 1742 -167 ct +1742 -167 1742 -167 1742 65 ct 1742 90 1737 96 1708 99 ct 1708 99 1708 99 1708 107 ct +1708 107 1708 107 1826 107 ct 1826 107 1826 107 1826 98 ct 1789 98 1783 93 1783 61 ct +1783 61 1783 61 1783 -16 ct 1800 0 1812 5 1832 5 ct 1889 5 1934 -50 1934 -122 ct +1934 -183 1900 -227 1853 -227 ct 1826 -227 1804 -215 1783 -189 ct 1783 -189 1783 -189 1783 -226 ct +1783 -226 1783 -226 1780 -227 ct 1754 -217 1737 -210 1710 -202 ct 1710 -202 1710 -202 1710 -195 ct +p +1783 -165 m 1783 -180 1810 -197 1832 -197 ct 1868 -197 1892 -160 1892 -103 ct +1892 -48 1868 -11 1833 -11 ct 1811 -11 1783 -29 1783 -44 ct 1783 -44 1783 -44 1783 -165 ct +p ef +2154 -81 m 2130 -43 2109 -29 2078 -29 ct 2051 -29 2030 -43 2016 -72 ct 2007 -90 2004 -107 2003 -137 ct +2003 -137 2003 -137 2152 -137 ct 2148 -169 2143 -183 2131 -199 ct 2117 -217 2094 -227 2069 -227 ct +2045 -227 2022 -218 2004 -201 ct 1981 -181 1968 -146 1968 -106 ct 1968 -37 2003 5 2059 5 ct +2105 5 2141 -24 2161 -78 ct 2161 -78 2161 -78 2154 -81 ct p +2004 -153 m 2009 -191 2026 -209 2055 -209 ct 2085 -209 2096 -196 2103 -153 ct +2103 -153 2103 -153 2004 -153 ct p ef +2374 -81 m 2350 -43 2329 -29 2298 -29 ct 2271 -29 2250 -43 2236 -72 ct 2227 -90 2224 -107 2223 -137 ct +2223 -137 2223 -137 2372 -137 ct 2368 -169 2363 -183 2351 -199 ct 2337 -217 2314 -227 2289 -227 ct +2265 -227 2242 -218 2224 -201 ct 2201 -181 2188 -146 2188 -106 ct 2188 -37 2223 5 2279 5 ct +2325 5 2361 -24 2381 -78 ct 2381 -78 2381 -78 2374 -81 ct p +2224 -153 m 2229 -191 2246 -209 2275 -209 ct 2305 -209 2316 -196 2323 -153 ct +2323 -153 2323 -153 2224 -153 ct p ef +2589 -77 m 2565 -42 2548 -31 2520 -31 ct 2476 -31 2445 -70 2445 -127 ct 2445 -178 2472 -213 2511 -213 ct +2529 -213 2535 -207 2540 -189 ct 2540 -189 2540 -189 2543 -178 ct 2547 -164 2555 -155 2565 -155 ct +2578 -155 2589 -164 2589 -176 ct 2589 -204 2555 -227 2514 -227 ct 2490 -227 2466 -217 2446 -199 ct +2422 -178 2408 -144 2408 -105 ct 2408 -41 2446 5 2500 5 ct 2522 5 2541 -3 2559 -18 ct +2572 -30 2581 -43 2595 -72 ct 2595 -72 2595 -72 2589 -77 ct p ef +2692 -169 m 2712 -192 2727 -200 2746 -200 ct 2770 -200 2782 -182 2782 -148 ct +2782 -148 2782 -148 2782 -50 ct 2782 -16 2777 -10 2749 -7 ct 2749 -7 2749 -7 2749 0 ct +2749 0 2749 0 2852 0 ct 2852 0 2852 0 2852 -7 ct 2826 -12 2823 -16 2823 -50 ct +2823 -50 2823 -50 2823 -148 ct 2823 -200 2802 -227 2763 -227 ct 2735 -227 2714 -215 2692 -185 ct +2692 -185 2692 -185 2692 -336 ct 2692 -336 2692 -336 2690 -337 ct 2673 -331 2661 -327 2634 -319 ct +2634 -319 2634 -319 2621 -315 ct 2621 -315 2621 -315 2621 -308 ct 2623 -308 2624 -308 2627 -308 ct +2647 -308 2651 -304 2651 -283 ct 2651 -283 2651 -283 2651 -50 ct 2651 -15 2648 -11 2620 -7 ct +2620 -7 2620 -7 2620 0 ct 2620 0 2620 0 2725 0 ct 2725 0 2725 0 2725 -7 ct 2697 -10 2692 -16 2692 -50 ct +2692 -50 2692 -50 2692 -169 ct p ef +pom +gr +gr +gs +gs +pum +10779 16488 t +9 -196 m 15 -198 19 -198 25 -198 ct 37 -198 42 -190 42 -166 ct 42 -166 42 -166 42 -41 ct +42 -15 35 -7 8 -7 ct 8 -7 8 -7 8 0 ct 8 0 8 0 115 0 ct 115 0 115 0 115 -8 ct 90 -8 82 -13 82 -33 ct +82 -33 82 -33 82 -172 ct 82 -173 86 -178 90 -181 ct 102 -193 122 -201 139 -201 ct +161 -201 171 -184 171 -149 ct 171 -149 171 -149 171 -42 ct 171 -14 166 -8 138 -8 ct +138 -8 138 -8 138 0 ct 138 0 138 0 247 0 ct 247 0 247 0 247 -7 ct 219 -7 212 -16 212 -46 ct +212 -46 212 -46 212 -171 ct 227 -192 243 -201 265 -201 ct 292 -201 301 -188 301 -147 ct +301 -147 301 -147 301 -43 ct 301 -15 297 -11 269 -7 ct 269 -7 269 -7 269 0 ct 269 0 269 0 375 0 ct +375 0 375 0 375 -8 ct 375 -8 375 -8 363 -8 ct 348 -8 342 -18 342 -37 ct 342 -37 342 -37 342 -139 ct +342 -197 323 -227 286 -227 ct 258 -227 233 -214 207 -185 ct 198 -214 182 -227 155 -227 ct +134 -227 121 -220 80 -189 ct 80 -189 80 -189 80 -226 ct 80 -226 80 -226 77 -227 ct +52 -218 36 -212 9 -205 ct 9 -205 9 -205 9 -196 ct p ef +470 -227 m 470 -227 470 -227 395 -200 ct 395 -200 395 -200 395 -192 ct 395 -192 395 -192 399 -193 ct +404 -194 411 -194 415 -194 ct 427 -194 431 -186 431 -164 ct 431 -164 431 -164 431 -49 ct +431 -14 426 -8 393 -8 ct 393 -8 393 -8 393 0 ct 393 0 393 0 507 0 ct 507 0 507 0 507 -8 ct +476 -8 472 -15 472 -50 ct 472 -50 472 -50 472 -225 ct 472 -225 472 -225 470 -227 ct +p +447 -337 m 434 -337 423 -326 423 -312 ct 423 -298 433 -287 447 -287 ct 461 -287 472 -298 472 -312 ct +472 -326 461 -337 447 -337 ct p ef +718 -77 m 694 -42 677 -31 649 -31 ct 605 -31 574 -70 574 -127 ct 574 -178 601 -213 640 -213 ct +658 -213 664 -207 669 -189 ct 669 -189 669 -189 672 -178 ct 676 -164 684 -155 694 -155 ct +707 -155 718 -164 718 -176 ct 718 -204 684 -227 643 -227 ct 619 -227 595 -217 575 -199 ct +551 -178 537 -144 537 -105 ct 537 -41 575 5 629 5 ct 651 5 670 -3 688 -18 ct 701 -30 710 -43 724 -72 ct +724 -72 724 -72 718 -77 ct p ef +748 -192 m 755 -194 760 -194 765 -194 ct 777 -194 782 -186 782 -164 ct 782 -164 782 -164 782 -41 ct +782 -17 778 -13 747 -7 ct 747 -7 747 -7 747 0 ct 747 0 747 0 864 0 ct 864 0 864 0 864 -8 ct +831 -8 822 -15 822 -44 ct 822 -44 822 -44 822 -155 ct 822 -171 843 -196 856 -196 ct +859 -196 864 -193 869 -188 ct 877 -182 882 -179 888 -179 ct 900 -179 907 -187 907 -201 ct +907 -217 897 -227 881 -227 ct 860 -227 846 -216 822 -181 ct 822 -181 822 -181 822 -226 ct +822 -226 822 -226 820 -227 ct 794 -216 777 -210 748 -200 ct 748 -200 748 -200 748 -192 ct +p ef +1031 -227 m 968 -227 924 -180 924 -112 ct 924 -45 969 5 1030 5 ct 1091 5 1138 -47 1138 -115 ct +1138 -180 1093 -227 1031 -227 ct p +1025 -213 m 1065 -213 1094 -166 1094 -98 ct 1094 -42 1072 -9 1036 -9 ct 1017 -9 999 -21 989 -40 ct +975 -66 968 -101 968 -136 ct 968 -183 990 -213 1025 -213 ct p ef +1164 -195 m 1169 -195 1172 -195 1176 -195 ct 1193 -195 1196 -190 1196 -167 ct +1196 -167 1196 -167 1196 65 ct 1196 90 1191 96 1162 99 ct 1162 99 1162 99 1162 107 ct +1162 107 1162 107 1280 107 ct 1280 107 1280 107 1280 98 ct 1243 98 1237 93 1237 61 ct +1237 61 1237 61 1237 -16 ct 1254 0 1266 5 1286 5 ct 1343 5 1388 -50 1388 -122 ct +1388 -183 1354 -227 1307 -227 ct 1280 -227 1258 -215 1237 -189 ct 1237 -189 1237 -189 1237 -226 ct +1237 -226 1237 -226 1234 -227 ct 1208 -217 1191 -210 1164 -202 ct 1164 -202 1164 -202 1164 -195 ct +p +1237 -165 m 1237 -180 1264 -197 1286 -197 ct 1322 -197 1346 -160 1346 -103 ct +1346 -48 1322 -11 1287 -11 ct 1265 -11 1237 -29 1237 -44 ct 1237 -44 1237 -44 1237 -165 ct +p ef +1486 -169 m 1506 -192 1521 -200 1540 -200 ct 1564 -200 1576 -182 1576 -148 ct +1576 -148 1576 -148 1576 -50 ct 1576 -16 1571 -10 1543 -7 ct 1543 -7 1543 -7 1543 0 ct +1543 0 1543 0 1646 0 ct 1646 0 1646 0 1646 -7 ct 1620 -12 1617 -16 1617 -50 ct +1617 -50 1617 -50 1617 -148 ct 1617 -200 1596 -227 1557 -227 ct 1529 -227 1508 -215 1486 -185 ct +1486 -185 1486 -185 1486 -336 ct 1486 -336 1486 -336 1484 -337 ct 1467 -331 1455 -327 1428 -319 ct +1428 -319 1428 -319 1415 -315 ct 1415 -315 1415 -315 1415 -308 ct 1417 -308 1418 -308 1421 -308 ct +1441 -308 1445 -304 1445 -283 ct 1445 -283 1445 -283 1445 -50 ct 1445 -15 1442 -11 1414 -7 ct +1414 -7 1414 -7 1414 0 ct 1414 0 1414 0 1519 0 ct 1519 0 1519 0 1519 -7 ct 1491 -10 1486 -16 1486 -50 ct +1486 -50 1486 -50 1486 -169 ct p ef +1780 -227 m 1717 -227 1673 -180 1673 -112 ct 1673 -45 1718 5 1779 5 ct 1840 5 1887 -47 1887 -115 ct +1887 -180 1842 -227 1780 -227 ct p +1774 -213 m 1814 -213 1843 -166 1843 -98 ct 1843 -42 1821 -9 1785 -9 ct 1766 -9 1748 -21 1738 -40 ct +1724 -66 1717 -101 1717 -136 ct 1717 -183 1739 -213 1774 -213 ct p ef +1917 -196 m 1920 -198 1924 -198 1930 -198 ct 1943 -198 1948 -191 1948 -166 ct +1948 -166 1948 -166 1948 -44 ct 1948 -15 1942 -8 1918 -8 ct 1918 -8 1918 -8 1918 0 ct +1918 0 1918 0 2020 0 ct 2020 0 2020 0 2020 -8 ct 1996 -8 1988 -14 1988 -32 ct 1988 -32 1988 -32 1988 -171 ct +2012 -194 2022 -200 2038 -200 ct 2062 -200 2074 -184 2074 -152 ct 2074 -152 2074 -152 2074 -48 ct +2074 -17 2067 -8 2043 -8 ct 2043 -8 2043 -8 2043 0 ct 2043 0 2043 0 2144 0 ct 2144 0 2144 0 2144 -7 ct +2120 -10 2114 -16 2114 -40 ct 2114 -40 2114 -40 2114 -153 ct 2114 -199 2093 -227 2057 -227 ct +2035 -227 2020 -219 1987 -187 ct 1987 -187 1987 -187 1987 -226 ct 1987 -226 1987 -226 1984 -227 ct +1960 -218 1943 -213 1917 -205 ct 1917 -205 1917 -205 1917 -196 ct p ef +2357 -81 m 2333 -43 2312 -29 2281 -29 ct 2254 -29 2233 -43 2219 -72 ct 2210 -90 2207 -107 2206 -137 ct +2206 -137 2206 -137 2355 -137 ct 2351 -169 2346 -183 2334 -199 ct 2320 -217 2297 -227 2272 -227 ct +2248 -227 2225 -218 2207 -201 ct 2184 -181 2171 -146 2171 -106 ct 2171 -37 2206 5 2262 5 ct +2308 5 2344 -24 2364 -78 ct 2364 -78 2364 -78 2357 -81 ct p +2207 -153 m 2212 -191 2229 -209 2258 -209 ct 2288 -209 2299 -196 2306 -153 ct +2306 -153 2306 -153 2207 -153 ct p ef +pom +gr +gr +gs +gs +pum +15356 12996 t +3 -192 m 10 -194 15 -194 20 -194 ct 32 -194 37 -186 37 -164 ct 37 -164 37 -164 37 -41 ct +37 -17 33 -13 2 -7 ct 2 -7 2 -7 2 0 ct 2 0 2 0 119 0 ct 119 0 119 0 119 -8 ct 86 -8 77 -15 77 -44 ct +77 -44 77 -44 77 -155 ct 77 -171 98 -196 111 -196 ct 114 -196 119 -193 124 -188 ct +132 -182 137 -179 143 -179 ct 155 -179 162 -187 162 -201 ct 162 -217 152 -227 136 -227 ct +115 -227 101 -216 77 -181 ct 77 -181 77 -181 77 -226 ct 77 -226 77 -226 75 -227 ct +49 -216 32 -210 3 -200 ct 3 -200 3 -200 3 -192 ct p ef +363 -81 m 339 -43 318 -29 287 -29 ct 260 -29 239 -43 225 -72 ct 216 -90 213 -107 212 -137 ct +212 -137 212 -137 361 -137 ct 357 -169 352 -183 340 -199 ct 326 -217 303 -227 278 -227 ct +254 -227 231 -218 213 -201 ct 190 -181 177 -146 177 -106 ct 177 -37 212 5 268 5 ct +314 5 350 -24 370 -78 ct 370 -78 370 -78 363 -81 ct p +213 -153 m 218 -191 235 -209 264 -209 ct 294 -209 305 -196 312 -153 ct 312 -153 312 -153 213 -153 ct +p ef +616 -222 m 616 -222 616 -222 549 -222 ct 549 -222 549 -222 549 -215 ct 564 -213 571 -208 571 -199 ct +571 -194 570 -189 568 -184 ct 568 -184 568 -184 521 -56 ct 521 -56 521 -56 471 -182 ct +468 -189 467 -196 467 -201 ct 467 -210 472 -213 489 -215 ct 489 -215 489 -215 489 -222 ct +489 -222 489 -222 394 -222 ct 394 -222 394 -222 394 -214 ct 413 -214 416 -209 438 -158 ct +438 -158 438 -158 496 -16 ct 497 -13 499 -10 500 -6 ct 503 3 506 7 509 7 ct 512 7 515 1 522 -18 ct +522 -18 522 -18 584 -176 ct 599 -210 601 -213 616 -215 ct 616 -215 616 -215 616 -222 ct +p ef +829 -81 m 805 -43 784 -29 753 -29 ct 726 -29 705 -43 691 -72 ct 682 -90 679 -107 678 -137 ct +678 -137 678 -137 827 -137 ct 823 -169 818 -183 806 -199 ct 792 -217 769 -227 744 -227 ct +720 -227 697 -218 679 -201 ct 656 -181 643 -146 643 -106 ct 643 -37 678 5 734 5 ct +780 5 816 -24 836 -78 ct 836 -78 836 -78 829 -81 ct p +679 -153 m 684 -191 701 -209 730 -209 ct 760 -209 771 -196 778 -153 ct 778 -153 778 -153 679 -153 ct +p ef +854 -192 m 861 -194 866 -194 871 -194 ct 883 -194 888 -186 888 -164 ct 888 -164 888 -164 888 -41 ct +888 -17 884 -13 853 -7 ct 853 -7 853 -7 853 0 ct 853 0 853 0 970 0 ct 970 0 970 0 970 -8 ct +937 -8 928 -15 928 -44 ct 928 -44 928 -44 928 -155 ct 928 -171 949 -196 962 -196 ct +965 -196 970 -193 975 -188 ct 983 -182 988 -179 994 -179 ct 1006 -179 1013 -187 1013 -201 ct +1013 -217 1003 -227 987 -227 ct 966 -227 952 -216 928 -181 ct 928 -181 928 -181 928 -226 ct +928 -226 928 -226 926 -227 ct 900 -216 883 -210 854 -200 ct 854 -200 854 -200 854 -192 ct +p ef +1090 -336 m 1090 -336 1090 -336 1088 -337 ct 1067 -330 1054 -326 1031 -319 ct +1031 -319 1031 -319 1017 -315 ct 1017 -315 1017 -315 1017 -308 ct 1020 -308 1022 -308 1026 -308 ct +1045 -308 1049 -304 1049 -283 ct 1049 -283 1049 -283 1049 -27 ct 1049 -11 1091 5 1129 5 ct +1193 5 1243 -49 1243 -120 ct 1243 -181 1206 -227 1157 -227 ct 1128 -227 1100 -209 1090 -185 ct +1090 -185 1090 -185 1090 -336 ct p +1090 -159 m 1090 -178 1113 -196 1138 -196 ct 1176 -196 1200 -157 1200 -97 ct +1200 -42 1177 -11 1137 -11 ct 1112 -11 1090 -22 1090 -35 ct 1090 -35 1090 -35 1090 -159 ct +p ef +1464 -81 m 1440 -43 1419 -29 1388 -29 ct 1361 -29 1340 -43 1326 -72 ct 1317 -90 1314 -107 1313 -137 ct +1313 -137 1313 -137 1462 -137 ct 1458 -169 1453 -183 1441 -199 ct 1427 -217 1404 -227 1379 -227 ct +1355 -227 1332 -218 1314 -201 ct 1291 -181 1278 -146 1278 -106 ct 1278 -37 1313 5 1369 5 ct +1415 5 1451 -24 1471 -78 ct 1471 -78 1471 -78 1464 -81 ct p +1314 -153 m 1319 -191 1336 -209 1365 -209 ct 1395 -209 1406 -196 1413 -153 ct +1413 -153 1413 -153 1314 -153 ct p ef +1489 -192 m 1496 -194 1501 -194 1506 -194 ct 1518 -194 1523 -186 1523 -164 ct +1523 -164 1523 -164 1523 -41 ct 1523 -17 1519 -13 1488 -7 ct 1488 -7 1488 -7 1488 0 ct +1488 0 1488 0 1605 0 ct 1605 0 1605 0 1605 -8 ct 1572 -8 1563 -15 1563 -44 ct 1563 -44 1563 -44 1563 -155 ct +1563 -171 1584 -196 1597 -196 ct 1600 -196 1605 -193 1610 -188 ct 1618 -182 1623 -179 1629 -179 ct +1641 -179 1648 -187 1648 -201 ct 1648 -217 1638 -227 1622 -227 ct 1601 -227 1587 -216 1563 -181 ct +1563 -181 1563 -181 1563 -226 ct 1563 -226 1563 -226 1561 -227 ct 1535 -216 1518 -210 1489 -200 ct +1489 -200 1489 -200 1489 -192 ct p ef +1865 -32 m 1857 -26 1851 -23 1844 -23 ct 1833 -23 1829 -30 1829 -52 ct 1829 -52 1829 -52 1829 -148 ct +1829 -173 1827 -188 1819 -200 ct 1809 -218 1788 -227 1759 -227 ct 1714 -227 1678 -203 1678 -171 ct +1678 -160 1688 -150 1699 -150 ct 1711 -150 1721 -160 1721 -171 ct 1721 -173 1720 -175 1720 -179 ct +1719 -183 1718 -187 1718 -191 ct 1718 -204 1734 -215 1753 -215 ct 1777 -215 1790 -201 1790 -174 ct +1790 -174 1790 -174 1790 -144 ct 1715 -113 1707 -109 1686 -90 ct 1676 -81 1669 -64 1669 -48 ct +1669 -17 1690 5 1720 5 ct 1741 5 1761 -5 1790 -31 ct 1793 -5 1802 5 1821 5 ct 1838 5 1848 -1 1865 -20 ct +1865 -20 1865 -20 1865 -32 ct p +1790 -61 m 1790 -45 1788 -41 1777 -35 ct 1766 -28 1752 -24 1742 -24 ct 1725 -24 1712 -40 1712 -62 ct +1712 -62 1712 -62 1712 -63 ct 1712 -92 1731 -110 1790 -132 ct 1790 -132 1790 -132 1790 -61 ct +p ef +1994 -222 m 1994 -222 1994 -222 1946 -222 ct 1946 -222 1946 -222 1946 -279 ct +1946 -284 1945 -286 1942 -286 ct 1939 -281 1936 -277 1932 -272 ct 1914 -245 1893 -221 1886 -219 ct +1880 -216 1877 -212 1877 -210 ct 1877 -208 1878 -207 1879 -206 ct 1879 -206 1879 -206 1905 -206 ct +1905 -206 1905 -206 1905 -58 ct 1905 -16 1919 5 1948 5 ct 1972 5 1990 -7 2006 -33 ct +2006 -33 2006 -33 2000 -38 ct 1990 -26 1981 -21 1971 -21 ct 1953 -21 1946 -34 1946 -65 ct +1946 -65 1946 -65 1946 -206 ct 1946 -206 1946 -206 1994 -206 ct 1994 -206 1994 -206 1994 -222 ct +p ef +2096 -227 m 2096 -227 2096 -227 2021 -200 ct 2021 -200 2021 -200 2021 -192 ct +2021 -192 2021 -192 2025 -193 ct 2030 -194 2037 -194 2041 -194 ct 2053 -194 2057 -186 2057 -164 ct +2057 -164 2057 -164 2057 -49 ct 2057 -14 2052 -8 2019 -8 ct 2019 -8 2019 -8 2019 0 ct +2019 0 2019 0 2133 0 ct 2133 0 2133 0 2133 -8 ct 2102 -8 2098 -15 2098 -50 ct 2098 -50 2098 -50 2098 -225 ct +2098 -225 2098 -225 2096 -227 ct p +2073 -337 m 2060 -337 2049 -326 2049 -312 ct 2049 -298 2059 -287 2073 -287 ct +2087 -287 2098 -298 2098 -312 ct 2098 -326 2087 -337 2073 -337 ct p ef +2272 -227 m 2209 -227 2165 -180 2165 -112 ct 2165 -45 2210 5 2271 5 ct 2332 5 2379 -47 2379 -115 ct +2379 -180 2334 -227 2272 -227 ct p +2266 -213 m 2306 -213 2335 -166 2335 -98 ct 2335 -42 2313 -9 2277 -9 ct 2258 -9 2240 -21 2230 -40 ct +2216 -66 2209 -101 2209 -136 ct 2209 -183 2231 -213 2266 -213 ct p ef +2408 -196 m 2411 -198 2415 -198 2421 -198 ct 2434 -198 2439 -191 2439 -166 ct +2439 -166 2439 -166 2439 -44 ct 2439 -15 2433 -8 2409 -8 ct 2409 -8 2409 -8 2409 0 ct +2409 0 2409 0 2511 0 ct 2511 0 2511 0 2511 -8 ct 2487 -8 2479 -14 2479 -32 ct 2479 -32 2479 -32 2479 -171 ct +2503 -194 2513 -200 2529 -200 ct 2553 -200 2565 -184 2565 -152 ct 2565 -152 2565 -152 2565 -48 ct +2565 -17 2558 -8 2534 -8 ct 2534 -8 2534 -8 2534 0 ct 2534 0 2534 0 2635 0 ct 2635 0 2635 0 2635 -7 ct +2611 -10 2605 -16 2605 -40 ct 2605 -40 2605 -40 2605 -153 ct 2605 -199 2584 -227 2548 -227 ct +2526 -227 2511 -219 2478 -187 ct 2478 -187 2478 -187 2478 -226 ct 2478 -226 2478 -226 2475 -227 ct +2451 -218 2434 -213 2408 -205 ct 2408 -205 2408 -205 2408 -196 ct p ef +pom +gr +gr +gs +gs +pum +4561 12996 t +214 -32 m 206 -26 200 -23 193 -23 ct 182 -23 178 -30 178 -52 ct 178 -52 178 -52 178 -148 ct +178 -173 176 -188 168 -200 ct 158 -218 137 -227 108 -227 ct 63 -227 27 -203 27 -171 ct +27 -160 37 -150 48 -150 ct 60 -150 70 -160 70 -171 ct 70 -173 69 -175 69 -179 ct +68 -183 67 -187 67 -191 ct 67 -204 83 -215 102 -215 ct 126 -215 139 -201 139 -174 ct +139 -174 139 -174 139 -144 ct 64 -113 56 -109 35 -90 ct 25 -81 18 -64 18 -48 ct +18 -17 39 5 69 5 ct 90 5 110 -5 139 -31 ct 142 -5 151 5 170 5 ct 187 5 197 -1 214 -20 ct +214 -20 214 -20 214 -32 ct p +139 -61 m 139 -45 137 -41 126 -35 ct 115 -28 101 -24 91 -24 ct 74 -24 61 -40 61 -62 ct +61 -62 61 -62 61 -63 ct 61 -92 80 -110 139 -132 ct 139 -132 139 -132 139 -61 ct +p ef +387 5 m 387 5 387 5 458 -21 ct 458 -21 458 -21 458 -28 ct 449 -28 448 -28 447 -28 ct +429 -28 425 -33 425 -56 ct 425 -56 425 -56 425 -336 ct 425 -336 425 -336 423 -337 ct +400 -329 383 -324 352 -315 ct 352 -315 352 -315 352 -308 ct 356 -308 358 -308 362 -308 ct +380 -308 385 -303 385 -283 ct 385 -283 385 -283 385 -206 ct 366 -222 353 -227 334 -227 ct +278 -227 233 -171 233 -101 ct 233 -38 269 5 323 5 ct 350 5 368 -5 385 -28 ct 385 -28 385 -28 385 4 ct +385 4 385 4 387 5 ct p +385 -50 m 385 -47 381 -41 376 -35 ct 368 -26 356 -21 342 -21 ct 301 -21 275 -60 275 -121 ct +275 -177 298 -213 335 -213 ct 361 -213 385 -190 385 -164 ct 385 -164 385 -164 385 -50 ct +p ef +684 -32 m 676 -26 670 -23 663 -23 ct 652 -23 648 -30 648 -52 ct 648 -52 648 -52 648 -148 ct +648 -173 646 -188 638 -200 ct 628 -218 607 -227 578 -227 ct 533 -227 497 -203 497 -171 ct +497 -160 507 -150 518 -150 ct 530 -150 540 -160 540 -171 ct 540 -173 539 -175 539 -179 ct +538 -183 537 -187 537 -191 ct 537 -204 553 -215 572 -215 ct 596 -215 609 -201 609 -174 ct +609 -174 609 -174 609 -144 ct 534 -113 526 -109 505 -90 ct 495 -81 488 -64 488 -48 ct +488 -17 509 5 539 5 ct 560 5 580 -5 609 -31 ct 612 -5 621 5 640 5 ct 657 5 667 -1 684 -20 ct +684 -20 684 -20 684 -32 ct p +609 -61 m 609 -45 607 -41 596 -35 ct 585 -28 571 -24 561 -24 ct 544 -24 531 -40 531 -62 ct +531 -62 531 -62 531 -63 ct 531 -92 550 -110 609 -132 ct 609 -132 609 -132 609 -61 ct +p ef +694 -195 m 699 -195 702 -195 706 -195 ct 723 -195 726 -190 726 -167 ct 726 -167 726 -167 726 65 ct +726 90 721 96 692 99 ct 692 99 692 99 692 107 ct 692 107 692 107 810 107 ct 810 107 810 107 810 98 ct +773 98 767 93 767 61 ct 767 61 767 61 767 -16 ct 784 0 796 5 816 5 ct 873 5 918 -50 918 -122 ct +918 -183 884 -227 837 -227 ct 810 -227 788 -215 767 -189 ct 767 -189 767 -189 767 -226 ct +767 -226 767 -226 764 -227 ct 738 -217 721 -210 694 -202 ct 694 -202 694 -202 694 -195 ct +p +767 -165 m 767 -180 794 -197 816 -197 ct 852 -197 876 -160 876 -103 ct 876 -48 852 -11 817 -11 ct +795 -11 767 -29 767 -44 ct 767 -44 767 -44 767 -165 ct p ef +1063 -222 m 1063 -222 1063 -222 1015 -222 ct 1015 -222 1015 -222 1015 -279 ct +1015 -284 1014 -286 1011 -286 ct 1008 -281 1005 -277 1001 -272 ct 983 -245 962 -221 955 -219 ct +949 -216 946 -212 946 -210 ct 946 -208 947 -207 948 -206 ct 948 -206 948 -206 974 -206 ct +974 -206 974 -206 974 -58 ct 974 -16 988 5 1017 5 ct 1041 5 1059 -7 1075 -33 ct +1075 -33 1075 -33 1069 -38 ct 1059 -26 1050 -21 1040 -21 ct 1022 -21 1015 -34 1015 -65 ct +1015 -65 1015 -65 1015 -206 ct 1015 -206 1015 -206 1063 -206 ct 1063 -206 1063 -206 1063 -222 ct +p ef +1165 -227 m 1165 -227 1165 -227 1090 -200 ct 1090 -200 1090 -200 1090 -192 ct +1090 -192 1090 -192 1094 -193 ct 1099 -194 1106 -194 1110 -194 ct 1122 -194 1126 -186 1126 -164 ct +1126 -164 1126 -164 1126 -49 ct 1126 -14 1121 -8 1088 -8 ct 1088 -8 1088 -8 1088 0 ct +1088 0 1088 0 1202 0 ct 1202 0 1202 0 1202 -8 ct 1171 -8 1167 -15 1167 -50 ct 1167 -50 1167 -50 1167 -225 ct +1167 -225 1167 -225 1165 -227 ct p +1142 -337 m 1129 -337 1118 -326 1118 -312 ct 1118 -298 1128 -287 1142 -287 ct +1156 -287 1167 -298 1167 -312 ct 1167 -326 1156 -337 1142 -337 ct p ef +1450 -222 m 1450 -222 1450 -222 1383 -222 ct 1383 -222 1383 -222 1383 -215 ct +1398 -213 1405 -208 1405 -199 ct 1405 -194 1404 -189 1402 -184 ct 1402 -184 1402 -184 1355 -56 ct +1355 -56 1355 -56 1305 -182 ct 1302 -189 1301 -196 1301 -201 ct 1301 -210 1306 -213 1323 -215 ct +1323 -215 1323 -215 1323 -222 ct 1323 -222 1323 -222 1228 -222 ct 1228 -222 1228 -222 1228 -214 ct +1247 -214 1250 -209 1272 -158 ct 1272 -158 1272 -158 1330 -16 ct 1331 -13 1333 -10 1334 -6 ct +1337 3 1340 7 1343 7 ct 1346 7 1349 1 1356 -18 ct 1356 -18 1356 -18 1418 -176 ct +1433 -210 1435 -213 1450 -215 ct 1450 -215 1450 -215 1450 -222 ct p ef +1663 -81 m 1639 -43 1618 -29 1587 -29 ct 1560 -29 1539 -43 1525 -72 ct 1516 -90 1513 -107 1512 -137 ct +1512 -137 1512 -137 1661 -137 ct 1657 -169 1652 -183 1640 -199 ct 1626 -217 1603 -227 1578 -227 ct +1554 -227 1531 -218 1513 -201 ct 1490 -181 1477 -146 1477 -106 ct 1477 -37 1512 5 1568 5 ct +1614 5 1650 -24 1670 -78 ct 1670 -78 1670 -78 1663 -81 ct p +1513 -153 m 1518 -191 1535 -209 1564 -209 ct 1594 -209 1605 -196 1612 -153 ct +1612 -153 1612 -153 1513 -153 ct p ef +1958 -222 m 1958 -222 1958 -222 1898 -222 ct 1898 -222 1898 -222 1898 -279 ct +1898 -308 1907 -323 1926 -323 ct 1936 -323 1943 -318 1951 -304 ct 1959 -291 1965 -286 1973 -286 ct +1984 -286 1993 -295 1993 -306 ct 1993 -324 1972 -337 1943 -337 ct 1913 -337 1887 -324 1875 -301 ct +1862 -279 1858 -261 1858 -222 ct 1858 -222 1858 -222 1818 -222 ct 1818 -222 1818 -222 1818 -206 ct +1818 -206 1818 -206 1858 -206 ct 1858 -206 1858 -206 1858 -51 ct 1858 -14 1853 -8 1818 -8 ct +1818 -8 1818 -8 1818 0 ct 1818 0 1818 0 1944 0 ct 1944 0 1944 0 1944 -8 ct 1904 -8 1899 -13 1899 -51 ct +1899 -51 1899 -51 1899 -206 ct 1899 -206 1899 -206 1958 -206 ct 1958 -206 1958 -206 1958 -222 ct +p ef +2054 -227 m 2054 -227 2054 -227 1979 -200 ct 1979 -200 1979 -200 1979 -192 ct +1979 -192 1979 -192 1983 -193 ct 1988 -194 1995 -194 1999 -194 ct 2011 -194 2015 -186 2015 -164 ct +2015 -164 2015 -164 2015 -49 ct 2015 -14 2010 -8 1977 -8 ct 1977 -8 1977 -8 1977 0 ct +1977 0 1977 0 2091 0 ct 2091 0 2091 0 2091 -8 ct 2060 -8 2056 -15 2056 -50 ct 2056 -50 2056 -50 2056 -225 ct +2056 -225 2056 -225 2054 -227 ct p +2031 -337 m 2018 -337 2007 -326 2007 -312 ct 2007 -298 2017 -287 2031 -287 ct +2045 -287 2056 -298 2056 -312 ct 2056 -326 2045 -337 2031 -337 ct p ef +2117 -307 m 2117 -307 2117 -307 2120 -307 ct 2125 -308 2131 -308 2135 -308 ct +2151 -308 2155 -301 2155 -278 ct 2155 -278 2155 -278 2155 -42 ct 2155 -15 2149 -8 2118 -8 ct +2118 -8 2118 -8 2118 0 ct 2118 0 2118 0 2232 0 ct 2232 0 2232 0 2232 -8 ct 2202 -8 2196 -14 2196 -41 ct +2196 -41 2196 -41 2196 -336 ct 2196 -336 2196 -336 2194 -337 ct 2169 -328 2151 -323 2117 -315 ct +2117 -315 2117 -315 2117 -307 ct p ef +2367 -222 m 2367 -222 2367 -222 2319 -222 ct 2319 -222 2319 -222 2319 -279 ct +2319 -284 2318 -286 2315 -286 ct 2312 -281 2309 -277 2305 -272 ct 2287 -245 2266 -221 2259 -219 ct +2253 -216 2250 -212 2250 -210 ct 2250 -208 2251 -207 2252 -206 ct 2252 -206 2252 -206 2278 -206 ct +2278 -206 2278 -206 2278 -58 ct 2278 -16 2292 5 2321 5 ct 2345 5 2363 -7 2379 -33 ct +2379 -33 2379 -33 2373 -38 ct 2363 -26 2354 -21 2344 -21 ct 2326 -21 2319 -34 2319 -65 ct +2319 -65 2319 -65 2319 -206 ct 2319 -206 2319 -206 2367 -206 ct 2367 -206 2367 -206 2367 -222 ct +p ef +2581 -81 m 2557 -43 2536 -29 2505 -29 ct 2478 -29 2457 -43 2443 -72 ct 2434 -90 2431 -107 2430 -137 ct +2430 -137 2430 -137 2579 -137 ct 2575 -169 2570 -183 2558 -199 ct 2544 -217 2521 -227 2496 -227 ct +2472 -227 2449 -218 2431 -201 ct 2408 -181 2395 -146 2395 -106 ct 2395 -37 2430 5 2486 5 ct +2532 5 2568 -24 2588 -78 ct 2588 -78 2588 -78 2581 -81 ct p +2431 -153 m 2436 -191 2453 -209 2482 -209 ct 2512 -209 2523 -196 2530 -153 ct +2530 -153 2530 -153 2431 -153 ct p ef +2607 -192 m 2614 -194 2619 -194 2624 -194 ct 2636 -194 2641 -186 2641 -164 ct +2641 -164 2641 -164 2641 -41 ct 2641 -17 2637 -13 2606 -7 ct 2606 -7 2606 -7 2606 0 ct +2606 0 2606 0 2723 0 ct 2723 0 2723 0 2723 -8 ct 2690 -8 2681 -15 2681 -44 ct 2681 -44 2681 -44 2681 -155 ct +2681 -171 2702 -196 2715 -196 ct 2718 -196 2723 -193 2728 -188 ct 2736 -182 2741 -179 2747 -179 ct +2759 -179 2766 -187 2766 -201 ct 2766 -217 2756 -227 2740 -227 ct 2719 -227 2705 -216 2681 -181 ct +2681 -181 2681 -181 2681 -226 ct 2681 -226 2681 -226 2679 -227 ct 2653 -216 2636 -210 2607 -200 ct +2607 -200 2607 -200 2607 -192 ct p ef +pom +gr +gr +gs +gs +pum +10753 9450 t +9 -307 m 9 -307 9 -307 12 -307 ct 17 -308 23 -308 27 -308 ct 43 -308 47 -301 47 -278 ct +47 -278 47 -278 47 -42 ct 47 -15 41 -8 10 -8 ct 10 -8 10 -8 10 0 ct 10 0 10 0 124 0 ct +124 0 124 0 124 -8 ct 94 -8 88 -14 88 -41 ct 88 -41 88 -41 88 -336 ct 88 -336 88 -336 86 -337 ct +61 -328 43 -323 9 -315 ct 9 -315 9 -315 9 -307 ct p ef +256 -227 m 193 -227 149 -180 149 -112 ct 149 -45 194 5 255 5 ct 316 5 363 -47 363 -115 ct +363 -180 318 -227 256 -227 ct p +250 -213 m 290 -213 319 -166 319 -98 ct 319 -42 297 -9 261 -9 ct 242 -9 224 -21 214 -40 ct +200 -66 193 -101 193 -136 ct 193 -183 215 -213 250 -213 ct p ef +617 -25 m 617 -25 617 -25 614 -25 ct 592 -25 587 -30 587 -53 ct 587 -53 587 -53 587 -222 ct +587 -222 587 -222 510 -222 ct 510 -222 510 -222 510 -213 ct 540 -213 546 -208 546 -183 ct +546 -183 546 -183 546 -67 ct 546 -53 544 -46 537 -41 ct 524 -30 509 -24 494 -24 ct +476 -24 460 -41 460 -61 ct 460 -61 460 -61 460 -222 ct 460 -222 460 -222 389 -222 ct +389 -222 389 -222 389 -214 ct 413 -214 419 -206 419 -184 ct 419 -184 419 -184 419 -59 ct +419 -20 443 5 478 5 ct 496 5 515 -3 528 -16 ct 528 -16 528 -16 549 -38 ct 549 -38 549 -38 549 4 ct +549 4 549 4 551 5 ct 575 -5 592 -11 617 -18 ct 617 -18 617 -18 617 -25 ct p ef +798 5 m 798 5 798 5 869 -21 ct 869 -21 869 -21 869 -28 ct 860 -28 859 -28 858 -28 ct +840 -28 836 -33 836 -56 ct 836 -56 836 -56 836 -336 ct 836 -336 836 -336 834 -337 ct +811 -329 794 -324 763 -315 ct 763 -315 763 -315 763 -308 ct 767 -308 769 -308 773 -308 ct +791 -308 796 -303 796 -283 ct 796 -283 796 -283 796 -206 ct 777 -222 764 -227 745 -227 ct +689 -227 644 -171 644 -101 ct 644 -38 680 5 734 5 ct 761 5 779 -5 796 -28 ct 796 -28 796 -28 796 4 ct +796 4 796 4 798 5 ct p +796 -50 m 796 -47 792 -41 787 -35 ct 779 -26 767 -21 753 -21 ct 712 -21 686 -60 686 -121 ct +686 -177 709 -213 746 -213 ct 772 -213 796 -190 796 -164 ct 796 -164 796 -164 796 -50 ct +p ef +1034 -155 m 1034 -155 1034 -155 1032 -222 ct 1032 -222 1032 -222 1026 -222 ct +1026 -222 1026 -222 1025 -221 ct 1021 -218 1020 -217 1018 -217 ct 1016 -217 1011 -218 1005 -221 ct +995 -225 984 -227 972 -227 ct 933 -227 906 -202 906 -166 ct 906 -138 921 -118 962 -95 ct +962 -95 962 -95 990 -78 ct 1007 -69 1016 -57 1016 -41 ct 1016 -20 1000 -6 975 -6 ct +959 -6 944 -12 935 -23 ct 925 -35 920 -47 914 -75 ct 914 -75 914 -75 906 -75 ct +906 -75 906 -75 906 2 ct 906 2 906 2 912 2 ct 916 -3 918 -4 924 -4 ct 928 -4 935 -3 946 0 ct +959 3 973 5 981 5 ct 1018 5 1049 -24 1049 -58 ct 1049 -83 1038 -99 1009 -117 ct +1009 -117 1009 -117 957 -148 ct 943 -156 936 -169 936 -182 ct 936 -202 951 -216 973 -216 ct +1001 -216 1015 -199 1026 -155 ct 1026 -155 1026 -155 1034 -155 ct p ef +1079 -195 m 1084 -195 1087 -195 1091 -195 ct 1108 -195 1111 -190 1111 -167 ct +1111 -167 1111 -167 1111 65 ct 1111 90 1106 96 1077 99 ct 1077 99 1077 99 1077 107 ct +1077 107 1077 107 1195 107 ct 1195 107 1195 107 1195 98 ct 1158 98 1152 93 1152 61 ct +1152 61 1152 61 1152 -16 ct 1169 0 1181 5 1201 5 ct 1258 5 1303 -50 1303 -122 ct +1303 -183 1269 -227 1222 -227 ct 1195 -227 1173 -215 1152 -189 ct 1152 -189 1152 -189 1152 -226 ct +1152 -226 1152 -226 1149 -227 ct 1123 -217 1106 -210 1079 -202 ct 1079 -202 1079 -202 1079 -195 ct +p +1152 -165 m 1152 -180 1179 -197 1201 -197 ct 1237 -197 1261 -160 1261 -103 ct +1261 -48 1237 -11 1202 -11 ct 1180 -11 1152 -29 1152 -44 ct 1152 -44 1152 -44 1152 -165 ct +p ef +1523 -81 m 1499 -43 1478 -29 1447 -29 ct 1420 -29 1399 -43 1385 -72 ct 1376 -90 1373 -107 1372 -137 ct +1372 -137 1372 -137 1521 -137 ct 1517 -169 1512 -183 1500 -199 ct 1486 -217 1463 -227 1438 -227 ct +1414 -227 1391 -218 1373 -201 ct 1350 -181 1337 -146 1337 -106 ct 1337 -37 1372 5 1428 5 ct +1474 5 1510 -24 1530 -78 ct 1530 -78 1530 -78 1523 -81 ct p +1373 -153 m 1378 -191 1395 -209 1424 -209 ct 1454 -209 1465 -196 1472 -153 ct +1472 -153 1472 -153 1373 -153 ct p ef +1759 -32 m 1751 -26 1745 -23 1738 -23 ct 1727 -23 1723 -30 1723 -52 ct 1723 -52 1723 -52 1723 -148 ct +1723 -173 1721 -188 1713 -200 ct 1703 -218 1682 -227 1653 -227 ct 1608 -227 1572 -203 1572 -171 ct +1572 -160 1582 -150 1593 -150 ct 1605 -150 1615 -160 1615 -171 ct 1615 -173 1614 -175 1614 -179 ct +1613 -183 1612 -187 1612 -191 ct 1612 -204 1628 -215 1647 -215 ct 1671 -215 1684 -201 1684 -174 ct +1684 -174 1684 -174 1684 -144 ct 1609 -113 1601 -109 1580 -90 ct 1570 -81 1563 -64 1563 -48 ct +1563 -17 1584 5 1614 5 ct 1635 5 1655 -5 1684 -31 ct 1687 -5 1696 5 1715 5 ct 1732 5 1742 -1 1759 -20 ct +1759 -20 1759 -20 1759 -32 ct p +1684 -61 m 1684 -45 1682 -41 1671 -35 ct 1660 -28 1646 -24 1636 -24 ct 1619 -24 1606 -40 1606 -62 ct +1606 -62 1606 -62 1606 -63 ct 1606 -92 1625 -110 1684 -132 ct 1684 -132 1684 -132 1684 -61 ct +p ef +1768 -307 m 1775 -307 1779 -308 1784 -308 ct 1800 -308 1805 -302 1805 -278 ct +1805 -278 1805 -278 1805 -40 ct 1805 -15 1803 -13 1768 -7 ct 1768 -7 1768 -7 1768 0 ct +1768 0 1768 0 1882 0 ct 1882 0 1882 0 1882 -8 ct 1882 -8 1882 -8 1872 -8 ct 1853 -8 1845 -15 1845 -32 ct +1845 -32 1845 -32 1845 -124 ct 1845 -124 1845 -124 1913 -32 ct 1913 -32 1913 -32 1915 -30 ct +1916 -28 1917 -27 1918 -25 ct 1922 -20 1923 -17 1923 -15 ct 1923 -10 1919 -7 1913 -7 ct +1913 -7 1913 -7 1904 -7 ct 1904 -7 1904 -7 1904 0 ct 1904 0 1904 0 2009 0 ct 2009 0 2009 0 2009 -8 ct +1988 -8 1973 -18 1953 -43 ct 1953 -43 1953 -43 1879 -139 ct 1879 -139 1879 -139 1893 -152 ct +1927 -185 1957 -208 1971 -212 ct 1979 -214 1985 -215 1994 -215 ct 1994 -215 1994 -215 1997 -215 ct +1997 -215 1997 -215 1997 -222 ct 1997 -222 1997 -222 1899 -222 ct 1899 -222 1899 -222 1899 -215 ct +1918 -215 1923 -213 1923 -206 ct 1923 -202 1918 -195 1912 -189 ct 1912 -189 1912 -189 1845 -129 ct +1845 -129 1845 -129 1845 -336 ct 1845 -336 1845 -336 1843 -337 ct 1825 -331 1811 -327 1783 -319 ct +1783 -319 1783 -319 1768 -315 ct 1768 -315 1768 -315 1768 -307 ct p ef +2217 -81 m 2193 -43 2172 -29 2141 -29 ct 2114 -29 2093 -43 2079 -72 ct 2070 -90 2067 -107 2066 -137 ct +2066 -137 2066 -137 2215 -137 ct 2211 -169 2206 -183 2194 -199 ct 2180 -217 2157 -227 2132 -227 ct +2108 -227 2085 -218 2067 -201 ct 2044 -181 2031 -146 2031 -106 ct 2031 -37 2066 5 2122 5 ct +2168 5 2204 -24 2224 -78 ct 2224 -78 2224 -78 2217 -81 ct p +2067 -153 m 2072 -191 2089 -209 2118 -209 ct 2148 -209 2159 -196 2166 -153 ct +2166 -153 2166 -153 2067 -153 ct p ef +2242 -192 m 2249 -194 2254 -194 2259 -194 ct 2271 -194 2276 -186 2276 -164 ct +2276 -164 2276 -164 2276 -41 ct 2276 -17 2272 -13 2241 -7 ct 2241 -7 2241 -7 2241 0 ct +2241 0 2241 0 2358 0 ct 2358 0 2358 0 2358 -8 ct 2325 -8 2316 -15 2316 -44 ct 2316 -44 2316 -44 2316 -155 ct +2316 -171 2337 -196 2350 -196 ct 2353 -196 2358 -193 2363 -188 ct 2371 -182 2376 -179 2382 -179 ct +2394 -179 2401 -187 2401 -201 ct 2401 -217 2391 -227 2375 -227 ct 2354 -227 2340 -216 2316 -181 ct +2316 -181 2316 -181 2316 -226 ct 2316 -226 2316 -226 2314 -227 ct 2288 -216 2271 -210 2242 -200 ct +2242 -200 2242 -200 2242 -192 ct p ef +pom +gr +gr +gs +gs +pum +4619 16250 t +121 -227 m 58 -227 14 -180 14 -112 ct 14 -45 59 5 120 5 ct 181 5 228 -47 228 -115 ct +228 -180 183 -227 121 -227 ct p +115 -213 m 155 -213 184 -166 184 -98 ct 184 -42 162 -9 126 -9 ct 107 -9 89 -21 79 -40 ct +65 -66 58 -101 58 -136 ct 58 -183 80 -213 115 -213 ct p ef +482 -25 m 482 -25 482 -25 479 -25 ct 457 -25 452 -30 452 -53 ct 452 -53 452 -53 452 -222 ct +452 -222 452 -222 375 -222 ct 375 -222 375 -222 375 -213 ct 405 -213 411 -208 411 -183 ct +411 -183 411 -183 411 -67 ct 411 -53 409 -46 402 -41 ct 389 -30 374 -24 359 -24 ct +341 -24 325 -41 325 -61 ct 325 -61 325 -61 325 -222 ct 325 -222 325 -222 254 -222 ct +254 -222 254 -222 254 -214 ct 278 -214 284 -206 284 -184 ct 284 -184 284 -184 284 -59 ct +284 -20 308 5 343 5 ct 361 5 380 -3 393 -16 ct 393 -16 393 -16 414 -38 ct 414 -38 414 -38 414 4 ct +414 4 414 4 416 5 ct 440 -5 457 -11 482 -18 ct 482 -18 482 -18 482 -25 ct p ef +618 -222 m 618 -222 618 -222 570 -222 ct 570 -222 570 -222 570 -279 ct 570 -284 569 -286 566 -286 ct +563 -281 560 -277 556 -272 ct 538 -245 517 -221 510 -219 ct 504 -216 501 -212 501 -210 ct +501 -208 502 -207 503 -206 ct 503 -206 503 -206 529 -206 ct 529 -206 529 -206 529 -58 ct +529 -16 543 5 572 5 ct 596 5 614 -7 630 -33 ct 630 -33 630 -33 624 -38 ct 614 -26 605 -21 595 -21 ct +577 -21 570 -34 570 -65 ct 570 -65 570 -65 570 -206 ct 570 -206 570 -206 618 -206 ct +618 -206 618 -206 618 -222 ct p ef +639 -195 m 644 -195 647 -195 651 -195 ct 668 -195 671 -190 671 -167 ct 671 -167 671 -167 671 65 ct +671 90 666 96 637 99 ct 637 99 637 99 637 107 ct 637 107 637 107 755 107 ct 755 107 755 107 755 98 ct +718 98 712 93 712 61 ct 712 61 712 61 712 -16 ct 729 0 741 5 761 5 ct 818 5 863 -50 863 -122 ct +863 -183 829 -227 782 -227 ct 755 -227 733 -215 712 -189 ct 712 -189 712 -189 712 -226 ct +712 -226 712 -226 709 -227 ct 683 -217 666 -210 639 -202 ct 639 -202 639 -202 639 -195 ct +p +712 -165 m 712 -180 739 -197 761 -197 ct 797 -197 821 -160 821 -103 ct 821 -48 797 -11 762 -11 ct +740 -11 712 -29 712 -44 ct 712 -44 712 -44 712 -165 ct p ef +1117 -25 m 1117 -25 1117 -25 1114 -25 ct 1092 -25 1087 -30 1087 -53 ct 1087 -53 1087 -53 1087 -222 ct +1087 -222 1087 -222 1010 -222 ct 1010 -222 1010 -222 1010 -213 ct 1040 -213 1046 -208 1046 -183 ct +1046 -183 1046 -183 1046 -67 ct 1046 -53 1044 -46 1037 -41 ct 1024 -30 1009 -24 994 -24 ct +976 -24 960 -41 960 -61 ct 960 -61 960 -61 960 -222 ct 960 -222 960 -222 889 -222 ct +889 -222 889 -222 889 -214 ct 913 -214 919 -206 919 -184 ct 919 -184 919 -184 919 -59 ct +919 -20 943 5 978 5 ct 996 5 1015 -3 1028 -16 ct 1028 -16 1028 -16 1049 -38 ct +1049 -38 1049 -38 1049 4 ct 1049 4 1049 4 1051 5 ct 1075 -5 1092 -11 1117 -18 ct +1117 -18 1117 -18 1117 -25 ct p ef +1253 -222 m 1253 -222 1253 -222 1205 -222 ct 1205 -222 1205 -222 1205 -279 ct +1205 -284 1204 -286 1201 -286 ct 1198 -281 1195 -277 1191 -272 ct 1173 -245 1152 -221 1145 -219 ct +1139 -216 1136 -212 1136 -210 ct 1136 -208 1137 -207 1138 -206 ct 1138 -206 1138 -206 1164 -206 ct +1164 -206 1164 -206 1164 -58 ct 1164 -16 1178 5 1207 5 ct 1231 5 1249 -7 1265 -33 ct +1265 -33 1265 -33 1259 -38 ct 1249 -26 1240 -21 1230 -21 ct 1212 -21 1205 -34 1205 -65 ct +1205 -65 1205 -65 1205 -206 ct 1205 -206 1205 -206 1253 -206 ct 1253 -206 1253 -206 1253 -222 ct +p ef +pom +gr +gs +pum +4138 16851 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +288 -222 m 288 -222 288 -222 240 -222 ct 240 -222 240 -222 240 -279 ct 240 -284 239 -286 236 -286 ct +233 -281 230 -277 226 -272 ct 208 -245 187 -221 180 -219 ct 174 -216 171 -212 171 -210 ct +171 -208 172 -207 173 -206 ct 173 -206 173 -206 199 -206 ct 199 -206 199 -206 199 -58 ct +199 -16 213 5 242 5 ct 266 5 284 -7 300 -33 ct 300 -33 300 -33 294 -38 ct 284 -26 275 -21 265 -21 ct +247 -21 240 -34 240 -65 ct 240 -65 240 -65 240 -206 ct 240 -206 240 -206 288 -206 ct +288 -206 288 -206 288 -222 ct p ef +426 -227 m 363 -227 319 -180 319 -112 ct 319 -45 364 5 425 5 ct 486 5 533 -47 533 -115 ct +533 -180 488 -227 426 -227 ct p +420 -213 m 460 -213 489 -166 489 -98 ct 489 -42 467 -9 431 -9 ct 412 -9 394 -21 384 -40 ct +370 -66 363 -101 363 -136 ct 363 -183 385 -213 420 -213 ct p ef +827 -222 m 827 -222 827 -222 767 -222 ct 767 -222 767 -222 767 -279 ct 767 -308 776 -323 795 -323 ct +805 -323 812 -318 820 -304 ct 828 -291 834 -286 842 -286 ct 853 -286 862 -295 862 -306 ct +862 -324 841 -337 812 -337 ct 782 -337 756 -324 744 -301 ct 731 -279 727 -261 727 -222 ct +727 -222 727 -222 687 -222 ct 687 -222 687 -222 687 -206 ct 687 -206 687 -206 727 -206 ct +727 -206 727 -206 727 -51 ct 727 -14 722 -8 687 -8 ct 687 -8 687 -8 687 0 ct 687 0 687 0 813 0 ct +813 0 813 0 813 -8 ct 773 -8 768 -13 768 -51 ct 768 -51 768 -51 768 -206 ct 768 -206 768 -206 827 -206 ct +827 -206 827 -206 827 -222 ct p ef +1052 -32 m 1044 -26 1038 -23 1031 -23 ct 1020 -23 1016 -30 1016 -52 ct 1016 -52 1016 -52 1016 -148 ct +1016 -173 1014 -188 1006 -200 ct 996 -218 975 -227 946 -227 ct 901 -227 865 -203 865 -171 ct +865 -160 875 -150 886 -150 ct 898 -150 908 -160 908 -171 ct 908 -173 907 -175 907 -179 ct +906 -183 905 -187 905 -191 ct 905 -204 921 -215 940 -215 ct 964 -215 977 -201 977 -174 ct +977 -174 977 -174 977 -144 ct 902 -113 894 -109 873 -90 ct 863 -81 856 -64 856 -48 ct +856 -17 877 5 907 5 ct 928 5 948 -5 977 -31 ct 980 -5 989 5 1008 5 ct 1025 5 1035 -1 1052 -20 ct +1052 -20 1052 -20 1052 -32 ct p +977 -61 m 977 -45 975 -41 964 -35 ct 953 -28 939 -24 929 -24 ct 912 -24 899 -40 899 -62 ct +899 -62 899 -62 899 -63 ct 899 -92 918 -110 977 -132 ct 977 -132 977 -132 977 -61 ct +p ef +1061 -192 m 1068 -194 1073 -194 1078 -194 ct 1090 -194 1095 -186 1095 -164 ct +1095 -164 1095 -164 1095 -41 ct 1095 -17 1091 -13 1060 -7 ct 1060 -7 1060 -7 1060 0 ct +1060 0 1060 0 1177 0 ct 1177 0 1177 0 1177 -8 ct 1144 -8 1135 -15 1135 -44 ct 1135 -44 1135 -44 1135 -155 ct +1135 -171 1156 -196 1169 -196 ct 1172 -196 1177 -193 1182 -188 ct 1190 -182 1195 -179 1201 -179 ct +1213 -179 1220 -187 1220 -201 ct 1220 -217 1210 -227 1194 -227 ct 1173 -227 1159 -216 1135 -181 ct +1135 -181 1135 -181 1135 -226 ct 1135 -226 1135 -226 1133 -227 ct 1107 -216 1090 -210 1061 -200 ct +1061 -200 1061 -200 1061 -192 ct p ef +1544 -81 m 1520 -43 1499 -29 1468 -29 ct 1441 -29 1420 -43 1406 -72 ct 1397 -90 1394 -107 1393 -137 ct +1393 -137 1393 -137 1542 -137 ct 1538 -169 1533 -183 1521 -199 ct 1507 -217 1484 -227 1459 -227 ct +1435 -227 1412 -218 1394 -201 ct 1371 -181 1358 -146 1358 -106 ct 1358 -37 1393 5 1449 5 ct +1495 5 1531 -24 1551 -78 ct 1551 -78 1551 -78 1544 -81 ct p +1394 -153 m 1399 -191 1416 -209 1445 -209 ct 1475 -209 1486 -196 1493 -153 ct +1493 -153 1493 -153 1394 -153 ct p ef +1574 -196 m 1577 -198 1581 -198 1587 -198 ct 1600 -198 1605 -191 1605 -166 ct +1605 -166 1605 -166 1605 -44 ct 1605 -15 1599 -8 1575 -8 ct 1575 -8 1575 -8 1575 0 ct +1575 0 1575 0 1677 0 ct 1677 0 1677 0 1677 -8 ct 1653 -8 1645 -14 1645 -32 ct 1645 -32 1645 -32 1645 -171 ct +1669 -194 1679 -200 1695 -200 ct 1719 -200 1731 -184 1731 -152 ct 1731 -152 1731 -152 1731 -48 ct +1731 -17 1724 -8 1700 -8 ct 1700 -8 1700 -8 1700 0 ct 1700 0 1700 0 1801 0 ct 1801 0 1801 0 1801 -7 ct +1777 -10 1771 -16 1771 -40 ct 1771 -40 1771 -40 1771 -153 ct 1771 -199 1750 -227 1714 -227 ct +1692 -227 1677 -219 1644 -187 ct 1644 -187 1644 -187 1644 -226 ct 1644 -226 1644 -226 1641 -227 ct +1617 -218 1600 -213 1574 -205 ct 1574 -205 1574 -205 1574 -196 ct p ef +1983 5 m 1983 5 1983 5 2054 -21 ct 2054 -21 2054 -21 2054 -28 ct 2045 -28 2044 -28 2043 -28 ct +2025 -28 2021 -33 2021 -56 ct 2021 -56 2021 -56 2021 -336 ct 2021 -336 2021 -336 2019 -337 ct +1996 -329 1979 -324 1948 -315 ct 1948 -315 1948 -315 1948 -308 ct 1952 -308 1954 -308 1958 -308 ct +1976 -308 1981 -303 1981 -283 ct 1981 -283 1981 -283 1981 -206 ct 1962 -222 1949 -227 1930 -227 ct +1874 -227 1829 -171 1829 -101 ct 1829 -38 1865 5 1919 5 ct 1946 5 1964 -5 1981 -28 ct +1981 -28 1981 -28 1981 4 ct 1981 4 1981 4 1983 5 ct p +1981 -50 m 1981 -47 1977 -41 1972 -35 ct 1964 -26 1952 -21 1938 -21 ct 1897 -21 1871 -60 1871 -121 ct +1871 -177 1894 -213 1931 -213 ct 1957 -213 1981 -190 1981 -164 ct 1981 -164 1981 -164 1981 -50 ct +p ef +2084 87 m 2120 64 2135 51 2153 28 ct 2187 -15 2204 -64 2204 -122 ct 2204 -185 2186 -233 2143 -283 ct +2124 -307 2111 -318 2086 -334 ct 2086 -334 2086 -334 2080 -326 ct 2119 -295 2132 -277 2145 -240 ct +2157 -207 2162 -170 2162 -120 ct 2162 -69 2156 -28 2143 2 ct 2129 33 2115 51 2080 79 ct +2080 79 2080 79 2084 87 ct p ef +pom +gr +gr +gs +gs +pum +8742 14319 t +7 -199 m 14 -200 17 -201 23 -201 ct 51 -201 58 -188 81 -103 ct 89 -71 101 -13 101 -4 ct +101 4 98 11 91 20 ct 76 41 66 54 60 59 ct 50 70 44 74 38 74 ct 35 74 31 73 26 69 ct +18 63 13 60 7 60 ct -3 60 -12 69 -12 80 ct -12 92 -1 102 13 102 ct 45 102 110 27 163 -71 ct +197 -131 210 -167 210 -191 ct 210 -206 198 -219 183 -219 ct 172 -219 164 -211 164 -200 ct +164 -193 168 -188 178 -181 ct 187 -176 191 -171 191 -164 ct 191 -145 172 -106 130 -36 ct +130 -36 130 -36 121 -94 ct 113 -137 85 -219 78 -219 ct 78 -219 78 -219 76 -219 ct +76 -218 74 -218 72 -218 ct 67 -217 49 -214 23 -209 ct 21 -209 14 -208 7 -207 ct +7 -207 7 -207 7 -199 ct p ef +pom +gr +gs +pum +8962 14319 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +9127 14319 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +9377 14319 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +gs +gs +pum +8742 14186 t +45 -147 m 114 -290 l 183 -147 l 216 -147 l 128 -327 l 99 -327 l 12 -147 l +45 -147 l p ef +pom +gr +gr +gs +gs +pum +14351 14292 t +7 -199 m 14 -200 17 -201 23 -201 ct 51 -201 58 -188 81 -103 ct 89 -71 101 -13 101 -4 ct +101 4 98 11 91 20 ct 76 41 66 54 60 59 ct 50 70 44 74 38 74 ct 35 74 31 73 26 69 ct +18 63 13 60 7 60 ct -3 60 -12 69 -12 80 ct -12 92 -1 102 13 102 ct 45 102 110 27 163 -71 ct +197 -131 210 -167 210 -191 ct 210 -206 198 -219 183 -219 ct 172 -219 164 -211 164 -200 ct +164 -193 168 -188 178 -181 ct 187 -176 191 -171 191 -164 ct 191 -145 172 -106 130 -36 ct +130 -36 130 -36 121 -94 ct 113 -137 85 -219 78 -219 ct 78 -219 78 -219 76 -219 ct +76 -218 74 -218 72 -218 ct 67 -217 49 -214 23 -209 ct 21 -209 14 -208 7 -207 ct +7 -207 7 -207 7 -199 ct p ef +pom +gr +gs +pum +14571 14292 t +143 -334 m 107 -310 92 -297 75 -274 ct 40 -231 23 -182 23 -124 ct 23 -62 41 -13 84 37 ct +104 61 116 72 141 87 ct 141 87 141 87 147 79 ct 108 48 95 31 82 -6 ct 70 -39 65 -76 65 -126 ct +65 -178 71 -218 84 -249 ct 98 -279 112 -297 147 -326 ct 147 -326 147 -326 143 -334 ct +p ef +pom +gr +gs +pum +14736 14292 t +227 -58 m 227 -58 227 -58 217 -45 ct 203 -27 194 -19 187 -19 ct 183 -19 179 -23 179 -27 ct +179 -31 179 -31 186 -58 ct 186 -58 186 -58 214 -160 ct 216 -170 218 -181 218 -188 ct +218 -206 205 -218 186 -218 ct 154 -218 123 -189 72 -110 ct 72 -110 72 -110 105 -217 ct +105 -217 105 -217 104 -218 ct 77 -213 67 -211 24 -203 ct 24 -203 24 -203 24 -195 ct +49 -195 55 -192 55 -182 ct 55 -179 55 -176 54 -173 ct 54 -173 54 -173 7 0 ct 7 0 7 0 44 0 ct +67 -78 72 -89 93 -123 ct 123 -168 148 -193 166 -193 ct 174 -193 178 -188 178 -179 ct +178 -173 175 -156 171 -141 ct 171 -141 171 -141 150 -60 ct 143 -35 142 -28 142 -23 ct +142 -4 149 4 165 4 ct 187 4 200 -6 234 -52 ct 234 -52 234 -52 227 -58 ct p ef +pom +gr +gs +pum +14986 14292 t +18 87 m 54 64 69 51 87 28 ct 121 -15 138 -64 138 -122 ct 138 -185 120 -233 77 -283 ct +58 -307 45 -318 20 -334 ct 20 -334 20 -334 14 -326 ct 53 -295 66 -277 79 -240 ct +91 -207 96 -170 96 -120 ct 96 -69 90 -28 77 2 ct 63 33 49 51 14 79 ct 14 79 14 79 18 87 ct +p ef +pom +gr +gr +tm setmatrix +0 0 t +1 1 s +0 8286 t +pom +count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore +%%PageTrailer +%%Trailer +%%EOF diff --git a/native/codec/libraries/speex/doc/echo_path.odg b/native/codec/libraries/speex/doc/echo_path.odg new file mode 100644 index 0000000..460af84 Binary files /dev/null and b/native/codec/libraries/speex/doc/echo_path.odg differ diff --git a/native/codec/libraries/speex/doc/manual.lyx b/native/codec/libraries/speex/doc/manual.lyx new file mode 100644 index 0000000..fa980a4 --- /dev/null +++ b/native/codec/libraries/speex/doc/manual.lyx @@ -0,0 +1,12085 @@ +#LyX 1.6.1 created this file. For more info see http://www.lyx.org/ +\lyxformat 345 +\begin_document +\begin_header +\textclass scrbook +\use_default_options true +\language english +\inputencoding auto +\font_roman default +\font_sans default +\font_typewriter default +\font_default_family default +\font_sc false +\font_osf false +\font_sf_scale 100 +\font_tt_scale 100 + +\graphics default +\paperfontsize 10 +\spacing single +\use_hyperref false +\papersize letterpaper +\use_geometry true +\use_amsmath 2 +\use_esint 2 +\cite_engine basic +\use_bibtopic false +\paperorientation portrait +\leftmargin 2cm +\topmargin 2cm +\rightmargin 2cm +\bottommargin 2cm +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\defskip medskip +\quotes_language english +\papercolumns 1 +\papersides 1 +\paperpagestyle headings +\tracking_changes false +\output_changes false +\author "" +\author "" +\end_header + +\begin_body + +\begin_layout Title +The Speex Manual +\begin_inset Newline newline +\end_inset + +Version 1.2 +\end_layout + +\begin_layout Author +Jean-Marc Valin +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Standard +Copyright +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +copyright +\end_layout + +\end_inset + + 2002-2008 Jean-Marc Valin/Xiph.org Foundation +\end_layout + +\begin_layout Standard +Permission is granted to copy, distribute and/or modify this document under + the terms of the GNU Free Documentation License, Version 1.1 or any later + version published by the Free Software Foundation; with no Invariant Section, + with no Front-Cover Texts, and with no Back-Cover. + A copy of the license is included in the section entitled "GNU Free Documentati +on License". + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\begin_inset CommandInset toc +LatexCommand tableofcontents + +\end_inset + + +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset FloatList table + +\end_inset + + +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Introduction to Speex +\end_layout + +\begin_layout Standard +The Speex codec ( +\family typewriter +http://www.speex.org/ +\family default +) exists because there is a need for a speech codec that is open-source + and free from software patent royalties. + These are essential conditions for being usable in any open-source software. + In essence, Speex is to speech what Vorbis is to audio/music. + Unlike many other speech codecs, Speex is not designed for mobile phones + but rather for packet networks and voice over IP (VoIP) applications. + File-based compression is of course also supported. + +\end_layout + +\begin_layout Standard +The Speex codec is designed to be very flexible and support a wide range + of speech quality and bit-rate. + Support for very good quality speech also means that Speex can encode wideband + speech (16 kHz sampling rate) in addition to narrowband speech (telephone + quality, 8 kHz sampling rate). +\end_layout + +\begin_layout Standard +Designing for VoIP instead of mobile phones means that Speex is robust to + lost packets, but not to corrupted ones. + This is based on the assumption that in VoIP, packets either arrive unaltered + or don't arrive at all. + Because Speex is targeted at a wide range of devices, it has modest (adjustable +) complexity and a small memory footprint. +\end_layout + +\begin_layout Standard +All the design goals led to the choice of CELP +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +CELP +\end_layout + +\end_inset + + as the encoding technique. + One of the main reasons is that CELP has long proved that it could work + reliably and scale well to both low bit-rates (e.g. + DoD CELP @ 4.8 kbps) and high bit-rates (e.g. + G.728 @ 16 kbps). + +\end_layout + +\begin_layout Section +Getting help +\begin_inset CommandInset label +LatexCommand label +name "sec:Getting-help" + +\end_inset + + +\end_layout + +\begin_layout Standard +As for many open source projects, there are many ways to get help with Speex. + These include: +\end_layout + +\begin_layout Itemize +This manual +\end_layout + +\begin_layout Itemize +Other documentation on the Speex website (http://www.speex.org/) +\end_layout + +\begin_layout Itemize +Mailing list: Discuss any Speex-related topic on speex-dev@xiph.org (not + just for developers) +\end_layout + +\begin_layout Itemize +IRC: The main channel is #speex on irc.freenode.net. + Note that due to time differences, it may take a while to get someone, + so please be patient. +\end_layout + +\begin_layout Itemize +Email the author privately at jean-marc.valin@usherbrooke.ca +\series bold +only +\series default + for private/delicate topics you do not wish to discuss publicly. +\end_layout + +\begin_layout Standard +Before asking for help (mailing list or IRC), +\series bold +it is important to first read this manual +\series default + (OK, so if you made it here it's already a good sign). + It is generally considered rude to ask on a mailing list about topics that + are clearly detailed in the documentation. + On the other hand, it's perfectly OK (and encouraged) to ask for clarifications + about something covered in the manual. + This manual does not (yet) cover everything about Speex, so everyone is + encouraged to ask questions, send comments, feature requests, or just let + us know how Speex is being used. + +\end_layout + +\begin_layout Standard +Here are some additional guidelines related to the mailing list. + Before reporting bugs in Speex to the list, it is strongly recommended + (if possible) to first test whether these bugs can be reproduced using + the speexenc and speexdec (see Section +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Command-line-encoder/decoder" + +\end_inset + +) command-line utilities. + Bugs reported based on 3rd party code are both harder to find and far too + often caused by errors that have nothing to do with Speex. + +\end_layout + +\begin_layout Section +About this document +\end_layout + +\begin_layout Standard +This document is divided in the following way. + Section +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Feature-description" + +\end_inset + + describes the different Speex features and defines many basic terms that + are used throughout this manual. + Section +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Command-line-encoder/decoder" + +\end_inset + + documents the standard command-line tools provided in the Speex distribution. + Section +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Programming-with-Speex" + +\end_inset + + includes detailed instructions about programming using the libspeex +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +libspeex +\end_layout + +\end_inset + + API. + Section +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Formats-and-standards" + +\end_inset + + has some information related to Speex and standards. + +\end_layout + +\begin_layout Standard +The three last sections describe the algorithms used in Speex. + These sections require signal processing knowledge, but are not required + for merely using Speex. + They are intended for people who want to understand how Speex really works + and/or want to do research based on Speex. + Section +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Introduction-to-CELP" + +\end_inset + + explains the general idea behind CELP, while sections +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Speex-narrowband-mode" + +\end_inset + + and +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Speex-wideband-mode" + +\end_inset + + are specific to Speex. +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Codec description +\begin_inset CommandInset label +LatexCommand label +name "sec:Feature-description" + +\end_inset + + +\end_layout + +\begin_layout Standard +This section describes Speex and its features into more details. +\end_layout + +\begin_layout Section +Concepts +\end_layout + +\begin_layout Standard +Before introducing all the Speex features, here are some concepts in speech + coding that help better understand the rest of the manual. + Although some are general concepts in speech/audio processing, others are + specific to Speex. +\end_layout + +\begin_layout Subsection* +Sampling rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +sampling rate +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The sampling rate expressed in Hertz (Hz) is the number of samples taken + from a signal per second. + For a sampling rate of +\begin_inset Formula $F_{s}$ +\end_inset + + kHz, the highest frequency that can be represented is equal to +\begin_inset Formula $F_{s}/2$ +\end_inset + + kHz ( +\begin_inset Formula $F_{s}/2$ +\end_inset + + is known as the Nyquist frequency). + This is a fundamental property in signal processing and is described by + the sampling theorem. + Speex is mainly designed for three different sampling rates: 8 kHz, 16 + kHz, and 32 kHz. + These are respectively referred to as narrowband +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +narrowband +\end_layout + +\end_inset + +, wideband +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +wideband +\end_layout + +\end_inset + + and ultra-wideband +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +ultra-wideband +\end_layout + +\end_inset + +. + +\end_layout + +\begin_layout Subsection* +Bit-rate +\end_layout + +\begin_layout Standard +When encoding a speech signal, the bit-rate is defined as the number of + bits per unit of time required to encode the speech. + It is measured in +\emph on +bits per second +\emph default + (bps), or generally +\emph on +kilobits per second +\emph default +. + It is important to make the distinction between +\emph on +kilo +\series bold +bits +\series default +\emph default + +\emph on +per second +\emph default + (k +\series bold +b +\series default +ps) and +\emph on +kilo +\series bold +bytes +\series default +\emph default + +\emph on +per second +\emph default + (k +\series bold +B +\series default +ps). +\end_layout + +\begin_layout Subsection* +Quality +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +quality +\end_layout + +\end_inset + + (variable) +\end_layout + +\begin_layout Standard +Speex is a lossy codec, which means that it achieves compression at the + expense of fidelity of the input speech signal. + Unlike some other speech codecs, it is possible to control the trade-off + made between quality and bit-rate. + The Speex encoding process is controlled most of the time by a quality + parameter that ranges from 0 to 10. + In constant bit-rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +constant bit-rate +\end_layout + +\end_inset + + (CBR) operation, the quality parameter is an integer, while for variable + bit-rate (VBR), the parameter is a float. + +\end_layout + +\begin_layout Subsection* +Complexity +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +complexity +\end_layout + +\end_inset + + (variable) +\end_layout + +\begin_layout Standard +With Speex, it is possible to vary the complexity allowed for the encoder. + This is done by controlling how the search is performed with an integer + ranging from 1 to 10 in a way that's similar to the -1 to -9 options to + +\emph on +gzip +\emph default + and +\emph on +bzip2 +\emph default + compression utilities. + For normal use, the noise level at complexity 1 is between 1 and 2 dB higher + than at complexity 10, but the CPU requirements for complexity 10 is about + 5 times higher than for complexity 1. + In practice, the best trade-off is between complexity 2 and 4, though higher + settings are often useful when encoding non-speech sounds like DTMF +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +DTMF +\end_layout + +\end_inset + + tones. +\end_layout + +\begin_layout Subsection* +Variable Bit-Rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +variable bit-rate +\end_layout + +\end_inset + + (VBR) +\end_layout + +\begin_layout Standard +Variable bit-rate (VBR) allows a codec to change its bit-rate dynamically + to adapt to the +\begin_inset Quotes eld +\end_inset + +difficulty +\begin_inset Quotes erd +\end_inset + + of the audio being encoded. + In the example of Speex, sounds like vowels and high-energy transients + require a higher bit-rate to achieve good quality, while fricatives (e.g. + s,f sounds) can be coded adequately with less bits. + For this reason, VBR can achieve lower bit-rate for the same quality, or + a better quality for a certain bit-rate. + Despite its advantages, VBR has two main drawbacks: first, by only specifying + quality, there's no guaranty about the final average bit-rate. + Second, for some real-time applications like voice over IP (VoIP), what + counts is the maximum bit-rate, which must be low enough for the communication + channel. +\end_layout + +\begin_layout Subsection* +Average Bit-Rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +average bit-rate +\end_layout + +\end_inset + + (ABR) +\end_layout + +\begin_layout Standard +Average bit-rate solves one of the problems of VBR, as it dynamically adjusts + VBR quality in order to meet a specific target bit-rate. + Because the quality/bit-rate is adjusted in real-time (open-loop), the + global quality will be slightly lower than that obtained by encoding in + VBR with exactly the right quality setting to meet the target average bit-rate. +\end_layout + +\begin_layout Subsection* +Voice Activity Detection +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +voice activity detection +\end_layout + +\end_inset + + (VAD) +\end_layout + +\begin_layout Standard +When enabled, voice activity detection detects whether the audio being encoded + is speech or silence/background noise. + VAD is always implicitly activated when encoding in VBR, so the option + is only useful in non-VBR operation. + In this case, Speex detects non-speech periods and encode them with just + enough bits to reproduce the background noise. + This is called +\begin_inset Quotes eld +\end_inset + +comfort noise generation +\begin_inset Quotes erd +\end_inset + + (CNG). +\end_layout + +\begin_layout Subsection* +Discontinuous Transmission +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +discontinuous transmission +\end_layout + +\end_inset + + (DTX) +\end_layout + +\begin_layout Standard +Discontinuous transmission is an addition to VAD/VBR operation, that allows + to stop transmitting completely when the background noise is stationary. + In file-based operation, since we cannot just stop writing to the file, + only 5 bits are used for such frames (corresponding to 250 bps). +\end_layout + +\begin_layout Subsection* +Perceptual enhancement +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +perceptual enhancement +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Perceptual enhancement is a part of the decoder which, when turned on, attempts + to reduce the perception of the noise/distortion produced by the encoding/decod +ing process. + In most cases, perceptual enhancement brings the sound further from the + original +\emph on +objectively +\emph default + (e.g. + considering only SNR), but in the end it still +\emph on +sounds +\emph default + better (subjective improvement). +\end_layout + +\begin_layout Subsection* +Latency and algorithmic delay +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +algorithmic delay +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Every speech codec introduces a delay in the transmission. + For Speex, this delay is equal to the frame size, plus some amount of +\begin_inset Quotes eld +\end_inset + +look-ahead +\begin_inset Quotes erd +\end_inset + + required to process each frame. + In narrowband operation (8 kHz), the look-ahead is 10 ms, in wideband operation + (16 kHz), the look-ahead is 13.9 ms and in ultra-wideband operation (32 + kHz) look-ahead is 15.9 ms, resulting in the algorithic delays of 30 ms, + 33.9 ms and 35.9 ms accordingly. + These values don't account for the CPU time it takes to encode or decode + the frames. +\end_layout + +\begin_layout Section +Codec +\end_layout + +\begin_layout Standard +The main characteristics of Speex can be summarized as follows: +\end_layout + +\begin_layout Itemize +Free software/open-source +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +open-source +\end_layout + +\end_inset + +, patent +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +patent +\end_layout + +\end_inset + + and royalty-free +\end_layout + +\begin_layout Itemize +Integration of narrowband +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +narrowband +\end_layout + +\end_inset + + and wideband +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +wideband +\end_layout + +\end_inset + + using an embedded bit-stream +\end_layout + +\begin_layout Itemize +Wide range of bit-rates available (from 2.15 kbps to 44 kbps) +\end_layout + +\begin_layout Itemize +Dynamic bit-rate switching (AMR) and Variable Bit-Rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +variable bit-rate +\end_layout + +\end_inset + + (VBR) operation +\end_layout + +\begin_layout Itemize +Voice Activity Detection +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +voice activity detection +\end_layout + +\end_inset + + (VAD, integrated with VBR) and discontinuous transmission (DTX) +\end_layout + +\begin_layout Itemize +Variable complexity +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +complexity +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +Embedded wideband structure (scalable sampling rate) +\end_layout + +\begin_layout Itemize +Ultra-wideband sampling rate at 32 kHz +\end_layout + +\begin_layout Itemize +Intensity stereo encoding option +\end_layout + +\begin_layout Itemize +Fixed-point implementation +\end_layout + +\begin_layout Section +Preprocessor +\end_layout + +\begin_layout Standard +This part refers to the preprocessor module introduced in the 1.1.x branch. + The preprocessor is designed to be used on the audio +\emph on +before +\emph default + running the encoder. + The preprocessor provides three main functionalities: +\end_layout + +\begin_layout Itemize +noise suppression +\end_layout + +\begin_layout Itemize +automatic gain control (AGC) +\end_layout + +\begin_layout Itemize +voice activity detection (VAD) +\end_layout + +\begin_layout Standard +The denoiser can be used to reduce the amount of background noise present + in the input signal. + This provides higher quality speech whether or not the denoised signal + is encoded with Speex (or at all). + However, when using the denoised signal with the codec, there is an additional + benefit. + Speech codecs in general (Speex included) tend to perform poorly on noisy + input, which tends to amplify the noise. + The denoiser greatly reduces this effect. +\end_layout + +\begin_layout Standard +Automatic gain control (AGC) is a feature that deals with the fact that + the recording volume may vary by a large amount between different setups. + The AGC provides a way to adjust a signal to a reference volume. + This is useful for voice over IP because it removes the need for manual + adjustment of the microphone gain. + A secondary advantage is that by setting the microphone gain to a conservative + (low) level, it is easier to avoid clipping. +\end_layout + +\begin_layout Standard +The voice activity detector (VAD) provided by the preprocessor is more advanced + than the one directly provided in the codec. + +\end_layout + +\begin_layout Section +Adaptive Jitter Buffer +\end_layout + +\begin_layout Standard +When transmitting voice (or any content for that matter) over UDP or RTP, + packet may be lost, arrive with different delay, or even out of order. + The purpose of a jitter buffer is to reorder packets and buffer them long + enough (but no longer than necessary) so they can be sent to be decoded. + +\end_layout + +\begin_layout Section +Acoustic Echo Canceller +\end_layout + +\begin_layout Standard +In any hands-free communication system (Fig. + +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Acoustic-echo-model" + +\end_inset + +), speech from the remote end is played in the local loudspeaker, propagates + in the room and is captured by the microphone. + If the audio captured from the microphone is sent directly to the remote + end, then the remote user hears an echo of his voice. + An acoustic echo canceller is designed to remove the acoustic echo before + it is sent to the remote end. + It is important to understand that the echo canceller is meant to improve + the quality on the +\series bold +remote +\series default + end. + For those who care a lot about mouth-to-ear delays it should be noted that + unlike Speex codec, resampler and preprocessor, this Acoustic Echo Canceller + does not introduce any latency. +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Graphics + filename echo_path.eps + width 10cm + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Acoustic echo model +\begin_inset CommandInset label +LatexCommand label +name "fig:Acoustic-echo-model" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Resampler +\end_layout + +\begin_layout Standard +In some cases, it may be useful to convert audio from one sampling rate + to another. + There are many reasons for that. + It can be for mixing streams that have different sampling rates, for supporting + sampling rates that the soundcard doesn't support, for transcoding, etc. + That's why there is now a resampler that is part of the Speex project. + This resampler can be used to convert between any two arbitrary rates (the + ratio must only be a rational number) and there is control over the quality/com +plexity tradeoff. + Keep in mind, that resampler introduce some delay in audio stream, which + size depends on resampler quality setting. + Refer to resampler API documentation to know how to get exact delay values. +\end_layout + +\begin_layout Section +Integration +\end_layout + +\begin_layout Standard +Knowing +\emph on +how +\emph default + to use each of the components is not that useful unless we know +\emph on +where +\emph default + to use them. + Figure +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:Integration-VoIP" + +\end_inset + + shows where each of the components would be used in a typical VoIP client. + Components in dotted lines are optional, though they may be very useful + in some circumstances. + There are several important things to note from there. + The AEC must be placed as close as possible to the playback and capture. + Only the resampling may be closer. + Also, it is very important to use the same clock for both mic capture and + speaker/headphones playback. +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Graphics + filename components.eps + width 80text% + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Integration of all the components in a VoIP client. +\begin_inset CommandInset label +LatexCommand label +name "fig:Integration-VoIP" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Compiling and Porting +\end_layout + +\begin_layout Standard +Compiling Speex under UNIX/Linux or any other platform supported by autoconf + (e.g. + Win32/cygwin) is as easy as typing: +\end_layout + +\begin_layout LyX-Code +% ./configure [options] +\end_layout + +\begin_layout LyX-Code +% make +\end_layout + +\begin_layout LyX-Code +% make install +\end_layout + +\begin_layout Standard +The options supported by the Speex configure script are: +\end_layout + +\begin_layout Description +--prefix= Specifies the base path for installing Speex (e.g. + /usr) +\end_layout + +\begin_layout Description +--enable-shared/--disable-shared Whether to compile shared libraries +\end_layout + +\begin_layout Description +--enable-static/--disable-static Whether to compile static libraries +\end_layout + +\begin_layout Description +--disable-wideband Disable the wideband part of Speex (typically to save + space) +\end_layout + +\begin_layout Description +--enable-valgrind Enable extra hits for valgrind for debugging purposes + (do not use by default) +\end_layout + +\begin_layout Description +--enable-sse Enable use of SSE instructions (x86/float only) +\end_layout + +\begin_layout Description +--enable-fixed-point +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +fixed-point +\end_layout + +\end_inset + + Compile Speex for a processor that does not have a floating point unit + (FPU) +\end_layout + +\begin_layout Description +--enable-arm4-asm Enable assembly specific to the ARMv4 architecture (gcc + only) +\end_layout + +\begin_layout Description +--enable-arm5e-asm Enable assembly specific to the ARMv5E architecture (gcc + only) +\end_layout + +\begin_layout Description +--enable-fixed-point-debug Use only for debugging the fixed-point +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +fixed-point +\end_layout + +\end_inset + + code (very slow) +\end_layout + +\begin_layout Description +--enable-ti-c55x Enable support for the TI C5x family +\end_layout + +\begin_layout Description +--enable-blackfin-asm Enable assembly specific to the Blackfin DSP architecture + (gcc only) +\end_layout + +\begin_layout Section +Platforms +\end_layout + +\begin_layout Standard +Speex is known to compile and work on a large number of architectures, both + floating-point and fixed-point. + In general, any architecture that can natively compute the multiplication + of two signed 16-bit numbers (32-bit result) and runs at a sufficient clock + rate (architecture-dependent) is capable of running Speex. + Architectures on which Speex is +\series bold +known +\series default + to work (it probably works on many others) are: +\end_layout + +\begin_layout Itemize +x86 & x86-64 +\end_layout + +\begin_layout Itemize +Power +\end_layout + +\begin_layout Itemize +SPARC +\end_layout + +\begin_layout Itemize +ARM +\end_layout + +\begin_layout Itemize +Blackfin +\end_layout + +\begin_layout Itemize +Coldfire (68k family) +\end_layout + +\begin_layout Itemize +TI C54xx & C55xx +\end_layout + +\begin_layout Itemize +TI C6xxx +\end_layout + +\begin_layout Itemize +TriMedia (experimental) +\end_layout + +\begin_layout Standard +Operating systems on top of which Speex is known to work include (it probably + works on many others): +\end_layout + +\begin_layout Itemize +Linux +\end_layout + +\begin_layout Itemize +\begin_inset Formula $\mu$ +\end_inset + +Clinux +\end_layout + +\begin_layout Itemize +MacOS X +\end_layout + +\begin_layout Itemize +BSD +\end_layout + +\begin_layout Itemize +Other UNIX/POSIX variants +\end_layout + +\begin_layout Itemize +Symbian +\end_layout + +\begin_layout Standard +The source code directory include additional information for compiling on + certain architectures or operating systems in README.xxx files. +\end_layout + +\begin_layout Section +Porting and Optimising +\end_layout + +\begin_layout Standard +Here are a few things to consider when porting or optimising Speex for a + new platform or an existing one. +\end_layout + +\begin_layout Subsection +CPU optimisation +\end_layout + +\begin_layout Standard +The single factor that will affect the CPU usage of Speex the most is whether + it is compiled for floating point or fixed-point. + If your CPU/DSP does not have a floating-point unit FPU, then compiling + as fixed-point will be orders of magnitudes faster. + If there is an FPU present, then it is important to test which version + is faster. + On the x86 architecture, floating-point is +\series bold +generally +\series default + faster, but not always. + To compile Speex as fixed-point, you need to pass --fixed-point to the + configure script or define the FIXED_POINT macro for the compiler. + As of 1.2beta3, it is now possible to disable the floating-point compatibility + API, which means that your code can link without a float emulation library. + To do that configure with --disable-float-api or define the DISABLE_FLOAT_API + macro. + Until the VBR feature is ported to fixed-point, you will also need to configure + with --disable-vbr or define DISABLE_VBR. +\end_layout + +\begin_layout Standard +Other important things to check on some DSP architectures are: +\end_layout + +\begin_layout Itemize +Make sure the cache is set to write-back mode +\end_layout + +\begin_layout Itemize +If the chip has SRAM instead of cache, make sure as much code and data are + in SRAM, rather than in RAM +\end_layout + +\begin_layout Standard +If you are going to be writing assembly, then the following functions are + +\series bold +usually +\series default + the first ones you should consider optimising: +\end_layout + +\begin_layout Itemize +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +filter_mem16() +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +iir_mem16() +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +vq_nbest() +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +pitch_xcorr() +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +interp_pitch() +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The filtering functions +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +filter_mem16() +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +iir_mem16() +\end_layout + +\end_inset + + are implemented in the direct form II transposed (DF2T). + However, for architectures based on multiply-accumulate (MAC), DF2T requires + frequent reload of the accumulator, which can make the code very slow. + For these architectures (e.g. + Blackfin and Coldfire), a better approach is to implement those functions + as direct form I (DF1), which is easier to express in terms of MAC. + When doing that however, +\series bold +it is important to make sure that the DF1 implementation still behaves like + the original DF2T behaviour when it comes to memory values +\series default +. + This is necessary because the filter is time-varying and must compute exactly + the same value (not counting machine rounding) on any encoder or decoder. +\end_layout + +\begin_layout Subsection +Memory optimisation +\end_layout + +\begin_layout Standard +Memory optimisation is mainly something that should be considered for small + embedded platforms. + For PCs, Speex is already so tiny that it's just not worth doing any of + the things suggested here. + There are several ways to reduce the memory usage of Speex, both in terms + of code size and data size. + For optimising code size, the trick is to first remove features you do + not need. + Some examples of things that can easily be disabled +\series bold +if you don't need them +\series default + are: +\end_layout + +\begin_layout Itemize +Wideband support (--disable-wideband) +\end_layout + +\begin_layout Itemize +Support for stereo (removing stereo.c) +\end_layout + +\begin_layout Itemize +VBR support (--disable-vbr or DISABLE_VBR) +\end_layout + +\begin_layout Itemize +Static codebooks that are not needed for the bit-rates you are using (*_table.c + files) +\end_layout + +\begin_layout Standard +Speex also has several methods for allocating temporary arrays. + When using a compiler that supports C99 properly (as of 2007, Microsoft + compilers don't, but gcc does), it is best to define VAR_ARRAYS. + That makes use of the variable-size array feature of C99. + The next best is to define USE_ALLOCA so that Speex can use alloca() to + allocate the temporary arrays. + Note that on many systems, alloca() is buggy so it may not work. + If none of VAR_ARRAYS and USE_ALLOCA are defined, then Speex falls back + to allocating a large +\begin_inset Quotes eld +\end_inset + +scratch space +\begin_inset Quotes erd +\end_inset + + and doing its own internal allocation. + The main disadvantage of this solution is that it is wasteful. + It needs to allocate enough stack for the worst case scenario (worst bit-rate, + highest complexity setting, ...) and by default, the memory isn't shared between + multiple encoder/decoder states. + Still, if the +\begin_inset Quotes eld +\end_inset + +manual +\begin_inset Quotes erd +\end_inset + + allocation is the only option left, there are a few things that can be + improved. + By overriding the speex_alloc_scratch() call in os_support.h, it is possible + to always return the same memory area for all states +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +In this case, one must be careful with threads +\end_layout + +\end_inset + +. + In addition to that, by redefining the NB_ENC_STACK and NB_DEC_STACK (or + similar for wideband), it is possible to only allocate memory for a scenario + that is known in advance. + In this case, it is important to measure the amount of memory required + for the specific sampling rate, bit-rate and complexity level being used. +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Command-line encoder/decoder +\begin_inset CommandInset label +LatexCommand label +name "sec:Command-line-encoder/decoder" + +\end_inset + + +\end_layout + +\begin_layout Standard +The base Speex distribution includes a command-line encoder ( +\emph on +speexenc +\emph default +) and decoder ( +\emph on +speexdec +\emph default +). + Those tools produce and read Speex files encapsulated in the Ogg container. + Although it is possible to encapsulate Speex in any container, Ogg is the + recommended container for files. + This section describes how to use the command line tools for Speex files + in Ogg. +\end_layout + +\begin_layout Section + +\emph on +speexenc +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +speexenc +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The +\emph on +speexenc +\emph default + utility is used to create Speex files from raw PCM or wave files. + It can be used by calling: +\end_layout + +\begin_layout LyX-Code +speexenc [options] input_file output_file +\end_layout + +\begin_layout Standard +The value '-' for input_file or output_file corresponds respectively to + stdin and stdout. + The valid options are: +\end_layout + +\begin_layout Description +--narrowband +\begin_inset space ~ +\end_inset + +(-n) Tell Speex to treat the input as narrowband (8 kHz). + This is the default +\end_layout + +\begin_layout Description +--wideband +\begin_inset space ~ +\end_inset + +(-w) Tell Speex to treat the input as wideband (16 kHz) +\end_layout + +\begin_layout Description +--ultra-wideband +\begin_inset space ~ +\end_inset + +(-u) Tell Speex to treat the input as +\begin_inset Quotes eld +\end_inset + +ultra-wideband +\begin_inset Quotes erd +\end_inset + + (32 kHz) +\end_layout + +\begin_layout Description +--quality +\begin_inset space ~ +\end_inset + +n Set the encoding quality (0-10), default is 8 +\end_layout + +\begin_layout Description +--bitrate +\begin_inset space ~ +\end_inset + +n Encoding bit-rate (use bit-rate n or lower) +\end_layout + +\begin_layout Description +--vbr Enable VBR (Variable Bit-Rate), disabled by default +\end_layout + +\begin_layout Description +--abr +\begin_inset space ~ +\end_inset + +n Enable ABR (Average Bit-Rate) at n kbps, disabled by default +\end_layout + +\begin_layout Description +--vad Enable VAD (Voice Activity Detection), disabled by default +\end_layout + +\begin_layout Description +--dtx Enable DTX (Discontinuous Transmission), disabled by default +\end_layout + +\begin_layout Description +--nframes +\begin_inset space ~ +\end_inset + +n Pack n frames in each Ogg packet (this saves space at low bit-rates) +\end_layout + +\begin_layout Description +--comp +\begin_inset space ~ +\end_inset + +n Set encoding speed/quality tradeoff. + The higher the value of n, the slower the encoding (default is 3) +\end_layout + +\begin_layout Description +-V Verbose operation, print bit-rate currently in use +\end_layout + +\begin_layout Description +--help +\begin_inset space ~ +\end_inset + +(-h) Print the help +\end_layout + +\begin_layout Description +--version +\begin_inset space ~ +\end_inset + +(-v) Print version information +\end_layout + +\begin_layout Subsection* +Speex comments +\end_layout + +\begin_layout Description +--comment Add the given string as an extra comment. + This may be used multiple times. + +\end_layout + +\begin_layout Description +--author Author of this track. + +\end_layout + +\begin_layout Description +--title Title for this track. + +\end_layout + +\begin_layout Subsection* +Raw input options +\end_layout + +\begin_layout Description +--rate +\begin_inset space ~ +\end_inset + +n Sampling rate for raw input +\end_layout + +\begin_layout Description +--stereo Consider raw input as stereo +\end_layout + +\begin_layout Description +--le Raw input is little-endian +\end_layout + +\begin_layout Description +--be Raw input is big-endian +\end_layout + +\begin_layout Description +--8bit Raw input is 8-bit unsigned +\end_layout + +\begin_layout Description +--16bit Raw input is 16-bit signed +\end_layout + +\begin_layout Section + +\emph on +speexdec +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +speexdec +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The +\emph on +speexdec +\emph default + utility is used to decode Speex files and can be used by calling: +\end_layout + +\begin_layout LyX-Code +speexdec [options] speex_file [output_file] +\end_layout + +\begin_layout Standard +The value '-' for input_file or output_file corresponds respectively to + stdin and stdout. + Also, when no output_file is specified, the file is played to the soundcard. + The valid options are: +\end_layout + +\begin_layout Description +--enh enable post-filter (default) +\end_layout + +\begin_layout Description +--no-enh disable post-filter +\end_layout + +\begin_layout Description +--force-nb Force decoding in narrowband +\end_layout + +\begin_layout Description +--force-wb Force decoding in wideband +\end_layout + +\begin_layout Description +--force-uwb Force decoding in ultra-wideband +\end_layout + +\begin_layout Description +--mono Force decoding in mono +\end_layout + +\begin_layout Description +--stereo Force decoding in stereo +\end_layout + +\begin_layout Description +--rate +\begin_inset space ~ +\end_inset + +n Force decoding at n Hz sampling rate +\end_layout + +\begin_layout Description +--packet-loss +\begin_inset space ~ +\end_inset + +n Simulate n % random packet loss +\end_layout + +\begin_layout Description +-V Verbose operation, print bit-rate currently in use +\end_layout + +\begin_layout Description +--help +\begin_inset space ~ +\end_inset + +(-h) Print the help +\end_layout + +\begin_layout Description +--version +\begin_inset space ~ +\end_inset + +(-v) Print version information +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Using the Speex Codec API ( +\emph on +libspeex +\emph default + +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +libspeex +\end_layout + +\end_inset + +) +\begin_inset CommandInset label +LatexCommand label +name "sec:Programming-with-Speex" + +\end_inset + + +\end_layout + +\begin_layout Standard +The +\emph on +libspeex +\emph default + library contains all the functions for encoding and decoding speech with + the Speex codec. + When linking on a UNIX system, one must add +\emph on +-lspeex -lm +\emph default + to the compiler command line. + One important thing to know is that +\series bold +libspeex calls are reentrant, but not thread-safe +\series default +. + That means that it is fine to use calls from many threads, but +\series bold +calls using the same state from multiple threads must be protected by mutexes +\series default +. + Examples of code can also be found in Appendix +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Sample-code" + +\end_inset + + and the complete API documentation is included in the Documentation section + of the Speex website (http://www.speex.org/). +\end_layout + +\begin_layout Section +Encoding +\begin_inset CommandInset label +LatexCommand label +name "sub:Encoding" + +\end_inset + + +\end_layout + +\begin_layout Standard +In order to encode speech using Speex, one first needs to: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +#include +\end_layout + +\end_inset + +Then in the code, a Speex bit-packing struct must be declared, along with + a Speex encoder state: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +SpeexBits bits; +\end_layout + +\begin_layout Plain Layout + +void *enc_state; +\end_layout + +\end_inset + +The two are initialized by: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_bits_init(&bits); +\end_layout + +\begin_layout Plain Layout + +enc_state = speex_encoder_init(&speex_nb_mode); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +For wideband coding, +\emph on +speex_nb_mode +\emph default + will be replaced by +\emph on +speex_wb_mode +\emph default +. + In most cases, you will need to know the frame size used at the sampling + rate you are using. + You can get that value in the +\emph on +frame_size +\emph default + variable (expressed in +\series bold +samples +\series default +, not bytes) with: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_encoder_ctl(enc_state,SPEEX_GET_FRAME_SIZE,&frame_size); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +In practice, +\emph on +frame_size +\emph default + will correspond to 20 ms when using 8, 16, or 32 kHz sampling rate. + There are many parameters that can be set for the Speex encoder, but the + most useful one is the quality parameter that controls the quality vs bit-rate + tradeoff. + This is set by: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_encoder_ctl(enc_state,SPEEX_SET_QUALITY,&quality); +\end_layout + +\end_inset + +where +\emph on +quality +\emph default + is an integer value ranging from 0 to 10 (inclusively). + The mapping between quality and bit-rate is described in Fig. + +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:quality_vs_bps" + +\end_inset + + for narrowband. +\end_layout + +\begin_layout Standard +Once the initialization is done, for every input frame: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_bits_reset(&bits); +\end_layout + +\begin_layout Plain Layout + +speex_encode_int(enc_state, input_frame, &bits); +\end_layout + +\begin_layout Plain Layout + +nbBytes = speex_bits_write(&bits, byte_ptr, MAX_NB_BYTES); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +where +\emph on +input_frame +\emph default + is a +\emph on +( +\emph default +short +\emph on +*) +\emph default + pointing to the beginning of a speech frame, +\emph on +byte_ptr +\emph default + is a +\emph on +(char *) +\emph default + where the encoded frame will be written, +\emph on +MAX_NB_BYTES +\emph default + is the maximum number of bytes that can be written to +\emph on +byte_ptr +\emph default + without causing an overflow and +\emph on +nbBytes +\emph default + is the number of bytes actually written to +\emph on +byte_ptr +\emph default + (the encoded size in bytes). + Before calling speex_bits_write, it is possible to find the number of bytes + that need to be written by calling +\family typewriter +speex_bits_nbytes(&bits) +\family default +, which returns a number of bytes. +\end_layout + +\begin_layout Standard +It is still possible to use the +\emph on +speex_encode() +\emph default + function, which takes a +\emph on +(float *) +\emph default + for the audio. + However, this would make an eventual port to an FPU-less platform (like + ARM) more complicated. + Internally, +\emph on +speex_encode() +\emph default + and +\emph on +speex_encode_int() +\emph default + are processed in the same way. + Whether the encoder uses the fixed-point version is only decided by the + compile-time flags, not at the API level. +\end_layout + +\begin_layout Standard +After you're done with the encoding, free all resources with: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_bits_destroy(&bits); +\end_layout + +\begin_layout Plain Layout + +speex_encoder_destroy(enc_state); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +That's about it for the encoder. + +\end_layout + +\begin_layout Section +Decoding +\begin_inset CommandInset label +LatexCommand label +name "sub:Decoding" + +\end_inset + + +\end_layout + +\begin_layout Standard +In order to decode speech using Speex, you first need to: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +#include +\end_layout + +\end_inset + +You also need to declare a Speex bit-packing struct +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +SpeexBits bits; +\end_layout + +\end_inset + +and a Speex decoder state +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void *dec_state; +\end_layout + +\end_inset + +The two are initialized by: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_bits_init(&bits); +\end_layout + +\begin_layout Plain Layout + +dec_state = speex_decoder_init(&speex_nb_mode); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +For wideband decoding, +\emph on +speex_nb_mode +\emph default + will be replaced by +\emph on +speex_wb_mode +\emph default +. + If you need to obtain the size of the frames that will be used by the decoder, + you can get that value in the +\emph on +frame_size +\emph default + variable (expressed in +\series bold +samples +\series default +, not bytes) with: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &frame_size); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +There is also a parameter that can be set for the decoder: whether or not + to use a perceptual enhancer. + This can be set by: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_decoder_ctl(dec_state, SPEEX_SET_ENH, &enh); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +where +\emph on +enh +\emph default + is an int with value 0 to have the enhancer disabled and 1 to have it enabled. + As of 1.2-beta1, the default is now to enable the enhancer. +\end_layout + +\begin_layout Standard +Again, once the decoder initialization is done, for every input frame: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_bits_read_from(&bits, input_bytes, nbBytes); +\end_layout + +\begin_layout Plain Layout + +speex_decode_int(dec_state, &bits, output_frame); +\end_layout + +\end_inset + +where input_bytes is a +\emph on +(char *) +\emph default + containing the bit-stream data received for a frame, +\emph on +nbBytes +\emph default + is the size (in bytes) of that bit-stream, and +\emph on +output_frame +\emph default + is a +\emph on +(short *) +\emph default + and points to the area where the decoded speech frame will be written. + A NULL value as the second argument indicates that we don't have the bits + for the current frame. + When a frame is lost, the Speex decoder will do its best to "guess" the + correct signal. +\end_layout + +\begin_layout Standard +As for the encoder, the +\emph on +speex_decode() +\emph default + function can still be used, with a +\emph on +(float *) +\emph default + as the output for the audio. + After you're done with the decoding, free all resources with: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_bits_destroy(&bits); +\end_layout + +\begin_layout Plain Layout + +speex_decoder_destroy(dec_state); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Codec Options (speex_*_ctl) +\begin_inset CommandInset label +LatexCommand label +name "sub:Codec-Options" + +\end_inset + + +\end_layout + +\begin_layout Quote +\align center + +\emph on +Entities should not be multiplied beyond necessity -- William of Ockham. +\end_layout + +\begin_layout Quote +\align center + +\emph on +Just because there's an option for it doesn't mean you have to turn it on + -- me. +\end_layout + +\begin_layout Standard +The Speex encoder and decoder support many options and requests that can + be accessed through the +\emph on +speex_encoder_ctl +\emph default + and +\emph on +speex_decoder_ctl +\emph default + functions. + These functions are similar to the +\emph on +ioctl +\emph default + system call and their prototypes are: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void speex_encoder_ctl(void *encoder, int request, void *ptr); +\end_layout + +\begin_layout Plain Layout + +void speex_decoder_ctl(void *encoder, int request, void *ptr); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Despite those functions, the defaults are usually good for many applications + and +\series bold +optional settings should only be used when one understands them and knows + that they are needed +\series default +. + A common error is to attempt to set many unnecessary settings. + +\end_layout + +\begin_layout Standard +Here is a list of the values allowed for the requests. + Some only apply to the encoder or the decoder. + Because the last argument is of type +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +void * +\end_layout + +\end_inset + +, the +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +_ctl() +\end_layout + +\end_inset + + functions are +\series bold +not type safe +\series default +, and should thus be used with care. + The type +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + is the same as the C99 +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +int32_t +\end_layout + +\end_inset + + type. +\end_layout + +\begin_layout Description +SPEEX_SET_ENH +\begin_inset Formula $\ddagger$ +\end_inset + + Set perceptual enhancer +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +perceptual enhancement +\end_layout + +\end_inset + + to on (1) or off (0) ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +, default is on) +\end_layout + +\begin_layout Description +SPEEX_GET_ENH +\begin_inset Formula $\ddagger$ +\end_inset + + Get perceptual enhancer status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_GET_FRAME_SIZE Get the number of samples per frame for the current + mode ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_SET_QUALITY +\begin_inset Formula $\dagger$ +\end_inset + + Set the encoder speech quality ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + from 0 to 10, default is 8) +\end_layout + +\begin_layout Description +SPEEX_GET_QUALITY +\begin_inset Formula $\dagger$ +\end_inset + + Get the current encoder speech quality ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + from 0 to 10) +\end_layout + +\begin_layout Description +SPEEX_SET_MODE +\begin_inset Formula $\dagger$ +\end_inset + + Set the mode number, as specified in the RTP spec ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_GET_MODE +\begin_inset Formula $\dagger$ +\end_inset + + Get the current mode number, as specified in the RTP spec ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_SET_VBR +\begin_inset Formula $\dagger$ +\end_inset + + Set variable bit-rate (VBR) to on (1) or off (0) ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +, default is off) +\end_layout + +\begin_layout Description +SPEEX_GET_VBR +\begin_inset Formula $\dagger$ +\end_inset + + Get variable bit-rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +variable bit-rate +\end_layout + +\end_inset + + (VBR) status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_SET_VBR_QUALITY +\begin_inset Formula $\dagger$ +\end_inset + + Set the encoder VBR speech quality (float 0.0 to 10.0, default is 8.0) +\end_layout + +\begin_layout Description +SPEEX_GET_VBR_QUALITY +\begin_inset Formula $\dagger$ +\end_inset + + Get the current encoder VBR speech quality (float 0 to 10) +\end_layout + +\begin_layout Description +SPEEX_SET_COMPLEXITY +\begin_inset Formula $\dagger$ +\end_inset + + Set the CPU resources allowed for the encoder ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + from 1 to 10, default is 2) +\end_layout + +\begin_layout Description +SPEEX_GET_COMPLEXITY +\begin_inset Formula $\dagger$ +\end_inset + + Get the CPU resources allowed for the encoder ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + from 1 to 10, default is 2) +\end_layout + +\begin_layout Description +SPEEX_SET_BITRATE +\begin_inset Formula $\dagger$ +\end_inset + + Set the bit-rate to use the closest value not exceeding the parameter ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in bits per second) +\end_layout + +\begin_layout Description +SPEEX_GET_BITRATE Get the current bit-rate in use ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in bits per second) +\end_layout + +\begin_layout Description +SPEEX_SET_SAMPLING_RATE Set real sampling rate ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in Hz) +\end_layout + +\begin_layout Description +SPEEX_GET_SAMPLING_RATE Get real sampling rate ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in Hz) +\end_layout + +\begin_layout Description +SPEEX_RESET_STATE Reset the encoder/decoder state to its original state, + clearing all memories (no argument) +\end_layout + +\begin_layout Description +SPEEX_SET_VAD +\begin_inset Formula $\dagger$ +\end_inset + + Set voice activity detection +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +voice activity detection +\end_layout + +\end_inset + + (VAD) to on (1) or off (0) ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +, default is off) +\end_layout + +\begin_layout Description +SPEEX_GET_VAD +\begin_inset Formula $\dagger$ +\end_inset + + Get voice activity detection (VAD) status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_SET_DTX +\begin_inset Formula $\dagger$ +\end_inset + + Set discontinuous transmission +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +discontinuous transmission +\end_layout + +\end_inset + + (DTX) to on (1) or off (0) ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +, default is off) +\end_layout + +\begin_layout Description +SPEEX_GET_DTX +\begin_inset Formula $\dagger$ +\end_inset + + Get discontinuous transmission (DTX) status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_SET_ABR +\begin_inset Formula $\dagger$ +\end_inset + + Set average bit-rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +average bit-rate +\end_layout + +\end_inset + + (ABR) to a value n in bits per second ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in bits per second) +\end_layout + +\begin_layout Description +SPEEX_GET_ABR +\begin_inset Formula $\dagger$ +\end_inset + + Get average bit-rate (ABR) setting ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in bits per second) +\end_layout + +\begin_layout Description +SPEEX_SET_PLC_TUNING +\begin_inset Formula $\dagger$ +\end_inset + + Tell the encoder to optimize encoding for a certain percentage of packet + loss ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in percent) +\end_layout + +\begin_layout Description +SPEEX_GET_PLC_TUNING +\begin_inset Formula $\dagger$ +\end_inset + + Get the current tuning of the encoder for PLC ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in percent) +\end_layout + +\begin_layout Description +SPEEX_GET_LOOKAHEAD Returns the lookahead used by Speex separately for an + encoder and a decoder. + Sum encoder and decoder lookahead values to get the total codec lookahead. +\end_layout + +\begin_layout Description +SPEEX_SET_VBR_MAX_BITRATE +\begin_inset Formula $\dagger$ +\end_inset + + Set the maximum bit-rate allowed in VBR operation ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in bits per second) +\end_layout + +\begin_layout Description +SPEEX_GET_VBR_MAX_BITRATE +\begin_inset Formula $\dagger$ +\end_inset + + Get the current maximum bit-rate allowed in VBR operation ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + + in bits per second) +\end_layout + +\begin_layout Description +SPEEX_SET_HIGHPASS Set the high-pass filter on (1) or off (0) ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +, default is on) +\end_layout + +\begin_layout Description +SPEEX_GET_HIGHPASS Get the current high-pass filter status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +\begin_inset Formula $\dagger$ +\end_inset + + applies only to the encoder +\end_layout + +\begin_layout Description +\begin_inset Formula $\ddagger$ +\end_inset + + applies only to the decoder +\end_layout + +\begin_layout Section +Mode queries +\begin_inset CommandInset label +LatexCommand label +name "sub:Mode-queries" + +\end_inset + + +\end_layout + +\begin_layout Standard +Speex modes have a query system similar to the speex_encoder_ctl and speex_decod +er_ctl calls. + Since modes are read-only, it is only possible to get information about + a particular mode. + The function used to do that is: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +void speex_mode_query(SpeexMode *mode, int request, void *ptr); +\end_layout + +\end_inset + +The admissible values for request are (unless otherwise note, the values + are returned through +\emph on +ptr +\emph default +): +\end_layout + +\begin_layout Description +SPEEX_MODE_FRAME_SIZE Get the frame size (in samples) for the mode +\end_layout + +\begin_layout Description +SPEEX_SUBMODE_BITRATE Get the bit-rate for a submode number specified through + +\emph on +ptr +\emph default + (integer in bps). + +\end_layout + +\begin_layout Section +Packing and in-band signalling +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +in-band signalling +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Sometimes it is desirable to pack more than one frame per packet (or other + basic unit of storage). + The proper way to do it is to call speex_encode +\begin_inset Formula $N$ +\end_inset + + times before writing the stream with speex_bits_write. + In cases where the number of frames is not determined by an out-of-band + mechanism, it is possible to include a terminator code. + That terminator consists of the code 15 (decimal) encoded with 5 bits, + as shown in Table +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:quality_vs_bps" + +\end_inset + +. + Note that as of version 1.0.2, calling speex_bits_write automatically inserts + the terminator so as to fill the last byte. + This doesn't involves any overhead and makes sure Speex can always detect + when there is no more frame in a packet. +\end_layout + +\begin_layout Standard +It is also possible to send in-band +\begin_inset Quotes eld +\end_inset + +messages +\begin_inset Quotes erd +\end_inset + + to the other side. + All these messages are encoded as +\begin_inset Quotes eld +\end_inset + +pseudo-frames +\begin_inset Quotes erd +\end_inset + + of mode 14 which contain a 4-bit message type code, followed by the message. + Table +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:In-band-signalling-codes" + +\end_inset + + lists the available codes, their meaning and the size of the message that + follows. + Most of these messages are requests that are sent to the encoder or decoder + on the other end, which is free to comply or ignore them. + By default, all in-band messages are ignored. +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement htbp +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +Code +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Size (bits) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Content +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Asks decoder to set perceptual enhancement off (0) or on(1) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Asks (if 1) the encoder to be less +\begin_inset Quotes eld +\end_inset + +aggressive +\begin_inset Quotes erd +\end_inset + + due to high packet loss +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Asks encoder to switch to mode N +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Asks encoder to switch to mode N for low-band +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Asks encoder to switch to mode N for high-band +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Asks encoder to switch to quality N for VBR +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Request acknowledge (0=no, 1=all, 2=only for in-band data) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Asks encoder to set CBR (0), VAD(1), DTX(3), VBR(5), VBR+DTX(7) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Transmit (8-bit) character to the other end +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +9 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Intensity stereo information +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +10 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +16 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Announce maximum bit-rate acceptable (N in bytes/second) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +11 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +16 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +reserved +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +12 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +32 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Acknowledge receiving packet N +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +13 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +32 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +reserved +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +14 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +64 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +reserved +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +15 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +64 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +reserved +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +In-band signalling codes +\begin_inset CommandInset label +LatexCommand label +name "cap:In-band-signalling-codes" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Finally, applications may define custom in-band messages using mode 13. + The size of the message in bytes is encoded with 5 bits, so that the decoder + can skip it if it doesn't know how to interpret it. +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Speech Processing API ( +\emph on +libspeexdsp +\emph default +) +\end_layout + +\begin_layout Standard +As of version 1.2beta3, the non-codec parts of the Speex package are now + in a separate library called +\emph on +libspeexdsp +\emph default +. + This library includes the preprocessor, the acoustic echo canceller, the + jitter buffer, and the resampler. + In a UNIX environment, it can be linked into a program by adding +\emph on +-lspeexdsp -lm +\emph default + to the compiler command line. + Just like for libspeex, +\series bold +libspeexdsp calls are reentrant, but not thread-safe +\series default +. + That means that it is fine to use calls from many threads, but +\series bold +calls using the same state from multiple threads must be protected by mutexes +\series default +. +\end_layout + +\begin_layout Section +Preprocessor +\begin_inset CommandInset label +LatexCommand label +name "sub:Preprocessor" + +\end_inset + + +\end_layout + +\begin_layout Standard +\noindent +In order to use the Speex preprocessor +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +preprocessor +\end_layout + +\end_inset + +, you first need to: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +#include +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\noindent +Then, a preprocessor state can be created as: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +SpeexPreprocessState *preprocess_state = speex_preprocess_state_init(frame_size, + sampling_rate); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\noindent +and it is recommended to use the same value for +\family typewriter +frame_size +\family default + as is used by the encoder (20 +\emph on +ms +\emph default +). +\end_layout + +\begin_layout Standard +For each input frame, you need to call: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_preprocess_run(preprocess_state, audio_frame); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\noindent +where +\family typewriter +audio_frame +\family default + is used both as input and output. + In cases where the output audio is not useful for a certain frame, it is + possible to use instead: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_preprocess_estimate_update(preprocess_state, audio_frame); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\noindent +This call will update all the preprocessor internal state variables without + computing the output audio, thus saving some CPU cycles. +\end_layout + +\begin_layout Standard +The behaviour of the preprocessor can be changed using: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_preprocess_ctl(preprocess_state, request, ptr); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\noindent +which is used in the same way as the encoder and decoder equivalent. + Options are listed in Section +\begin_inset CommandInset ref +LatexCommand ref +reference "sub:Preprocessor-options" + +\end_inset + +. +\end_layout + +\begin_layout Standard +The preprocessor state can be destroyed using: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_preprocess_state_destroy(preprocess_state); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +Preprocessor options +\begin_inset CommandInset label +LatexCommand label +name "sub:Preprocessor-options" + +\end_inset + + +\end_layout + +\begin_layout Standard +As with the codec, the preprocessor also has options that can be controlled + using an ioctl()-like call. + The available options are: +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_DENOISE Turns denoising on(1) or off(0) ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_DENOISE Get denoising status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_AGC Turns automatic gain control (AGC) on(1) or off(0) + ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_AGC Get AGC status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_VAD Turns voice activity detector (VAD) on(1) or off(0) + ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_VAD Get VAD status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_AGC_LEVEL +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_AGC_LEVEL +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_DEREVERB Turns reverberation removal on(1) or off(0) + ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_DEREVERB Get reverberation removal status ( +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_DEREVERB_LEVEL Not working yet, do not use +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_DEREVERB_LEVEL Not working yet, do not use +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_DEREVERB_DECAY Not working yet, do not use +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_DEREVERB_DECAY Not working yet, do not use +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_PROB_START +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_PROB_START +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_PROB_CONTINUE +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_PROB_CONTINUE +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_NOISE_SUPPRESS Set maximum attenuation of the noise + in dB (negative +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_NOISE_SUPPRESS Get maximum attenuation of the noise + in dB (negative +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_ECHO_SUPPRESS Set maximum attenuation of the residual + echo in dB (negative +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_ECHO_SUPPRESS Get maximum attenuation of the residual + echo in dB (negative +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE Set maximum attenuation of the + echo in dB when near end is active (negative +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE Get maximum attenuation of the + echo in dB when near end is active (negative +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +spx_int32_t +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_SET_ECHO_STATE Set the associated echo canceller for residual + echo suppression (pointer or NULL for no residual echo suppression) +\end_layout + +\begin_layout Description +SPEEX_PREPROCESS_GET_ECHO_STATE Get the associated echo canceller (pointer) +\end_layout + +\begin_layout Section +Echo Cancellation +\begin_inset CommandInset label +LatexCommand label +name "sub:Echo-Cancellation" + +\end_inset + + +\end_layout + +\begin_layout Standard +The Speex library now includes an echo cancellation +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +echo cancellation +\end_layout + +\end_inset + + algorithm suitable for Acoustic Echo Cancellation +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +acoustic echo cancellation +\end_layout + +\end_inset + + (AEC). + In order to use the echo canceller, you first need to +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +#include +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Then, an echo canceller state can be created by: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +SpeexEchoState *echo_state = speex_echo_state_init(frame_size, filter_length); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +where +\family typewriter +frame_size +\family default + is the amount of data (in samples) you want to process at once and +\family typewriter +filter_length +\family default + is the length (in samples) of the echo cancelling filter you want to use + (also known as +\shape italic +tail length +\shape default + +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +tail length +\end_layout + +\end_inset + +). + It is recommended to use a frame size in the order of 20 ms (or equal to + the codec frame size) and make sure it is easy to perform an FFT of that + size (powers of two are better than prime sizes). + The recommended tail length is approximately the third of the room reverberatio +n time. + For example, in a small room, reverberation time is in the order of 300 + ms, so a tail length of 100 ms is a good choice (800 samples at 8000 Hz + sampling rate). +\end_layout + +\begin_layout Standard +Once the echo canceller state is created, audio can be processed by: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_echo_cancellation(echo_state, input_frame, echo_frame, output_frame); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +where +\family typewriter +input_frame +\family default + is the audio as captured by the microphone, +\family typewriter +echo_frame +\family default + is the signal that was played in the speaker (and needs to be removed) + and +\family typewriter +output_frame +\family default + is the signal with echo removed. + +\end_layout + +\begin_layout Standard +One important thing to keep in mind is the relationship between +\family typewriter +input_frame +\family default + and +\family typewriter +echo_frame +\family default +. + It is important that, at any time, any echo that is present in the input + has already been sent to the echo canceller as +\family typewriter +echo_frame +\family default +. + In other words, the echo canceller cannot remove a signal that it hasn't + yet received. + On the other hand, the delay between the input signal and the echo signal + must be small enough because otherwise part of the echo cancellation filter + is inefficient. + In the ideal case, you code would look like: +\begin_inset listings +lstparams "breaklines=true" +inline false +status open + +\begin_layout Plain Layout + +write_to_soundcard(echo_frame, frame_size); +\end_layout + +\begin_layout Plain Layout + +read_from_soundcard(input_frame, frame_size); +\end_layout + +\begin_layout Plain Layout + +speex_echo_cancellation(echo_state, input_frame, echo_frame, output_frame); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +If you wish to further reduce the echo present in the signal, you can do + so by associating the echo canceller to the preprocessor (see Section +\begin_inset CommandInset ref +LatexCommand ref +reference "sub:Preprocessor" + +\end_inset + +). + This is done by calling: +\begin_inset listings +lstparams "breaklines=true" +inline false +status open + +\begin_layout Plain Layout + +speex_preprocess_ctl(preprocess_state, SPEEX_PREPROCESS_SET_ECHO_STATE,echo_stat +e); +\end_layout + +\end_inset + +in the initialisation. +\end_layout + +\begin_layout Standard +As of version 1.2-beta2, there is an alternative, simpler API that can be + used instead of +\emph on +speex_echo_cancellation() +\emph default +. + When audio capture and playback are handled asynchronously (e.g. + in different threads or using the +\emph on +poll() +\emph default + or +\emph on +select() +\emph default + system call), it can be difficult to keep track of what input_frame comes + with what echo_frame. + Instead, the playback context/thread can simply call: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_echo_playback(echo_state, echo_frame); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +every time an audio frame is played. + Then, the capture context/thread calls: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_echo_capture(echo_state, input_frame, output_frame); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +for every frame captured. + Internally, +\emph on +speex_echo_playback() +\emph default + simply buffers the playback frame so it can be used by +\emph on +speex_echo_capture() +\emph default + to call +\emph on +speex_echo_cancel() +\emph default +. + A side effect of using this alternate API is that the playback audio is + delayed by two frames, which is the normal delay caused by the soundcard. + When capture and playback are already synchronised, +\emph on +speex_echo_cancellation() +\emph default + is preferable since it gives better control on the exact input/echo timing. +\end_layout + +\begin_layout Standard +The echo cancellation state can be destroyed with: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_echo_state_destroy(echo_state); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +It is also possible to reset the state of the echo canceller so it can be + reused without the need to create another state with: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +speex_echo_state_reset(echo_state); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +Troubleshooting +\end_layout + +\begin_layout Standard +There are several things that may prevent the echo canceller from working + properly. + One of them is a bug (or something suboptimal) in the code, but there are + many others you should consider first +\end_layout + +\begin_layout Itemize +Using a different soundcard to do the capture and plaback will +\series bold +not +\series default + work, regardless of what you may think. + The only exception to that is if the two cards can be made to have their + sampling clock +\begin_inset Quotes eld +\end_inset + +locked +\begin_inset Quotes erd +\end_inset + + on the same clock source. + If not, the clocks will always have a small amount of drift, which will + prevent the echo canceller from adapting. +\end_layout + +\begin_layout Itemize +The delay between the record and playback signals must be minimal. + Any signal played has to +\begin_inset Quotes eld +\end_inset + +appear +\begin_inset Quotes erd +\end_inset + + on the playback (far end) signal slightly before the echo canceller +\begin_inset Quotes eld +\end_inset + +sees +\begin_inset Quotes erd +\end_inset + + it in the near end signal, but excessive delay means that part of the filter + length is wasted. + In the worst situations, the delay is such that it is longer than the filter + length, in which case, no echo can be cancelled. +\end_layout + +\begin_layout Itemize +When it comes to echo tail length (filter length), longer is +\series bold +not +\series default + better. + Actually, the longer the tail length, the longer it takes for the filter + to adapt. + Of course, a tail length that is too short will not cancel enough echo, + but the most common problem seen is that people set a very long tail length + and then wonder why no echo is being cancelled. +\end_layout + +\begin_layout Itemize +Non-linear distortion cannot (by definition) be modeled by the linear adaptive + filter used in the echo canceller and thus cannot be cancelled. + Use good audio gear and avoid saturation/clipping. +\end_layout + +\begin_layout Standard +Also useful is reading +\emph on +Echo Cancellation Demystified +\emph default + by Alexey Frunze +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +http://www.embeddedstar.com/articles/2003/7/article20030720-1.html +\end_layout + +\end_inset + +, which explains the fundamental principles of echo cancellation. + The details of the algorithm described in the article are different, but + the general ideas of echo cancellation through adaptive filters are the + same. +\end_layout + +\begin_layout Standard +As of version 1.2beta2, a new +\family typewriter +echo_diagnostic.m +\family default + tool is included in the source distribution. + The first step is to define DUMP_ECHO_CANCEL_DATA during the build. + This causes the echo canceller to automatically save the near-end, far-end + and output signals to files (aec_rec.sw aec_play.sw and aec_out.sw). + These are exactly what the AEC receives and outputs. + From there, it is necessary to start Octave and type: +\end_layout + +\begin_layout Standard +\begin_inset listings +lstparams "language=Matlab" +inline false +status open + +\begin_layout Plain Layout + +echo_diagnostic('aec_rec.sw', 'aec_play.sw', 'aec_diagnostic.sw', 1024); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The value of 1024 is the filter length and can be changed. + There will be some (hopefully) useful messages printed and echo cancelled + audio will be saved to aec_diagnostic.sw . + If even that output is bad (almost no cancellation) then there is probably + problem with the playback or recording process. +\end_layout + +\begin_layout Section +Jitter Buffer +\end_layout + +\begin_layout Standard +The jitter buffer can be enabled by including: +\begin_inset listings +lstparams "breaklines=true" +inline false +status open + +\begin_layout Plain Layout + +#include +\end_layout + +\end_inset + + and a new jitter buffer state can be initialised by: +\end_layout + +\begin_layout Standard +\begin_inset listings +lstparams "breaklines=true" +inline false +status open + +\begin_layout Plain Layout + +JitterBuffer *state = jitter_buffer_init(step); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +where the +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +step +\end_layout + +\end_inset + + argument is the default time step (in timestamp units) used for adjusting + the delay and doing concealment. + A value of 1 is always correct, but higher values may be more convenient + sometimes. + For example, if you are only able to do concealment on 20ms frames, there + is no point in the jitter buffer asking you to do it on one sample. + Another example is that for video, it makes no sense to adjust the delay + by less than a full frame. + The value provided can always be changed at a later time. +\end_layout + +\begin_layout Standard +The jitter buffer API is based on the +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +JitterBufferPacket +\end_layout + +\end_inset + + type, which is defined as: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +typedef struct { +\end_layout + +\begin_layout Plain Layout + + char *data; /* Data bytes contained in the packet */ +\end_layout + +\begin_layout Plain Layout + + spx_uint32_t len; /* Length of the packet in bytes */ +\end_layout + +\begin_layout Plain Layout + + spx_uint32_t timestamp; /* Timestamp for the packet */ +\end_layout + +\begin_layout Plain Layout + + spx_uint32_t span; /* Time covered by the packet (timestamp units) + */ +\end_layout + +\begin_layout Plain Layout + +} JitterBufferPacket; +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +As an example, for audio the timestamp field would be what is obtained from + the RTP timestamp field and the span would be the number of samples that + are encoded in the packet. + For Speex narrowband, span would be 160 if only one frame is included in + the packet. + +\end_layout + +\begin_layout Standard +When a packet arrives, it need to be inserter into the jitter buffer by: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +JitterBufferPacket packet; +\end_layout + +\begin_layout Plain Layout + +/* Fill in each field in the packet struct */ +\end_layout + +\begin_layout Plain Layout + +jitter_buffer_put(state, &packet); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +When the decoder is ready to decode a packet the packet to be decoded can + be obtained by: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +int start_offset; +\end_layout + +\begin_layout Plain Layout + +err = jitter_buffer_get(state, &packet, desired_span, &start_offset); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +If +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +jitter_buffer_put() +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +jitter_buffer_get() +\end_layout + +\end_inset + + are called from different threads, then +\series bold +you need to protect the jitter buffer state with a mutex +\series default +. + +\end_layout + +\begin_layout Standard +Because the jitter buffer is designed not to use an explicit timer, it needs + to be told about the time explicitly. + This is done by calling: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +jitter_buffer_tick(state); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +This needs to be done periodically in the playing thread. + This will be the last jitter buffer call before going to sleep (until more + data is played back). + In some cases, it may be preferable to use +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +jitter_buffer_remaining_span(state, remaining); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The second argument is used to specify that we are still holding data that + has not been written to the playback device. + For instance, if 256 samples were needed by the soundcard (specified by + +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +desired_span +\end_layout + +\end_inset + +), but +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +jitter_buffer_get() +\end_layout + +\end_inset + + returned 320 samples, we would have +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +remaining=64 +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Section +Resampler +\end_layout + +\begin_layout Standard +Speex includes a resampling modules. + To make use of the resampler, it is necessary to include its header file: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +#include +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +For each stream that is to be resampled, it is necessary to create a resampler + state with: +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +SpeexResamplerState *resampler; +\end_layout + +\begin_layout Plain Layout + +resampler = speex_resampler_init(nb_channels, input_rate, output_rate, quality, + &err); +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +where +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +nb_channels +\end_layout + +\end_inset + + is the number of channels that will be used (either interleaved or non-interlea +ved), +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +input_rate +\end_layout + +\end_inset + + is the sampling rate of the input stream, +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +output_rate +\end_layout + +\end_inset + + is the sampling rate of the output stream and +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +quality +\end_layout + +\end_inset + + is the requested quality setting (0 to 10). + The quality parameter is useful for controlling the quality/complexity/latency + tradeoff. + Using a higher quality setting means less noise/aliasing, a higher complexity + and a higher latency. + Usually, a quality of 3 is acceptable for most desktop uses and quality + 10 is mostly recommended for pro audio work. + Quality 0 usually has a decent sound (certainly better than using linear + interpolation resampling), but artifacts may be heard. +\end_layout + +\begin_layout Standard +The actual resampling is performed using +\end_layout + +\begin_layout Standard +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +err = speex_resampler_process_int(resampler, channelID, in, &in_length, + out, &out_length); +\end_layout + +\end_inset + +where +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +channelID +\end_layout + +\end_inset + + is the ID of the channel to be processed. + For a mono stream, use 0. + The +\emph on +in +\emph default + pointer points to the first sample of the input buffer for the selected + channel and +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +out +\end_layout + +\end_inset + + points to the first sample of the output. + The size of the input and output buffers are specified by +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +in_length +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +out_length +\end_layout + +\end_inset + + respectively. + Upon completion, these values are replaced by the number of samples read + and written by the resampler. + Unless an error occurs, either all input samples will be read or all output + samples will be written to (or both). + For floating-point samples, the function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +speex_resampler_process_float() +\end_layout + +\end_inset + + behaves similarly. +\end_layout + +\begin_layout Standard +It is also possible to process multiple channels at once. + To do that, you can use speex_resampler_process_interleaved_int() or +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +speex_resampler_process_interleaved_float() +\end_layout + +\end_inset + +. + The arguments are the same except that there is no +\begin_inset listings +inline true +status collapsed + +\begin_layout Plain Layout + +channelID +\end_layout + +\end_inset + + argument. + Note that the +\series bold +length parameters are per-channel +\series default +. + So if you have 1024 samples for each of 4 channels, you pass 1024 and not + 4096. +\end_layout + +\begin_layout Standard +The resampler allows changing the quality and input/output sampling frequencies + on the fly without glitches. + This can be done with calls such as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +speex_resampler_set_quality() +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +speex_resampler_set_rate() +\end_layout + +\end_inset + +. + The only side effect is that a new filter will have to be recomputed, consuming + many CPU cycles. + +\end_layout + +\begin_layout Standard +When resampling a file, it is often desirable to have the output file perfectly + synchronised with the input. + To do that, you need to call +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +speex_resampler_skip_zeros() +\end_layout + +\end_inset + + +\series bold +before +\series default + you start processing any samples. + For real-time applications (e.g. + VoIP), it is not recommended to do that as the first process frame will + be shorter to compensate for the delay (the skipped zeros). + Instead, in real-time applications you may want to know how many delay + is introduced by the resampler. + This can be done at run-time with +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +speex_resampler_get_input_latency() +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +speex_resampler_get_output_latency() +\end_layout + +\end_inset + + functions. + First function returns delay measured in samples at input samplerate, while + second returns delay measured in samples at output samplerate. +\end_layout + +\begin_layout Standard +To destroy a resampler state, just call +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +speex_resampler_destroy() +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Section +Ring Buffer +\end_layout + +\begin_layout Standard +In some cases, it is necessary to interface components that use different + block sizes. + For example, it is possible that the soundcard does not support reading/writing + in blocks of 20 +\begin_inset space ~ +\end_inset + +ms or sometimes, complicated resampling ratios mean that the blocks don't + always have the same time. + In thoses cases, it is often necessary to buffer a bit of audio using a + ring buffer. +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Formats and standards +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +standards +\end_layout + +\end_inset + + +\begin_inset CommandInset label +LatexCommand label +name "sec:Formats-and-standards" + +\end_inset + + +\end_layout + +\begin_layout Standard +Speex can encode speech in both narrowband and wideband and provides different + bit-rates. + However, not all features need to be supported by a certain implementation + or device. + In order to be called +\begin_inset Quotes eld +\end_inset + +Speex compatible +\begin_inset Quotes erd +\end_inset + + (whatever that means), an implementation must implement at least a basic + set of features. +\end_layout + +\begin_layout Standard +At the minimum, all narrowband modes of operation MUST be supported at the + decoder. + This includes the decoding of a wideband bit-stream by the narrowband decoder +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +The wideband bit-stream contains an embedded narrowband bit-stream which + can be decoded alone +\end_layout + +\end_inset + +. + If present, a wideband decoder MUST be able to decode a narrowband stream, + and MAY either be able to decode all wideband modes or be able to decode + the embedded narrowband part of all modes (which includes ignoring the + high-band bits). +\end_layout + +\begin_layout Standard +For encoders, at least one narrowband or wideband mode MUST be supported. + The main reason why all encoding modes do not have to be supported is that + some platforms may not be able to handle the complexity of encoding in + some modes. +\end_layout + +\begin_layout Section +RTP +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +RTP +\end_layout + +\end_inset + + Payload Format +\end_layout + +\begin_layout Standard +The RTP payload draft is included in appendix +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:IETF-draft" + +\end_inset + + and the latest version is available at +\begin_inset Flex URL +status collapsed + +\begin_layout Plain Layout + +http://www.speex.org/drafts/latest +\end_layout + +\end_inset + +. + This draft has been sent (2003/02/26) to the Internet Engineering Task + Force (IETF) and will be discussed at the March 18th meeting in San Francisco. + +\end_layout + +\begin_layout Section +MIME Type +\end_layout + +\begin_layout Standard +For now, you should use the MIME type audio/x-speex for Speex-in-Ogg. + We will apply for type +\family typewriter +audio/speex +\family default + in the near future. +\end_layout + +\begin_layout Section +Ogg +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +Ogg +\end_layout + +\end_inset + + file format +\end_layout + +\begin_layout Standard +Speex bit-streams can be stored in Ogg files. + In this case, the first packet of the Ogg file contains the Speex header + described in table +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:ogg_speex_header" + +\end_inset + +. + All integer fields in the headers are stored as little-endian. + The +\family typewriter +speex_string +\family default + field must contain the +\begin_inset Quotes eld +\end_inset + + +\family typewriter +Speex +\family default + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + +\begin_inset Quotes erd +\end_inset + + (with 3 trailing spaces), which identifies the bit-stream. + The next field, +\family typewriter +speex_version +\family default + contains the version of Speex that encoded the file. + For now, refer to speex_header.[ch] for more info. + The +\emph on +beginning of stream +\emph default + ( +\family typewriter +b_o_s +\family default +) flag is set to 1 for the header. + The header packet has +\family typewriter +packetno=0 +\family default + and +\family typewriter +granulepos=0 +\family default +. +\end_layout + +\begin_layout Standard +The second packet contains the Speex comment header. + The format used is the Vorbis comment format described here: http://www.xiph.org/ +ogg/vorbis/doc/v-comment.html . + This packet has +\family typewriter +packetno=1 +\family default + and +\family typewriter +granulepos=0 +\family default +. +\end_layout + +\begin_layout Standard +The third and subsequent packets each contain one or more (number found + in header) Speex frames. + These are identified with +\family typewriter +packetno +\family default + starting from 2 and the +\family typewriter +granulepos +\family default + is the number of the last sample encoded in that packet. + The last of these packets has the +\emph on +end of stream +\emph default + ( +\family typewriter +e_o_s +\family default +) flag is set to 1. +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement htbp +wide true +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +Field +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Type +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Size +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +speex_string +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +char[] +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +speex_version +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +char[] +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +20 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +speex_version_id +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +header_size +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +rate +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +mode +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +mode_bitstream_version +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +nb_channels +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +bitrate +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +frame_size +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +vbr +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +frames_per_packet +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +extra_headers +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +reserved1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +reserved2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +int +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Ogg/Speex header packet +\begin_inset CommandInset label +LatexCommand label +name "cap:ogg_speex_header" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +clearpage +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Chapter +Introduction to CELP Coding +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +CELP +\end_layout + +\end_inset + + +\begin_inset CommandInset label +LatexCommand label +name "sec:Introduction-to-CELP" + +\end_inset + + +\end_layout + +\begin_layout Quote +\align center + +\emph on +Do not meddle in the affairs of poles, for they are subtle and quick to + leave the unit circle. +\end_layout + +\begin_layout Standard +Speex is based on CELP, which stands for Code Excited Linear Prediction. + This section attempts to introduce the principles behind CELP, so if you + are already familiar with CELP, you can safely skip to section +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Speex-narrowband-mode" + +\end_inset + +. + The CELP technique is based on three ideas: +\end_layout + +\begin_layout Enumerate +The use of a linear prediction (LP) model to model the vocal tract +\end_layout + +\begin_layout Enumerate +The use of (adaptive and fixed) codebook entries as input (excitation) of + the LP model +\end_layout + +\begin_layout Enumerate +The search performed in closed-loop in a +\begin_inset Quotes eld +\end_inset + +perceptually weighted domain +\begin_inset Quotes erd +\end_inset + + +\end_layout + +\begin_layout Standard +This section describes the basic ideas behind CELP. + This is still a work in progress. +\end_layout + +\begin_layout Section +Source-Filter Model of Speech Prediction +\end_layout + +\begin_layout Standard +The source-filter model of speech production assumes that the vocal cords + are the source of spectrally flat sound (the excitation signal), and that + the vocal tract acts as a filter to spectrally shape the various sounds + of speech. + While still an approximation, the model is widely used in speech coding + because of its simplicity.Its use is also the reason why most speech codecs + (Speex included) perform badly on music signals. + The different phonemes can be distinguished by their excitation (source) + and spectral shape (filter). + Voiced sounds (e.g. + vowels) have an excitation signal that is periodic and that can be approximated + by an impulse train in the time domain or by regularly-spaced harmonics + in the frequency domain. + On the other hand, fricatives (such as the "s", "sh" and "f" sounds) have + an excitation signal that is similar to white Gaussian noise. + So called voice fricatives (such as "z" and "v") have excitation signal + composed of an harmonic part and a noisy part. +\end_layout + +\begin_layout Standard +The source-filter model is usually tied with the use of Linear prediction. + The CELP model is based on source-filter model, as can be seen from the + CELP decoder illustrated in Figure +\begin_inset CommandInset ref +LatexCommand ref +reference "fig:The-CELP-model" + +\end_inset + +. + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Graphics + filename celp_decoder.eps + width 45page% + keepAspectRatio + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +The CELP model of speech synthesis (decoder) +\begin_inset CommandInset label +LatexCommand label +name "fig:The-CELP-model" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Linear Prediction Coefficients (LPC) +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +linear prediction +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Linear prediction is at the base of many speech coding techniques, including + CELP. + The idea behind it is to predict the signal +\begin_inset Formula $x[n]$ +\end_inset + + using a linear combination of its past samples: +\end_layout + +\begin_layout Standard +\begin_inset Formula \[ +y[n]=\sum_{i=1}^{N}a_{i}x[n-i]\] + +\end_inset + +where +\begin_inset Formula $y[n]$ +\end_inset + + is the linear prediction of +\begin_inset Formula $x[n]$ +\end_inset + +. + The prediction error is thus given by: +\begin_inset Formula \[ +e[n]=x[n]-y[n]=x[n]-\sum_{i=1}^{N}a_{i}x[n-i]\] + +\end_inset + + +\end_layout + +\begin_layout Standard +The goal of the LPC analysis is to find the best prediction coefficients + +\begin_inset Formula $a_{i}$ +\end_inset + + which minimize the quadratic error function: +\begin_inset Formula \[ +E=\sum_{n=0}^{L-1}\left[e[n]\right]^{2}=\sum_{n=0}^{L-1}\left[x[n]-\sum_{i=1}^{N}a_{i}x[n-i]\right]^{2}\] + +\end_inset + +That can be done by making all derivatives +\begin_inset Formula $\frac{\partial E}{\partial a_{i}}$ +\end_inset + + equal to zero: +\begin_inset Formula \[ +\frac{\partial E}{\partial a_{i}}=\frac{\partial}{\partial a_{i}}\sum_{n=0}^{L-1}\left[x[n]-\sum_{i=1}^{N}a_{i}x[n-i]\right]^{2}=0\] + +\end_inset + + +\end_layout + +\begin_layout Standard +For an order +\begin_inset Formula $N$ +\end_inset + + filter, the filter coefficients +\begin_inset Formula $a_{i}$ +\end_inset + + are found by solving the system +\begin_inset Formula $N\times N$ +\end_inset + + linear system +\begin_inset Formula $\mathbf{Ra}=\mathbf{r}$ +\end_inset + +, where +\begin_inset Formula \[ +\mathbf{R}=\left[\begin{array}{cccc} +R(0) & R(1) & \cdots & R(N-1)\\ +R(1) & R(0) & \cdots & R(N-2)\\ +\vdots & \vdots & \ddots & \vdots\\ +R(N-1) & R(N-2) & \cdots & R(0)\end{array}\right]\] + +\end_inset + + +\begin_inset Formula \[ +\mathbf{r}=\left[\begin{array}{c} +R(1)\\ +R(2)\\ +\vdots\\ +R(N)\end{array}\right]\] + +\end_inset + +with +\begin_inset Formula $R(m)$ +\end_inset + +, the auto-correlation +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +auto-correlation +\end_layout + +\end_inset + + of the signal +\begin_inset Formula $x[n]$ +\end_inset + +, computed as: +\end_layout + +\begin_layout Standard +\begin_inset Formula \[ +R(m)=\sum_{i=0}^{N-1}x[i]x[i-m]\] + +\end_inset + + +\end_layout + +\begin_layout Standard +Because +\begin_inset Formula $\mathbf{R}$ +\end_inset + + is Hermitian Toeplitz, the Levinson-Durbin +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +Levinson-Durbin +\end_layout + +\end_inset + + algorithm can be used, making the solution to the problem +\begin_inset Formula $\mathcal{O}\left(N^{2}\right)$ +\end_inset + + instead of +\begin_inset Formula $\mathcal{O}\left(N^{3}\right)$ +\end_inset + +. + Also, it can be proven that all the roots of +\begin_inset Formula $A(z)$ +\end_inset + + are within the unit circle, which means that +\begin_inset Formula $1/A(z)$ +\end_inset + + is always stable. + This is in theory; in practice because of finite precision, there are two + commonly used techniques to make sure we have a stable filter. + First, we multiply +\begin_inset Formula $R(0)$ +\end_inset + + by a number slightly above one (such as 1.0001), which is equivalent to + adding noise to the signal. + Also, we can apply a window to the auto-correlation, which is equivalent + to filtering in the frequency domain, reducing sharp resonances. +\end_layout + +\begin_layout Section +Pitch Prediction +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +pitch +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +During voiced segments, the speech signal is periodic, so it is possible + to take advantage of that property by approximating the excitation signal + +\begin_inset Formula $e[n]$ +\end_inset + + by a gain times the past of the excitation: +\end_layout + +\begin_layout Standard +\begin_inset Formula \[ +e[n]\simeq p[n]=\beta e[n-T]\ ,\] + +\end_inset + +where +\begin_inset Formula $T$ +\end_inset + + is the pitch period, +\begin_inset Formula $\beta$ +\end_inset + + is the pitch gain. + We call that long-term prediction since the excitation is predicted from + +\begin_inset Formula $e[n-T]$ +\end_inset + + with +\begin_inset Formula $T\gg N$ +\end_inset + +. +\end_layout + +\begin_layout Section +Innovation Codebook +\end_layout + +\begin_layout Standard +The final excitation +\begin_inset Formula $e[n]$ +\end_inset + + will be the sum of the pitch prediction and an +\emph on +innovation +\emph default + signal +\begin_inset Formula $c[n]$ +\end_inset + + taken from a fixed codebook, hence the name +\emph on +Code +\emph default + Excited Linear Prediction. + The final excitation is given by +\end_layout + +\begin_layout Standard +\begin_inset Formula \[ +e[n]=p[n]+c[n]=\beta e[n-T]+c[n]\ .\] + +\end_inset + +The quantization of +\begin_inset Formula $c[n]$ +\end_inset + + is where most of the bits in a CELP codec are allocated. + It represents the information that couldn't be obtained either from linear + prediction or pitch prediction. + In the +\emph on +z +\emph default +-domain we can represent the final signal +\begin_inset Formula $X(z)$ +\end_inset + + as +\begin_inset Formula \[ +X(z)=\frac{C(z)}{A(z)\left(1-\beta z^{-T}\right)}\] + +\end_inset + + +\end_layout + +\begin_layout Section +Noise Weighting +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +error weighting +\end_layout + +\end_inset + + +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +analysis-by-synthesis +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Most (if not all) modern audio codecs attempt to +\begin_inset Quotes eld +\end_inset + +shape +\begin_inset Quotes erd +\end_inset + + the noise so that it appears mostly in the frequency regions where the + ear cannot detect it. + For example, the ear is more tolerant to noise in parts of the spectrum + that are louder and +\emph on +vice versa +\emph default +. + In order to maximize speech quality, CELP codecs minimize the mean square + of the error (noise) in the perceptually weighted domain. + This means that a perceptual noise weighting filter +\begin_inset Formula $W(z)$ +\end_inset + + is applied to the error signal in the encoder. + In most CELP codecs, +\begin_inset Formula $W(z)$ +\end_inset + + is a pole-zero weighting filter derived from the linear prediction coefficients + (LPC), generally using bandwidth expansion. + Let the spectral envelope be represented by the synthesis filter +\begin_inset Formula $1/A(z)$ +\end_inset + +, CELP codecs typically derive the noise weighting filter as +\begin_inset Formula \begin{equation} +W(z)=\frac{A(z/\gamma_{1})}{A(z/\gamma_{2})}\ ,\label{eq:gamma-weighting}\end{equation} + +\end_inset + +where +\begin_inset Formula $\gamma_{1}=0.9$ +\end_inset + + and +\begin_inset Formula $\gamma_{2}=0.6$ +\end_inset + + in the Speex reference implementation. + If a filter +\begin_inset Formula $A(z)$ +\end_inset + + has (complex) poles at +\begin_inset Formula $p_{i}$ +\end_inset + + in the +\begin_inset Formula $z$ +\end_inset + +-plane, the filter +\begin_inset Formula $A(z/\gamma)$ +\end_inset + + will have its poles at +\begin_inset Formula $p'_{i}=\gamma p_{i}$ +\end_inset + +, making it a flatter version of +\begin_inset Formula $A(z)$ +\end_inset + +. +\end_layout + +\begin_layout Standard +The weighting filter is applied to the error signal used to optimize the + codebook search through analysis-by-synthesis (AbS). + This results in a spectral shape of the noise that tends towards +\begin_inset Formula $1/W(z)$ +\end_inset + +. + While the simplicity of the model has been an important reason for the + success of CELP, it remains that +\begin_inset Formula $W(z)$ +\end_inset + + is a very rough approximation for the perceptually optimal noise weighting + function. + Fig. + +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:Standard-noise-shaping" + +\end_inset + + illustrates the noise shaping that results from Eq. + +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:gamma-weighting" + +\end_inset + +. + Throughout this paper, we refer to +\begin_inset Formula $W(z)$ +\end_inset + + as the noise weighting filter and to +\begin_inset Formula $1/W(z)$ +\end_inset + + as the noise shaping filter (or curve). +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Graphics + filename ref_shaping.eps + width 45page% + keepAspectRatio + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Standard noise shaping in CELP. + Arbitrary y-axis offset. +\begin_inset CommandInset label +LatexCommand label +name "cap:Standard-noise-shaping" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Analysis-by-Synthesis +\end_layout + +\begin_layout Standard +One of the main principles behind CELP is called Analysis-by-Synthesis (AbS), + meaning that the encoding (analysis) is performed by perceptually optimising + the decoded (synthesis) signal in a closed loop. + In theory, the best CELP stream would be produced by trying all possible + bit combinations and selecting the one that produces the best-sounding + decoded signal. + This is obviously not possible in practice for two reasons: the required + complexity is beyond any currently available hardware and the +\begin_inset Quotes eld +\end_inset + +best sounding +\begin_inset Quotes erd +\end_inset + + selection criterion implies a human listener. + +\end_layout + +\begin_layout Standard +In order to achieve real-time encoding using limited computing resources, + the CELP optimisation is broken down into smaller, more manageable, sequential + searches using the perceptual weighting function described earlier. +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +The Speex Decoder Specification +\end_layout + +\begin_layout Section +Narrowband decoder +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Subsection +Narrowband modes +\end_layout + +\begin_layout Standard +There are 7 different narrowband bit-rates defined for Speex, ranging from + 250 bps to 24.6 kbps, although the modes below 5.9 kbps should not be used + for speech. + The bit-allocation for each mode is detailed in table +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:bits-narrowband" + +\end_inset + +. + Each frame starts with the mode ID encoded with 4 bits which allows a range + from 0 to 15, though only the first 7 values are used (the others are reserved). + The parameters are listed in the table in the order they are packed in + the bit-stream. + All frame-based parameters are packed before sub-frame parameters. + The parameters for a certain sub-frame are all packed before the following + sub-frame is packed. + The +\begin_inset Quotes eld +\end_inset + +OL +\begin_inset Quotes erd +\end_inset + + in the parameter description means that the parameter is an open loop estimatio +n based on the whole frame. +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement h +wide true +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Tabular + + + + + + + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Update rate +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Wideband bit +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Mode ID +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +LSP +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +18 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +18 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +18 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +18 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +30 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +30 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +30 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +18 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +OL pitch +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +OL pitch gain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +OL Exc gain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Fine pitch +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +sub-frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Pitch gain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +sub-frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Innovation gain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +sub-frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Innovation VQ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +sub-frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +16 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +20 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +35 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +48 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +64 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +96 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +10 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Total +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +43 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +119 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +160 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +220 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +300 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +364 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +492 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +79 +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Bit allocation for narrowband modes +\begin_inset CommandInset label +LatexCommand label +name "cap:bits-narrowband" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +LSP decoding +\end_layout + +\begin_layout Standard +Depending on the mode, LSP parameters are encoded using either 18 bits or + 30 bits. +\end_layout + +\begin_layout Standard +Interpolation +\end_layout + +\begin_layout Standard +Safe margin +\end_layout + +\begin_layout Subsection +Adaptive codebook +\end_layout + +\begin_layout Standard +For rates of 8 kbit/s and above, the pitch period is encoded for each subframe. + The real period is +\begin_inset Formula $T=p_{i}+17$ +\end_inset + + where +\begin_inset Formula $p_{i}$ +\end_inset + + is a value encoded with 7 bits and 17 corresponds to the minimum pitch. + The maximum period is 144. + At 5.95 kbit/s (mode 2), the pitch period is similarly encoded, but only + once for the frame. + Each sub-frame then has a 2-bit offset that is added to the pitch value + of the frame. + In that case, the pitch for each sub-frame is equal to +\begin_inset Formula $T-1+offset$ +\end_inset + +. + For rates below 5.95 kbit/s, only the per-frame pitch is used and the pitch + is constant for all sub-frames. +\end_layout + +\begin_layout Standard +Speex uses a 3-tap predictor for rates of 5.95 kbit/s and above. + The three gain values are obtained from a 5-bit or a 7-bit codebook, depending + on the mode. + +\end_layout + +\begin_layout Subsection +Innovation codebook +\end_layout + +\begin_layout Standard +Split codebook, size and entries depend on bit-rate +\end_layout + +\begin_layout Standard +a 5-bit gain is encoder on a per-frame basis +\end_layout + +\begin_layout Standard +Depending on the mode, higher resolution per sub-frame +\end_layout + +\begin_layout Standard +innovation sub-vectors concatenated, gain applied +\end_layout + +\begin_layout Subsection +Perceptual enhancement +\end_layout + +\begin_layout Standard +Optional, implementation-defined. + +\end_layout + +\begin_layout Subsection +Bit-stream definition +\end_layout + +\begin_layout Standard +This section defines the bit-stream that is transmitted on the wire. + One speex packet consist of 1 frame header and 4 sub-frames: +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +Frame Header +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Subframe 1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Subframe2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Subframe 3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Subframe 4 +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Standard +The frame header is variable length, depending on decoding mode and submode. + The narrowband frame header is defined as follows: +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +wb bit +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +modeid +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +LSP +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +OL-pitch +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +OL-pitchgain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +OL ExcGain +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Standard +wb-bit: Wideband bit (1 bit) 0=narrowband, 1=wideband +\end_layout + +\begin_layout Standard +modeid: Mode identifier (4 bits) +\end_layout + +\begin_layout Standard +LSP: Line Spectral Pairs (0, 18 or 30 bits) +\end_layout + +\begin_layout Standard +OL-pitch: Open Loop Pitch (0 or 7 bits) +\end_layout + +\begin_layout Standard +OL-pitchgain: Open Loop Pitch Gain (0 or 4 bits) +\end_layout + +\begin_layout Standard +OL-ExcGain: Open Loop Excitation Gain (0 or 5 bits) +\end_layout + +\begin_layout Standard +... +\end_layout + +\begin_layout Standard +Each subframe is defined as follows: +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +FinePitch +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +PitchGain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +InnovationGain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Innovation VQ +\end_layout + +\end_inset + + + + +\end_inset + + +\end_layout + +\begin_layout Standard +FinePitch: (0 or 7 bits) +\end_layout + +\begin_layout Standard +PitchGain: (0, 5, or 7 bits) +\end_layout + +\begin_layout Standard +Innovation Gain: (0, 1, 3 bits) +\end_layout + +\begin_layout Standard +Innovation VQ: (0-96 bits) +\end_layout + +\begin_layout Standard +... +\end_layout + +\begin_layout Subsection +Sample decoder +\end_layout + +\begin_layout Standard +This section contains some sample source code, showing how a basic Speex + decoder can be implemented. + The sample decoder is narrowband submode 3 only, and with no advanced features + like enhancement, vbr etc. +\end_layout + +\begin_layout Standard +... +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "nb_celp.c" +lstparams "caption={Sample Decoder}" + +\end_inset + + +\end_layout + +\begin_layout Subsection +Lookup tables +\end_layout + +\begin_layout Standard +The Speex decoder includes a set of lookup tables and codebooks, which are + used to convert between values of different domains. + This includes: +\end_layout + +\begin_layout Standard +- Excitation 10x16 (3200 bps) +\end_layout + +\begin_layout Standard +- Excitation 10x32 (4000 bps) +\end_layout + +\begin_layout Standard +- Excitation 20x32 (2000 bps) +\end_layout + +\begin_layout Standard +- Excitation 5x256 (12800 bps) +\end_layout + +\begin_layout Standard +- Excitation 5x64 (9600 bps) +\end_layout + +\begin_layout Standard +- Excitation 8x128 (7000 bps) +\end_layout + +\begin_layout Standard +- Codebook for 3-tap pitch prediction gain (Normal and Low Bitrate) +\end_layout + +\begin_layout Standard +- Codebook for LSPs in narrowband CELP mode +\end_layout + +\begin_layout Standard +... +\end_layout + +\begin_layout Standard +The exact lookup tables are included here for reference. +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/exc_5_64_table.c" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/exc_5_256_table.c" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/exc_8_128_table.c" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/exc_10_16_table.c" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/exc_10_32_table.c" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/exc_20_32_table.c" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/gain_table.c" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/gain_table_lbr.c" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../libspeex/lsp_tables_nb.c" + +\end_inset + + +\end_layout + +\begin_layout Section +Wideband embedded decoder +\end_layout + +\begin_layout Standard +QMF filter. + Narrowband signal decoded using narrowband decoder +\end_layout + +\begin_layout Standard +For the high band, the decoder is similar to the narrowband decoder, with + the main difference being that there is no adaptive codebook. +\end_layout + +\begin_layout Standard +Gain is per-subframe +\end_layout + +\begin_layout Chapter +Speex narrowband mode +\begin_inset CommandInset label +LatexCommand label +name "sec:Speex-narrowband-mode" + +\end_inset + + +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +narrowband +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +This section looks at how Speex works for narrowband ( +\begin_inset Formula $8\:\mathrm{kHz}$ +\end_inset + + sampling rate) operation. + The frame size for this mode is +\begin_inset Formula $20\:\mathrm{ms}$ +\end_inset + +, corresponding to 160 samples. + Each frame is also subdivided into 4 sub-frames of 40 samples each. +\end_layout + +\begin_layout Standard +Also many design decisions were based on the original goals and assumptions: +\end_layout + +\begin_layout Itemize +Minimizing the amount of information extracted from past frames (for robustness + to packet loss) +\end_layout + +\begin_layout Itemize +Dynamically-selectable codebooks (LSP, pitch and innovation) +\end_layout + +\begin_layout Itemize +sub-vector fixed (innovation) codebooks +\end_layout + +\begin_layout Section +Whole-Frame Analysis +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +linear prediction +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +In narrowband, Speex frames are 20 ms long (160 samples) and are subdivided + in 4 sub-frames of 5 ms each (40 samples). + For most narrowband bit-rates (8 kbps and above), the only parameters encoded + at the frame level are the Line Spectral Pairs (LSP) and a global excitation + gain +\begin_inset Formula $g_{frame}$ +\end_inset + +, as shown in Fig. + +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:Frame-open-loop-analysis" + +\end_inset + +. + All other parameters are encoded at the sub-frame level. +\end_layout + +\begin_layout Standard +Linear prediction analysis is performed once per frame using an asymmetric + Hamming window centered on the fourth sub-frame. + Because linear prediction coefficients (LPC) are not robust to quantization, + they are first converted to line spectral pairs (LSP) +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +line spectral pair +\end_layout + +\end_inset + +. + The LSP's are considered to be associated to the +\begin_inset Formula $4^{th}$ +\end_inset + + sub-frames and the LSP's associated to the first 3 sub-frames are linearly + interpolated using the current and previous LSP coefficients. + The LSP coefficients and converted back to the LPC filter +\begin_inset Formula $\hat{A}(z)$ +\end_inset + +. + The non-quantized interpolated filter is denoted +\begin_inset Formula $A(z)$ +\end_inset + + and can be used for the weighting filter +\begin_inset Formula $W(z)$ +\end_inset + + because it does not need to be available to the decoder. + +\end_layout + +\begin_layout Standard +To make Speex more robust to packet loss, no prediction is applied on the + LSP coefficients prior to quantization. + The LSPs are encoded using vector quantization (VQ) with 30 bits for higher + quality modes and 18 bits for lower quality. +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Graphics + filename speex_analysis.eps + width 35page% + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Frame open-loop analysis +\begin_inset CommandInset label +LatexCommand label +name "cap:Frame-open-loop-analysis" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Sub-Frame Analysis-by-Synthesis +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Graphics + filename speex_abs.eps + lyxscale 75 + width 40page% + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Analysis-by-synthesis closed-loop optimization on a sub-frame. +\begin_inset CommandInset label +LatexCommand label +name "cap:Sub-frame-AbS" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The analysis-by-synthesis (AbS) encoder loop is described in Fig. + +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:Sub-frame-AbS" + +\end_inset + +. + There are three main aspects where Speex significantly differs from most + other CELP codecs. + First, while most recent CELP codecs make use of fractional pitch estimation + with a single gain, Speex uses an integer to encode the pitch period, but + uses a 3-tap predictor (3 gains). + The adaptive codebook contribution +\begin_inset Formula $e_{a}[n]$ +\end_inset + + can thus be expressed as: +\begin_inset Formula \begin{equation} +e_{a}[n]=g_{0}e[n-T-1]+g_{1}e[n-T]+g_{2}e[n-T+1]\label{eq:adaptive-3tap}\end{equation} + +\end_inset + +where +\begin_inset Formula $g_{0}$ +\end_inset + +, +\begin_inset Formula $g_{1}$ +\end_inset + + and +\begin_inset Formula $g_{2}$ +\end_inset + + are the jointly quantized pitch gains and +\begin_inset Formula $e[n]$ +\end_inset + + is the codec excitation memory. + It is worth noting that when the pitch is smaller than the sub-frame size, + we repeat the excitation at a period +\begin_inset Formula $T$ +\end_inset + +. + For example, when +\begin_inset Formula $n-T+1\geq0$ +\end_inset + +, we use +\begin_inset Formula $n-2T+1$ +\end_inset + + instead. + In most modes, the pitch period is encoded with 7 bits in the +\begin_inset Formula $\left[17,144\right]$ +\end_inset + + range and the +\begin_inset Formula $\beta_{i}$ +\end_inset + + coefficients are vector-quantized using 7 bits at higher bit-rates (15 + kbps narrowband and above) and 5 bits at lower bit-rates (11 kbps narrowband + and below). +\end_layout + +\begin_layout Standard +Many current CELP codecs use moving average (MA) prediction to encode the + fixed codebook gain. + This provides slightly better coding at the expense of introducing a dependency + on previously encoded frames. + A second difference is that Speex encodes the fixed codebook gain as the + product of the global excitation gain +\begin_inset Formula $g_{frame}$ +\end_inset + + with a sub-frame gain corrections +\begin_inset Formula $g_{subf}$ +\end_inset + +. + This increases robustness to packet loss by eliminating the inter-frame + dependency. + The sub-frame gain correction is encoded before the fixed codebook is searched + (not closed-loop optimized) and uses between 0 and 3 bits per sub-frame, + depending on the bit-rate. +\end_layout + +\begin_layout Standard +The third difference is that Speex uses sub-vector quantization of the innovatio +n (fixed codebook) signal instead of an algebraic codebook. + Each sub-frame is divided into sub-vectors of lengths ranging between 5 + and 20 samples. + Each sub-vector is chosen from a bitrate-dependent codebook and all sub-vectors + are concatenated to form a sub-frame. + As an example, the 3.95 kbps mode uses a sub-vector size of 20 samples with + 32 entries in the codebook (5 bits). + This means that the innovation is encoded with 10 bits per sub-frame, or + 2000 bps. + On the other hand, the 18.2 kbps mode uses a sub-vector size of 5 samples + with 256 entries in the codebook (8 bits), so the innovation uses 64 bits + per sub-frame, or 12800 bps. + +\end_layout + +\begin_layout Section +Bit-rates +\end_layout + +\begin_layout Standard +So far, no MOS (Mean Opinion Score +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +mean opinion score +\end_layout + +\end_inset + +) subjective evaluation has been performed for Speex. + In order to give an idea of the quality achievable with it, table +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:quality_vs_bps" + +\end_inset + + presents my own subjective opinion on it. + It should be noted that different people will perceive the quality differently + and that the person that designed the codec often has a bias (one way or + another) when it comes to subjective evaluation. + Last thing, it should be noted that for most codecs (including Speex) encoding + quality sometimes varies depending on the input. + Note that the complexity is only approximate (within 0.5 mflops and using + the lowest complexity setting). + Decoding requires approximately 0.5 mflops +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +complexity +\end_layout + +\end_inset + + in most modes (1 mflops with perceptual enhancement). +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement h +wide true +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Tabular + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +Mode +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Quality +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Bit-rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +bit-rate +\end_layout + +\end_inset + + (bps) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +mflops +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +complexity +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Quality/description +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +250 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +No transmission (DTX) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2,150 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Vocoder (mostly for comfort noise) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5,950 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +9 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Very noticeable artifacts/noise, good intelligibility +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3-4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +8,000 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +10 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Artifacts/noise sometimes noticeable +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5-6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +11,000 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +14 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Artifacts usually noticeable only with headphones +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7-8 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +15,000 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +11 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Need good headphones to tell the difference +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +9 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +18,200 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +17.5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Hard to tell the difference even with good headphones +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +10 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +24,600 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +14.5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Completely transparent for voice, good quality music +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3,950 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +10.5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Very noticeable artifacts/noise, good intelligibility +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +9 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +reserved +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +10 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +reserved +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +11 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +reserved +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +12 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +reserved +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +13 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Application-defined, interpreted by callback or skipped +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +14 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Speex in-band signaling +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +15 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +- +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Terminator code +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Quality versus bit-rate +\begin_inset CommandInset label +LatexCommand label +name "cap:quality_vs_bps" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Perceptual enhancement +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +perceptual enhancement +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +This section was only valid for version 1.1.12 and earlier. + It does not apply to version 1.2-beta1 (and later), for which the new perceptual + enhancement is not yet documented. +\end_layout + +\begin_layout Standard +This part of the codec only applies to the decoder and can even be changed + without affecting inter-operability. + For that reason, the implementation provided and described here should + only be considered as a reference implementation. + The enhancement system is divided into two parts. + First, the synthesis filter +\begin_inset Formula $S(z)=1/A(z)$ +\end_inset + + is replaced by an enhanced filter: +\begin_inset Formula \[ +S'(z)=\frac{A\left(z/a_{2}\right)A\left(z/a_{3}\right)}{A\left(z\right)A\left(z/a_{1}\right)}\] + +\end_inset + +where +\begin_inset Formula $a_{1}$ +\end_inset + + and +\begin_inset Formula $a_{2}$ +\end_inset + + depend on the mode in use and +\begin_inset Formula $a_{3}=\frac{1}{r}\left(1-\frac{1-ra_{1}}{1-ra_{2}}\right)$ +\end_inset + + with +\begin_inset Formula $r=.9$ +\end_inset + +. + The second part of the enhancement consists of using a comb filter to enhance + the pitch in the excitation domain. + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Speex wideband mode (sub-band CELP) +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +wideband +\end_layout + +\end_inset + + +\begin_inset CommandInset label +LatexCommand label +name "sec:Speex-wideband-mode" + +\end_inset + + +\end_layout + +\begin_layout Standard +For wideband, the Speex approach uses a +\emph on +q +\emph default +uadrature +\emph on +m +\emph default +irror +\emph on +f +\emph default +ilter +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +quadrature mirror filter +\end_layout + +\end_inset + + (QMF) to split the band in two. + The 16 kHz signal is thus divided into two 8 kHz signals, one representing + the low band (0-4 kHz), the other the high band (4-8 kHz). + The low band is encoded with the narrowband mode described in section +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Speex-narrowband-mode" + +\end_inset + + in such a way that the resulting +\begin_inset Quotes eld +\end_inset + +embedded narrowband bit-stream +\begin_inset Quotes erd +\end_inset + + can also be decoded with the narrowband decoder. + Since the low band encoding has already been described, only the high band + encoding is described in this section. +\end_layout + +\begin_layout Section +Linear Prediction +\end_layout + +\begin_layout Standard +The linear prediction part used for the high-band is very similar to what + is done for narrowband. + The only difference is that we use only 12 bits to encode the high-band + LSP's using a multi-stage vector quantizer (MSVQ). + The first level quantizes the 10 coefficients with 6 bits and the error + is then quantized using 6 bits, too. +\end_layout + +\begin_layout Section +Pitch Prediction +\end_layout + +\begin_layout Standard +That part is easy: there's no pitch prediction for the high-band. + There are two reasons for that. + First, there is usually little harmonic structure in this band (above 4 + kHz). + Second, it would be very hard to implement since the QMF folds the 4-8 + kHz band into 4-0 kHz (reversing the frequency axis), which means that + the location of the harmonics is no longer at multiples of the fundamental + (pitch). +\end_layout + +\begin_layout Section +Excitation Quantization +\end_layout + +\begin_layout Standard +The high-band excitation is coded in the same way as for narrowband. + +\end_layout + +\begin_layout Section +Bit allocation +\end_layout + +\begin_layout Standard +For the wideband mode, the entire narrowband frame is packed before the + high-band is encoded. + The narrowband part of the bit-stream is as defined in table +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:bits-narrowband" + +\end_inset + +. + The high-band follows, as described in table +\begin_inset CommandInset ref +LatexCommand ref +reference "cap:bits-wideband" + +\end_inset + +. + For wideband, the mode ID is the same as the Speex quality setting and + is defined in table +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:wideband-quality" + +\end_inset + +. + This also means that a wideband frame may be correctly decoded by a narrowband + decoder with the only caveat that if more than one frame is packed in the + same packet, the decoder will need to skip the high-band parts in order + to sync with the bit-stream. +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement h +wide true +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Tabular + + + + + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Update rate +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Wideband bit +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Mode ID +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +LSP +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +12 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +12 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +12 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +12 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Excitation gain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +sub-frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Excitation VQ +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +sub-frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +20 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +40 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +80 +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Total +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +frame +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +36 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +112 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +192 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +352 +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Bit allocation for high-band in wideband mode +\begin_inset CommandInset label +LatexCommand label +name "cap:bits-wideband" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Float table +placement h +wide true +sideways false +status open + +\begin_layout Plain Layout +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +begin{center} +\end_layout + +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +Mode/Quality +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Bit-rate +\begin_inset Index +status collapsed + +\begin_layout Plain Layout +bit-rate +\end_layout + +\end_inset + + (bps) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Quality/description +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +3,950 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Barely intelligible (mostly for comfort noise) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +5,750 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Very noticeable artifacts/noise, poor intelligibility +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +7,750 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Very noticeable artifacts/noise, good intelligibility +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +3 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +9,800 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Artifacts/noise sometimes annoying +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +12,800 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Artifacts/noise usually noticeable +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +16,800 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Artifacts/noise sometimes noticeable +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +6 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +20,600 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Need good headphones to tell the difference +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +7 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +23,800 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Need good headphones to tell the difference +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +8 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +27,800 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Hard to tell the difference even with good headphones +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +9 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +34,200 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Hard to tell the difference even with good headphones +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +10 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +42,200 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Completely transparent for voice, good quality music +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +end{center} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption + +\begin_layout Plain Layout +Quality versus bit-rate for the wideband encoder +\begin_inset CommandInset label +LatexCommand label +name "tab:wideband-quality" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +clearpage +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + + +\backslash +clearpage +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Chapter +\start_of_appendix +Sample code +\begin_inset CommandInset label +LatexCommand label +name "sec:Sample-code" + +\end_inset + + +\end_layout + +\begin_layout Standard +This section shows sample code for encoding and decoding speech using the + Speex API. + The commands can be used to encode and decode a file by calling: +\family typewriter + +\begin_inset Newline newline +\end_inset + +% sampleenc in_file.sw | sampledec out_file.sw +\family default + +\begin_inset Newline newline +\end_inset + +where both files are raw (no header) files encoded at 16 bits per sample + (in the machine natural endianness). +\end_layout + +\begin_layout Section +sampleenc.c +\end_layout + +\begin_layout Standard +sampleenc takes a raw 16 bits/sample file, encodes it and outputs a Speex + stream to stdout. + Note that the packing used is +\series bold +not +\series default + compatible with that of speexenc/speexdec. +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "sampleenc.c" +lstparams "caption={Source code for sampleenc},label={sampleenc-source-code},numbers=left,numberstyle={\\footnotesize}" + +\end_inset + + +\end_layout + +\begin_layout Section +sampledec.c +\end_layout + +\begin_layout Standard +sampledec reads a Speex stream from stdin, decodes it and outputs it to + a raw 16 bits/sample file. + Note that the packing used is +\series bold +not +\series default + compatible with that of speexenc/speexdec. +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "sampledec.c" +lstparams "caption={Source code for sampledec},label={sampledec-source-code},numbers=left,numberstyle={\\footnotesize}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Jitter Buffer for Speex +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand lstinputlisting +filename "../speexclient/speex_jitter_buffer.c" +lstparams "caption={Example of using the jitter buffer for Speex packets},label={example-speex-jitter},numbers=left,numberstyle={\\footnotesize}" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +IETF RTP Profile +\begin_inset CommandInset label +LatexCommand label +name "sec:IETF-draft" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand verbatiminput +filename "draft-ietf-avt-rtp-speex-05-tmp.txt" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +Speex License +\begin_inset CommandInset label +LatexCommand label +name "sec:Speex-License" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset CommandInset include +LatexCommand verbatiminput +filename "../COPYING" + +\end_inset + + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Chapter +GNU Free Documentation License +\end_layout + +\begin_layout Standard +Version 1.1, March 2000 +\end_layout + +\begin_layout Standard +Copyright (C) 2000 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted + to copy and distribute verbatim copies of this license document, but changing + it is not allowed. + +\end_layout + +\begin_layout Section* +0. + PREAMBLE +\end_layout + +\begin_layout Standard +The purpose of this License is to make a manual, textbook, or other written + document "free" in the sense of freedom: to assure everyone the effective + freedom to copy and redistribute it, with or without modifying it, either + commercially or noncommercially. + Secondarily, this License preserves for the author and publisher a way + to get credit for their work, while not being considered responsible for + modifications made by others. +\end_layout + +\begin_layout Standard +This License is a kind of "copyleft", which means that derivative works + of the document must themselves be free in the same sense. + It complements the GNU General Public License, which is a copyleft license + designed for free software. +\end_layout + +\begin_layout Standard +We have designed this License in order to use it for manuals for free software, + because free software needs free documentation: a free program should come + with manuals providing the same freedoms that the software does. + But this License is not limited to software manuals; it can be used for + any textual work, regardless of subject matter or whether it is published + as a printed book. + We recommend this License principally for works whose purpose is instruction + or reference. + +\end_layout + +\begin_layout Section* +1. + APPLICABILITY AND DEFINITIONS +\end_layout + +\begin_layout Standard +This License applies to any manual or other work that contains a notice + placed by the copyright holder saying it can be distributed under the terms + of this License. + The "Document", below, refers to any such manual or work. + Any member of the public is a licensee, and is addressed as "you". +\end_layout + +\begin_layout Standard +A "Modified Version" of the Document means any work containing the Document + or a portion of it, either copied verbatim, or with modifications and/or + translated into another language. +\end_layout + +\begin_layout Standard +A "Secondary Section" is a named appendix or a front-matter section of the + Document that deals exclusively with the relationship of the publishers + or authors of the Document to the Document's overall subject (or to related + matters) and contains nothing that could fall directly within that overall + subject. + (For example, if the Document is in part a textbook of mathematics, a Secondary + Section may not explain any mathematics.) The relationship could be a matter + of historical connection with the subject or with related matters, or of + legal, commercial, philosophical, ethical or political position regarding + them. +\end_layout + +\begin_layout Standard +The "Invariant Sections" are certain Secondary Sections whose titles are + designated, as being those of Invariant Sections, in the notice that says + that the Document is released under this License. +\end_layout + +\begin_layout Standard +The "Cover Texts" are certain short passages of text that are listed, as + Front-Cover Texts or Back-Cover Texts, in the notice that says that the + Document is released under this License. +\end_layout + +\begin_layout Standard +A "Transparent" copy of the Document means a machine-readable copy, represented + in a format whose specification is available to the general public, whose + contents can be viewed and edited directly and straightforwardly with generic + text editors or (for images composed of pixels) generic paint programs + or (for drawings) some widely available drawing editor, and that is suitable + for input to text formatters or for automatic translation to a variety + of formats suitable for input to text formatters. + A copy made in an otherwise Transparent file format whose markup has been + designed to thwart or discourage subsequent modification by readers is + not Transparent. + A copy that is not "Transparent" is called "Opaque". +\end_layout + +\begin_layout Standard +Examples of suitable formats for Transparent copies include plain ASCII + without markup, Texinfo input format, LaTeX input format, SGML or XML using + a publicly available DTD, and standard-conforming simple HTML designed + for human modification. + Opaque formats include PostScript, PDF, proprietary formats that can be + read and edited only by proprietary word processors, SGML or XML for which + the DTD and/or processing tools are not generally available, and the machine-ge +nerated HTML produced by some word processors for output purposes only. +\end_layout + +\begin_layout Standard +The "Title Page" means, for a printed book, the title page itself, plus + such following pages as are needed to hold, legibly, the material this + License requires to appear in the title page. + For works in formats which do not have any title page as such, "Title Page" + means the text near the most prominent appearance of the work's title, + preceding the beginning of the body of the text. +\end_layout + +\begin_layout Section* +2. + VERBATIM COPYING +\end_layout + +\begin_layout Standard +You may copy and distribute the Document in any medium, either commercially + or noncommercially, provided that this License, the copyright notices, + and the license notice saying this License applies to the Document are + reproduced in all copies, and that you add no other conditions whatsoever + to those of this License. + You may not use technical measures to obstruct or control the reading or + further copying of the copies you make or distribute. + However, you may accept compensation in exchange for copies. + If you distribute a large enough number of copies you must also follow + the conditions in section 3. +\end_layout + +\begin_layout Standard +You may also lend copies, under the same conditions stated above, and you + may publicly display copies. +\end_layout + +\begin_layout Section* +3. + COPYING IN QUANTITY +\end_layout + +\begin_layout Standard +If you publish printed copies of the Document numbering more than 100, and + the Document's license notice requires Cover Texts, you must enclose the + copies in covers that carry, clearly and legibly, all these Cover Texts: + Front-Cover Texts on the front cover, and Back-Cover Texts on the back + cover. + Both covers must also clearly and legibly identify you as the publisher + of these copies. + The front cover must present the full title with all words of the title + equally prominent and visible. + You may add other material on the covers in addition. + Copying with changes limited to the covers, as long as they preserve the + title of the Document and satisfy these conditions, can be treated as verbatim + copying in other respects. +\end_layout + +\begin_layout Standard +If the required texts for either cover are too voluminous to fit legibly, + you should put the first ones listed (as many as fit reasonably) on the + actual cover, and continue the rest onto adjacent pages. +\end_layout + +\begin_layout Standard +If you publish or distribute Opaque copies of the Document numbering more + than 100, you must either include a machine-readable Transparent copy along + with each Opaque copy, or state in or with each Opaque copy a publicly-accessib +le computer-network location containing a complete Transparent copy of the + Document, free of added material, which the general network-using public + has access to download anonymously at no charge using public-standard network + protocols. + If you use the latter option, you must take reasonably prudent steps, when + you begin distribution of Opaque copies in quantity, to ensure that this + Transparent copy will remain thus accessible at the stated location until + at least one year after the last time you distribute an Opaque copy (directly + or through your agents or retailers) of that edition to the public. +\end_layout + +\begin_layout Standard +It is requested, but not required, that you contact the authors of the Document + well before redistributing any large number of copies, to give them a chance + to provide you with an updated version of the Document. + +\end_layout + +\begin_layout Section* +4. + MODIFICATIONS +\end_layout + +\begin_layout Standard +You may copy and distribute a Modified Version of the Document under the + conditions of sections 2 and 3 above, provided that you release the Modified + Version under precisely this License, with the Modified Version filling + the role of the Document, thus licensing distribution and modification + of the Modified Version to whoever possesses a copy of it. + In addition, you must do these things in the Modified Version: +\end_layout + +\begin_layout Itemize +A. + Use in the Title Page (and on the covers, if any) a title distinct from + that of the Document, and from those of previous versions (which should, + if there were any, be listed in the History section of the Document). + You may use the same title as a previous version if the original publisher + of that version gives permission. +\end_layout + +\begin_layout Itemize +B. + List on the Title Page, as authors, one or more persons or entities responsible + for authorship of the modifications in the Modified Version, together with + at least five of the principal authors of the Document (all of its principal + authors, if it has less than five). +\end_layout + +\begin_layout Itemize +C. + State on the Title page the name of the publisher of the Modified Version, + as the publisher. +\end_layout + +\begin_layout Itemize +D. + Preserve all the copyright notices of the Document. +\end_layout + +\begin_layout Itemize +E. + Add an appropriate copyright notice for your modifications adjacent to + the other copyright notices. +\end_layout + +\begin_layout Itemize +F. + Include, immediately after the copyright notices, a license notice giving + the public permission to use the Modified Version under the terms of this + License, in the form shown in the Addendum below. +\end_layout + +\begin_layout Itemize +G. + Preserve in that license notice the full lists of Invariant Sections and + required Cover Texts given in the Document's license notice. +\end_layout + +\begin_layout Itemize +H. + Include an unaltered copy of this License. +\end_layout + +\begin_layout Itemize +I. + Preserve the section entitled "History", and its title, and add to it an + item stating at least the title, year, new authors, and publisher of the + Modified Version as given on the Title Page. + If there is no section entitled "History" in the Document, create one stating + the title, year, authors, and publisher of the Document as given on its + Title Page, then add an item describing the Modified Version as stated + in the previous sentence. +\end_layout + +\begin_layout Itemize +J. + Preserve the network location, if any, given in the Document for public + access to a Transparent copy of the Document, and likewise the network + locations given in the Document for previous versions it was based on. + These may be placed in the "History" section. + You may omit a network location for a work that was published at least + four years before the Document itself, or if the original publisher of + the version it refers to gives permission. +\end_layout + +\begin_layout Itemize +K. + In any section entitled "Acknowledgements" or "Dedications", preserve the + section's title, and preserve in the section all the substance and tone + of each of the contributor acknowledgements and/or dedications given therein. +\end_layout + +\begin_layout Itemize +L. + Preserve all the Invariant Sections of the Document, unaltered in their + text and in their titles. + Section numbers or the equivalent are not considered part of the section + titles. +\end_layout + +\begin_layout Itemize +M. + Delete any section entitled "Endorsements". + Such a section may not be included in the Modified Version. +\end_layout + +\begin_layout Itemize +N. + Do not retitle any existing section as "Endorsements" or to conflict in + title with any Invariant Section. + +\end_layout + +\begin_layout Standard +If the Modified Version includes new front-matter sections or appendices + that qualify as Secondary Sections and contain no material copied from + the Document, you may at your option designate some or all of these sections + as invariant. + To do this, add their titles to the list of Invariant Sections in the Modified + Version's license notice. + These titles must be distinct from any other section titles. +\end_layout + +\begin_layout Standard +You may add a section entitled "Endorsements", provided it contains nothing + but endorsements of your Modified Version by various parties--for example, + statements of peer review or that the text has been approved by an organization + as the authoritative definition of a standard. +\end_layout + +\begin_layout Standard +You may add a passage of up to five words as a Front-Cover Text, and a passage + of up to 25 words as a Back-Cover Text, to the end of the list of Cover + Texts in the Modified Version. + Only one passage of Front-Cover Text and one of Back-Cover Text may be + added by (or through arrangements made by) any one entity. + If the Document already includes a cover text for the same cover, previously + added by you or by arrangement made by the same entity you are acting on + behalf of, you may not add another; but you may replace the old one, on + explicit permission from the previous publisher that added the old one. +\end_layout + +\begin_layout Standard +The author(s) and publisher(s) of the Document do not by this License give + permission to use their names for publicity for or to assert or imply endorseme +nt of any Modified Version. + +\end_layout + +\begin_layout Section* +5. + COMBINING DOCUMENTS +\end_layout + +\begin_layout Standard +You may combine the Document with other documents released under this License, + under the terms defined in section 4 above for modified versions, provided + that you include in the combination all of the Invariant Sections of all + of the original documents, unmodified, and list them all as Invariant Sections + of your combined work in its license notice. +\end_layout + +\begin_layout Standard +The combined work need only contain one copy of this License, and multiple + identical Invariant Sections may be replaced with a single copy. + If there are multiple Invariant Sections with the same name but different + contents, make the title of each such section unique by adding at the end + of it, in parentheses, the name of the original author or publisher of + that section if known, or else a unique number. + Make the same adjustment to the section titles in the list of Invariant + Sections in the license notice of the combined work. +\end_layout + +\begin_layout Standard +In the combination, you must combine any sections entitled "History" in + the various original documents, forming one section entitled "History"; + likewise combine any sections entitled "Acknowledgements", and any sections + entitled "Dedications". + You must delete all sections entitled "Endorsements." +\end_layout + +\begin_layout Section* +6. + COLLECTIONS OF DOCUMENTS +\end_layout + +\begin_layout Standard +You may make a collection consisting of the Document and other documents + released under this License, and replace the individual copies of this + License in the various documents with a single copy that is included in + the collection, provided that you follow the rules of this License for + verbatim copying of each of the documents in all other respects. +\end_layout + +\begin_layout Standard +You may extract a single document from such a collection, and distribute + it individually under this License, provided you insert a copy of this + License into the extracted document, and follow this License in all other + respects regarding verbatim copying of that document. + +\end_layout + +\begin_layout Section* +7. + AGGREGATION WITH INDEPENDENT WORKS +\end_layout + +\begin_layout Standard +A compilation of the Document or its derivatives with other separate and + independent documents or works, in or on a volume of a storage or distribution + medium, does not as a whole count as a Modified Version of the Document, + provided no compilation copyright is claimed for the compilation. + Such a compilation is called an "aggregate", and this License does not + apply to the other self-contained works thus compiled with the Document, + on account of their being thus compiled, if they are not themselves derivative + works of the Document. +\end_layout + +\begin_layout Standard +If the Cover Text requirement of section 3 is applicable to these copies + of the Document, then if the Document is less than one quarter of the entire + aggregate, the Document's Cover Texts may be placed on covers that surround + only the Document within the aggregate. + Otherwise they must appear on covers around the whole aggregate. +\end_layout + +\begin_layout Section* +8. + TRANSLATION +\end_layout + +\begin_layout Standard +Translation is considered a kind of modification, so you may distribute + translations of the Document under the terms of section 4. + Replacing Invariant Sections with translations requires special permission + from their copyright holders, but you may include translations of some + or all Invariant Sections in addition to the original versions of these + Invariant Sections. + You may include a translation of this License provided that you also include + the original English version of this License. + In case of a disagreement between the translation and the original English + version of this License, the original English version will prevail. +\end_layout + +\begin_layout Section* +9. + TERMINATION +\end_layout + +\begin_layout Standard +You may not copy, modify, sublicense, or distribute the Document except + as expressly provided for under this License. + Any other attempt to copy, modify, sublicense or distribute the Document + is void, and will automatically terminate your rights under this License. + However, parties who have received copies, or rights, from you under this + License will not have their licenses terminated so long as such parties + remain in full compliance. + +\end_layout + +\begin_layout Section* +10. + FUTURE REVISIONS OF THIS LICENSE +\end_layout + +\begin_layout Standard +The Free Software Foundation may publish new, revised versions of the GNU + Free Documentation License from time to time. + Such new versions will be similar in spirit to the present version, but + may differ in detail to address new problems or concerns. + See http://www.gnu.org/copyleft/. +\end_layout + +\begin_layout Standard +Each version of the License is given a distinguishing version number. + If the Document specifies that a particular numbered version of this License + "or any later version" applies to it, you have the option of following + the terms and conditions either of that specified version or of any later + version that has been published (not as a draft) by the Free Software Foundatio +n. + If the Document does not specify a version number of this License, you + may choose any version ever published (not as a draft) by the Free Software + Foundation. +\end_layout + +\begin_layout Standard +\begin_inset CommandInset index_print +LatexCommand printindex + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/native/codec/libraries/speex/doc/manual.pdf b/native/codec/libraries/speex/doc/manual.pdf new file mode 100644 index 0000000..292f304 Binary files /dev/null and b/native/codec/libraries/speex/doc/manual.pdf differ diff --git a/native/codec/libraries/speex/doc/nb_celp.c b/native/codec/libraries/speex/doc/nb_celp.c new file mode 100644 index 0000000..50d5ffa --- /dev/null +++ b/native/codec/libraries/speex/doc/nb_celp.c @@ -0,0 +1,182 @@ +#include +#include "nb_celp.h" +#include "lsp.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "filters.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +#define LSP_MARGIN .002f +#define SIG_SCALING 1.f +#define NB_DEC_BUFFER (NB_FRAME_SIZE+2*NB_PITCH_END+NB_SUBFRAME_SIZE+12) +#define NB_ORDER 10 +#define NB_FRAME_SIZE 160 +#define NB_SUBFRAME_SIZE 40 +#define NB_NB_SUBFRAMES 4 +#define NB_PITCH_START 17 +#define NB_PITCH_END 144 + + +struct speex_decode_state { + float excBuf[NB_DEC_BUFFER]; /**< Excitation buffer */ + float *exc; /**< Start of excitation frame */ + float old_qlsp[10]; /**< Quantized LSPs for previous frame */ + float interp_qlpc[10]; /**< Interpolated quantized LPCs */ + float mem_sp[10]; /**< Filter memory for synthesis signal */ + int first; /**< Is this the first frame? */ +}; + + +static const float exc_gain_quant_scal1[2] = {0.70469f, 1.05127f}; + + +struct speex_decode_state *nb_decoder_init(void) +{ + struct speex_decode_state *st; + + st = malloc(sizeof(*st)); + if (!st) + return NULL; + + memset(st, 0, sizeof(*st)); + st->first = 1; + + return st; +} + + +void nb_decoder_destroy(struct speex_decode_state *state) +{ + if (state) + free(state); +} + + +/* basic decoder using mode3 only */ +int nb_decode(struct speex_decode_state *st, SpeexBits *bits, float *out) +{ + int i, sub, wideband, mode, qe; + float ol_gain; + float innov[NB_SUBFRAME_SIZE]; + float exc32[NB_SUBFRAME_SIZE]; + float qlsp[NB_ORDER], interp_qlsp[NB_ORDER]; + float ak[NB_ORDER]; + + if (!bits) + return -1; + + st->exc = st->excBuf + 2*NB_PITCH_END + NB_SUBFRAME_SIZE + 6; + + /* Decode Sub-modes */ + do { + if (speex_bits_remaining(bits) < 5) + return -1; + + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) { + printf("wideband not supported\n"); + return -2; + } + + mode = speex_bits_unpack_unsigned(bits, 4); + if (mode == 15) + return -1; + + } while (mode > 8); + + if (mode != 3) { + printf("only mode 3 supported\n"); + return -2; + } + + /* Shift all buffers by one frame */ + SPEEX_MOVE(st->excBuf, st->excBuf+NB_FRAME_SIZE, + 2*NB_PITCH_END + NB_SUBFRAME_SIZE + 12); + + /* Unquantize LSPs */ + lsp_unquant_lbr(qlsp, NB_ORDER, bits); + + /* Handle first frame */ + if (st->first) { + st->first = 0; + + for (i=0; iold_qlsp[i] = qlsp[i]; + } + + /* Get global excitation gain */ + qe = speex_bits_unpack_unsigned(bits, 5); + ol_gain = SIG_SCALING*exp(qe/3.5); + + /* Loop on subframes */ + for (sub=0; sub<4; sub++) { + int offset, q_energy; + float *exc, *sp; + float ener; + + offset = NB_SUBFRAME_SIZE*sub; + exc = st->exc + offset; + sp = out + offset; + + SPEEX_MEMSET(exc, 0, NB_SUBFRAME_SIZE); + + /* Adaptive codebook contribution */ + pitch_unquant_3tap(exc, exc32, NB_PITCH_START, + NB_SUBFRAME_SIZE, bits, 0); + + sanitize_values32(exc32, -32000, 32000, NB_SUBFRAME_SIZE); + + /* Unquantize the innovation */ + SPEEX_MEMSET(innov, 0, NB_SUBFRAME_SIZE); + + /* Decode sub-frame gain correction */ + q_energy = speex_bits_unpack_unsigned(bits, 1); + ener = exc_gain_quant_scal1[q_energy] * ol_gain; + + /* Fixed codebook contribution */ + split_cb_shape_sign_unquant(innov, bits); + + /* De-normalize innovation and update excitation */ + signal_mul(innov, innov, ener, NB_SUBFRAME_SIZE); + + for (i=0; iexc[-NB_SUBFRAME_SIZE], NB_FRAME_SIZE); + + /* Loop on subframes */ + for (sub=0; sub<4; sub++) { + const int offset = NB_SUBFRAME_SIZE*sub; + float *sp, *exc; + + sp = out + offset; + exc = st->exc + offset; + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, NB_ORDER, + sub, NB_NB_SUBFRAMES, LSP_MARGIN); + + /* Compute interpolated LPCs (unquantized) */ + lsp_to_lpc(interp_qlsp, ak, NB_ORDER); + + iir_mem16(sp, st->interp_qlpc, sp, NB_SUBFRAME_SIZE, + NB_ORDER, st->mem_sp); + + /* Save for interpolation in next frame */ + for (i=0; iinterp_qlpc[i] = ak[i]; + } + + /* Store the LSPs for interpolation in the next frame */ + for (i=0; iold_qlsp[i] = qlsp[i]; + + return 0; +} diff --git a/native/codec/libraries/speex/doc/programming.html b/native/codec/libraries/speex/doc/programming.html new file mode 100644 index 0000000..7b5bc7a --- /dev/null +++ b/native/codec/libraries/speex/doc/programming.html @@ -0,0 +1,125 @@ + + + + Speex Programming + + + + + +
    +

    Speex Programming

    + +
    +

    Encoding

    + In order to encode speech using Speex, you first need to:
    + +
    +
    #include <speex.h>
    +
    + You then need to declare a Speex bit-packing struct
    + +
    +
    SpeexBits bits;
    +
    + and a Speex encoder state
    + +
    +
    void *enc_state;
    +
    + The two are initialized by:
    + +
    +
    speex_bits_init(&bits);
    + +
    enc_state = speex_encoder_init(&speex_nb_mode);
    +
    + For wideband coding, speex_nb_mode will be replaced by speex_wb_mode +. In most cases, you will need to know the frame size used by the mode you +are using. You can get that value in the frame_size variable with:
    +
    speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &frame_size);
    +
    + For every input frame:
    + +
    +
    speex_bits_reset(&bits);
    + +
    speex_encode(enc_state, input_frame, &bits);
    + +
    nbBytes = speex_bits_write(&bits, byte_ptr, MAX_NB_BYTES);
    +
    + where input_frame is a (float *) pointing to the beginning +of a speech frame, byte_ptr is a (char *) where the encoded frame will +be written, MAX_NB_BYTES is the maximum number of bytes that can be +written to byte_ptr without causing an overflow and nbBytes + is the number of bytes actually written to byte_ptr (the encoded +size in bytes).
    +
    + After you're done with the encoding, free all resources with:
    + +
    +
    speex_bits_destroy(&bits);
    + +
    speex_encoder_destroy(&enc_state);
    +
    + That's about it for the encoder.
    + +

    Decoding

    + In order to encode speech using Speex, you first need to:
    + +
    +
    #include <speex.h>
    +
    + You then need to declare a Speex bit-packing struct
    + +
    +
    SpeexBits bits;
    +
    + and a Speex encoder state
    + +
    +
    void *dec_state;
    +
    + The two are initialized by:
    + +
    +
    speex_bits_init(&bits);
    + +
    dec_state = speex_decoder_init(&speex_nb_mode);
    +
    + For wideband decoding, speex_nb_mode will be replaced by speex_wb_mode +. You can get that value in the frame_size variable with:
    + +
    speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &frame_size);
    +
    + There is also a parameter that can be set for the decoder: whether or not +to use a perceptual post-filter. This can be set by:
    +
    speex_decoder_ctl(dec_state, SPEEX_SET_PF, &pf);
    +
    +where pf is an int that with value 0 to have the post-filter +disabled and 1 to have it enabled.
    +
    +For every input frame:
    + +
    +
    speex_bits_read_from(&bits, input_bytes, nbBytes);
    + +
    speex_decode(st, &bits, output_frame, 0);
    +
    + where input_bytes is a (char *) containing the bit-stream +data received for a frame, nbBytes is the size (in bytes) of that +bit-stream, and output_frame is a (float *) and points to the +area where the decoded speech frame will be written. The last argument indicates +whether the frame we'd like to decode was lost. A value of 0 indicates the +normal case where bits points to the bit of the current frame. A value of +1 indicates that we don't have the bits for the current frame, in which case +the bits argument should be the same as the bits for the last correctly received +frame. When a frame is lost, the Speex decoder will do its best to "guess" +the sorrect signal.
    +
    +
    +
    + + + diff --git a/native/codec/libraries/speex/doc/ref_shaping.eps b/native/codec/libraries/speex/doc/ref_shaping.eps new file mode 100644 index 0000000..4ef7007 --- /dev/null +++ b/native/codec/libraries/speex/doc/ref_shaping.eps @@ -0,0 +1,2045 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: printout.eps +%%Creator: gnuplot 4.0 patchlevel 0 +%%CreationDate: Mon Mar 6 17:15:27 2006 +%%DocumentFonts: (atend) +%%BoundingBox: 50 50 410 302 +%%Orientation: Portrait +%%EndComments +/gnudict 256 dict def +gnudict begin +/Color true def +/Solid false def +/gnulinewidth 5.000 def +/userlinewidth gnulinewidth def +/vshift -46 def +/dl {10.0 mul} def +/hpt_ 31.5 def +/vpt_ 31.5 def +/hpt hpt_ def +/vpt vpt_ def +/Rounded false def +/M {moveto} bind def +/L {lineto} bind def +/R {rmoveto} bind def +/V {rlineto} bind def +/N {newpath moveto} bind def +/C {setrgbcolor} bind def +/f {rlineto fill} bind def +/vpt2 vpt 2 mul def +/hpt2 hpt 2 mul def +/Lshow { currentpoint stroke M + 0 vshift R show } def +/Rshow { currentpoint stroke M + dup stringwidth pop neg vshift R show } def +/Cshow { currentpoint stroke M + dup stringwidth pop -2 div vshift R show } def +/UP { dup vpt_ mul /vpt exch def hpt_ mul /hpt exch def + /hpt2 hpt 2 mul def /vpt2 vpt 2 mul def } def +/DL { Color {setrgbcolor Solid {pop []} if 0 setdash } + {pop pop pop 0 setgray Solid {pop []} if 0 setdash} ifelse } def +/BL { stroke userlinewidth 2 mul setlinewidth + Rounded { 1 setlinejoin 1 setlinecap } if } def +/AL { stroke userlinewidth 2 div setlinewidth + Rounded { 1 setlinejoin 1 setlinecap } if } def +/UL { dup gnulinewidth mul /userlinewidth exch def + dup 1 lt {pop 1} if 10 mul /udl exch def } def +/PL { stroke userlinewidth setlinewidth + Rounded { 1 setlinejoin 1 setlinecap } if } def +/LTw { PL [] 1 setgray } def +/LTb { BL [] 0 0 0 DL } def +/LTa { AL [1 udl mul 2 udl mul] 0 setdash 0 0 0 setrgbcolor } def +/LT0 { PL [] 1 0 0 DL } def +/LT1 { PL [4 dl 2 dl] 0 1 0 DL } def +/LT2 { PL [2 dl 3 dl] 0 0 1 DL } def +/LT3 { PL [1 dl 1.5 dl] 1 0 1 DL } def +/LT4 { PL [5 dl 2 dl 1 dl 2 dl] 0 1 1 DL } def +/LT5 { PL [4 dl 3 dl 1 dl 3 dl] 1 1 0 DL } def +/LT6 { PL [2 dl 2 dl 2 dl 4 dl] 0 0 0 DL } def +/LT7 { PL [2 dl 2 dl 2 dl 2 dl 2 dl 4 dl] 1 0.3 0 DL } def +/LT8 { PL [2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 4 dl] 0.5 0.5 0.5 DL } def +/Pnt { stroke [] 0 setdash + gsave 1 setlinecap M 0 0 V stroke grestore } def +/Dia { stroke [] 0 setdash 2 copy vpt add M + hpt neg vpt neg V hpt vpt neg V + hpt vpt V hpt neg vpt V closepath stroke + Pnt } def +/Pls { stroke [] 0 setdash vpt sub M 0 vpt2 V + currentpoint stroke M + hpt neg vpt neg R hpt2 0 V stroke + } def +/Box { stroke [] 0 setdash 2 copy exch hpt sub exch vpt add M + 0 vpt2 neg V hpt2 0 V 0 vpt2 V + hpt2 neg 0 V closepath stroke + Pnt } def +/Crs { stroke [] 0 setdash exch hpt sub exch vpt add M + hpt2 vpt2 neg V currentpoint stroke M + hpt2 neg 0 R hpt2 vpt2 V stroke } def +/TriU { stroke [] 0 setdash 2 copy vpt 1.12 mul add M + hpt neg vpt -1.62 mul V + hpt 2 mul 0 V + hpt neg vpt 1.62 mul V closepath stroke + Pnt } def +/Star { 2 copy Pls Crs } def +/BoxF { stroke [] 0 setdash exch hpt sub exch vpt add M + 0 vpt2 neg V hpt2 0 V 0 vpt2 V + hpt2 neg 0 V closepath fill } def +/TriUF { stroke [] 0 setdash vpt 1.12 mul add M + hpt neg vpt -1.62 mul V + hpt 2 mul 0 V + hpt neg vpt 1.62 mul V closepath fill } def +/TriD { stroke [] 0 setdash 2 copy vpt 1.12 mul sub M + hpt neg vpt 1.62 mul V + hpt 2 mul 0 V + hpt neg vpt -1.62 mul V closepath stroke + Pnt } def +/TriDF { stroke [] 0 setdash vpt 1.12 mul sub M + hpt neg vpt 1.62 mul V + hpt 2 mul 0 V + hpt neg vpt -1.62 mul V closepath fill} def +/DiaF { stroke [] 0 setdash vpt add M + hpt neg vpt neg V hpt vpt neg V + hpt vpt V hpt neg vpt V closepath fill } def +/Pent { stroke [] 0 setdash 2 copy gsave + translate 0 hpt M 4 {72 rotate 0 hpt L} repeat + closepath stroke grestore Pnt } def +/PentF { stroke [] 0 setdash gsave + translate 0 hpt M 4 {72 rotate 0 hpt L} repeat + closepath fill grestore } def +/Circle { stroke [] 0 setdash 2 copy + hpt 0 360 arc stroke Pnt } def +/CircleF { stroke [] 0 setdash hpt 0 360 arc fill } def +/C0 { BL [] 0 setdash 2 copy moveto vpt 90 450 arc } bind def +/C1 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 0 90 arc closepath fill + vpt 0 360 arc closepath } bind def +/C2 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 90 180 arc closepath fill + vpt 0 360 arc closepath } bind def +/C3 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 0 180 arc closepath fill + vpt 0 360 arc closepath } bind def +/C4 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 180 270 arc closepath fill + vpt 0 360 arc closepath } bind def +/C5 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 0 90 arc + 2 copy moveto + 2 copy vpt 180 270 arc closepath fill + vpt 0 360 arc } bind def +/C6 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 90 270 arc closepath fill + vpt 0 360 arc closepath } bind def +/C7 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 0 270 arc closepath fill + vpt 0 360 arc closepath } bind def +/C8 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 270 360 arc closepath fill + vpt 0 360 arc closepath } bind def +/C9 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 270 450 arc closepath fill + vpt 0 360 arc closepath } bind def +/C10 { BL [] 0 setdash 2 copy 2 copy moveto vpt 270 360 arc closepath fill + 2 copy moveto + 2 copy vpt 90 180 arc closepath fill + vpt 0 360 arc closepath } bind def +/C11 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 0 180 arc closepath fill + 2 copy moveto + 2 copy vpt 270 360 arc closepath fill + vpt 0 360 arc closepath } bind def +/C12 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 180 360 arc closepath fill + vpt 0 360 arc closepath } bind def +/C13 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 0 90 arc closepath fill + 2 copy moveto + 2 copy vpt 180 360 arc closepath fill + vpt 0 360 arc closepath } bind def +/C14 { BL [] 0 setdash 2 copy moveto + 2 copy vpt 90 360 arc closepath fill + vpt 0 360 arc } bind def +/C15 { BL [] 0 setdash 2 copy vpt 0 360 arc closepath fill + vpt 0 360 arc closepath } bind def +/Rec { newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto + neg 0 rlineto closepath } bind def +/Square { dup Rec } bind def +/Bsquare { vpt sub exch vpt sub exch vpt2 Square } bind def +/S0 { BL [] 0 setdash 2 copy moveto 0 vpt rlineto BL Bsquare } bind def +/S1 { BL [] 0 setdash 2 copy vpt Square fill Bsquare } bind def +/S2 { BL [] 0 setdash 2 copy exch vpt sub exch vpt Square fill Bsquare } bind def +/S3 { BL [] 0 setdash 2 copy exch vpt sub exch vpt2 vpt Rec fill Bsquare } bind def +/S4 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt Square fill Bsquare } bind def +/S5 { BL [] 0 setdash 2 copy 2 copy vpt Square fill + exch vpt sub exch vpt sub vpt Square fill Bsquare } bind def +/S6 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill Bsquare } bind def +/S7 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill + 2 copy vpt Square fill + Bsquare } bind def +/S8 { BL [] 0 setdash 2 copy vpt sub vpt Square fill Bsquare } bind def +/S9 { BL [] 0 setdash 2 copy vpt sub vpt vpt2 Rec fill Bsquare } bind def +/S10 { BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt Square fill + Bsquare } bind def +/S11 { BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt2 vpt Rec fill + Bsquare } bind def +/S12 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill Bsquare } bind def +/S13 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill + 2 copy vpt Square fill Bsquare } bind def +/S14 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill + 2 copy exch vpt sub exch vpt Square fill Bsquare } bind def +/S15 { BL [] 0 setdash 2 copy Bsquare fill Bsquare } bind def +/D0 { gsave translate 45 rotate 0 0 S0 stroke grestore } bind def +/D1 { gsave translate 45 rotate 0 0 S1 stroke grestore } bind def +/D2 { gsave translate 45 rotate 0 0 S2 stroke grestore } bind def +/D3 { gsave translate 45 rotate 0 0 S3 stroke grestore } bind def +/D4 { gsave translate 45 rotate 0 0 S4 stroke grestore } bind def +/D5 { gsave translate 45 rotate 0 0 S5 stroke grestore } bind def +/D6 { gsave translate 45 rotate 0 0 S6 stroke grestore } bind def +/D7 { gsave translate 45 rotate 0 0 S7 stroke grestore } bind def +/D8 { gsave translate 45 rotate 0 0 S8 stroke grestore } bind def +/D9 { gsave translate 45 rotate 0 0 S9 stroke grestore } bind def +/D10 { gsave translate 45 rotate 0 0 S10 stroke grestore } bind def +/D11 { gsave translate 45 rotate 0 0 S11 stroke grestore } bind def +/D12 { gsave translate 45 rotate 0 0 S12 stroke grestore } bind def +/D13 { gsave translate 45 rotate 0 0 S13 stroke grestore } bind def +/D14 { gsave translate 45 rotate 0 0 S14 stroke grestore } bind def +/D15 { gsave translate 45 rotate 0 0 S15 stroke grestore } bind def +/DiaE { stroke [] 0 setdash vpt add M + hpt neg vpt neg V hpt vpt neg V + hpt vpt V hpt neg vpt V closepath stroke } def +/BoxE { stroke [] 0 setdash exch hpt sub exch vpt add M + 0 vpt2 neg V hpt2 0 V 0 vpt2 V + hpt2 neg 0 V closepath stroke } def +/TriUE { stroke [] 0 setdash vpt 1.12 mul add M + hpt neg vpt -1.62 mul V + hpt 2 mul 0 V + hpt neg vpt 1.62 mul V closepath stroke } def +/TriDE { stroke [] 0 setdash vpt 1.12 mul sub M + hpt neg vpt 1.62 mul V + hpt 2 mul 0 V + hpt neg vpt -1.62 mul V closepath stroke } def +/PentE { stroke [] 0 setdash gsave + translate 0 hpt M 4 {72 rotate 0 hpt L} repeat + closepath stroke grestore } def +/CircE { stroke [] 0 setdash + hpt 0 360 arc stroke } def +/Opaque { gsave closepath 1 setgray fill grestore 0 setgray closepath } def +/DiaW { stroke [] 0 setdash vpt add M + hpt neg vpt neg V hpt vpt neg V + hpt vpt V hpt neg vpt V Opaque stroke } def +/BoxW { stroke [] 0 setdash exch hpt sub exch vpt add M + 0 vpt2 neg V hpt2 0 V 0 vpt2 V + hpt2 neg 0 V Opaque stroke } def +/TriUW { stroke [] 0 setdash vpt 1.12 mul add M + hpt neg vpt -1.62 mul V + hpt 2 mul 0 V + hpt neg vpt 1.62 mul V Opaque stroke } def +/TriDW { stroke [] 0 setdash vpt 1.12 mul sub M + hpt neg vpt 1.62 mul V + hpt 2 mul 0 V + hpt neg vpt -1.62 mul V Opaque stroke } def +/PentW { stroke [] 0 setdash gsave + translate 0 hpt M 4 {72 rotate 0 hpt L} repeat + Opaque stroke grestore } def +/CircW { stroke [] 0 setdash + hpt 0 360 arc Opaque stroke } def +/BoxFill { gsave Rec 1 setgray fill grestore } def +/BoxColFill { + gsave Rec + /Fillden exch def + currentrgbcolor + /ColB exch def /ColG exch def /ColR exch def + /ColR ColR Fillden mul Fillden sub 1 add def + /ColG ColG Fillden mul Fillden sub 1 add def + /ColB ColB Fillden mul Fillden sub 1 add def + ColR ColG ColB setrgbcolor + fill grestore } def +% +% PostScript Level 1 Pattern Fill routine +% Usage: x y w h s a XX PatternFill +% x,y = lower left corner of box to be filled +% w,h = width and height of box +% a = angle in degrees between lines and x-axis +% XX = 0/1 for no/yes cross-hatch +% +/PatternFill { gsave /PFa [ 9 2 roll ] def + PFa 0 get PFa 2 get 2 div add PFa 1 get PFa 3 get 2 div add translate + PFa 2 get -2 div PFa 3 get -2 div PFa 2 get PFa 3 get Rec + gsave 1 setgray fill grestore clip + currentlinewidth 0.5 mul setlinewidth + /PFs PFa 2 get dup mul PFa 3 get dup mul add sqrt def + 0 0 M PFa 5 get rotate PFs -2 div dup translate + 0 1 PFs PFa 4 get div 1 add floor cvi + { PFa 4 get mul 0 M 0 PFs V } for + 0 PFa 6 get ne { + 0 1 PFs PFa 4 get div 1 add floor cvi + { PFa 4 get mul 0 2 1 roll M PFs 0 V } for + } if + stroke grestore } def +% +/Symbol-Oblique /Symbol findfont [1 0 .167 1 0 0] makefont +dup length dict begin {1 index /FID eq {pop pop} {def} ifelse} forall +currentdict end definefont pop +end +%%EndProlog +gnudict begin +gsave +50 50 translate +0.050 0.050 scale +0 setgray +newpath +(Helvetica) findfont 140 scalefont setfont +1.000 UL +LTb +630 420 M +63 0 V +6269 0 R +-63 0 V +546 420 M +(-40) Rshow +1.000 UL +LTb +630 1056 M +63 0 V +6269 0 R +-63 0 V +-6353 0 R +(-30) Rshow +1.000 UL +LTb +630 1692 M +63 0 V +6269 0 R +-63 0 V +-6353 0 R +(-20) Rshow +1.000 UL +LTb +630 2328 M +63 0 V +6269 0 R +-63 0 V +-6353 0 R +(-10) Rshow +1.000 UL +LTb +630 2964 M +63 0 V +6269 0 R +-63 0 V +-6353 0 R +( 0) Rshow +1.000 UL +LTb +630 3600 M +63 0 V +6269 0 R +-63 0 V +-6353 0 R +( 10) Rshow +1.000 UL +LTb +630 4236 M +63 0 V +6269 0 R +-63 0 V +-6353 0 R +( 20) Rshow +1.000 UL +LTb +630 4872 M +63 0 V +6269 0 R +-63 0 V +-6353 0 R +( 30) Rshow +1.000 UL +LTb +630 420 M +0 63 V +0 4389 R +0 -63 V +630 280 M +( 0) Cshow +1.000 UL +LTb +1421 420 M +0 63 V +0 4389 R +0 -63 V +0 -4529 R +( 500) Cshow +1.000 UL +LTb +2213 420 M +0 63 V +0 4389 R +0 -63 V +0 -4529 R +( 1000) Cshow +1.000 UL +LTb +3004 420 M +0 63 V +0 4389 R +0 -63 V +0 -4529 R +( 1500) Cshow +1.000 UL +LTb +3796 420 M +0 63 V +0 4389 R +0 -63 V +0 -4529 R +( 2000) Cshow +1.000 UL +LTb +4587 420 M +0 63 V +0 4389 R +0 -63 V +0 -4529 R +( 2500) Cshow +1.000 UL +LTb +5379 420 M +0 63 V +0 4389 R +0 -63 V +0 -4529 R +( 3000) Cshow +1.000 UL +LTb +6170 420 M +0 63 V +0 4389 R +0 -63 V +0 -4529 R +( 3500) Cshow +1.000 UL +LTb +6962 420 M +0 63 V +0 4389 R +0 -63 V +0 -4529 R +( 4000) Cshow +1.000 UL +LTb +1.000 UL +LTb +630 420 M +6332 0 V +0 4452 V +-6332 0 V +630 420 L +LTb +140 2646 M +currentpoint gsave translate 90 rotate 0 0 M +(Response \(dB\)) Cshow +grestore +LTb +3796 70 M +(Frequency \(Hz\)) Cshow +1.000 UP +1.000 UL +LT0 +LTb +6311 4739 M +(Speech signal) Rshow +LT0 +6395 4739 M +399 0 V +630 1817 M +12 -132 V +13 -287 V +12 256 V +12 139 V +13 -127 V +12 -193 V +13 256 V +12 101 V +12 -189 V +13 -269 V +12 429 V +12 152 V +13 -102 V +12 -276 V +13 139 V +12 115 V +12 -205 V +13 -174 V +12 485 V +12 193 V +13 37 V +12 -17 V +12 41 V +13 230 V +12 242 V +13 107 V +12 190 V +12 513 V +13 436 V +12 323 V +12 236 V +13 168 V +12 110 V +12 58 V +13 9 V +12 -40 V +13 -90 V +12 -141 V +12 -197 V +13 -251 V +12 -289 V +12 -283 V +13 -247 V +12 -265 V +13 -324 V +12 -302 V +12 -231 V +13 -75 V +12 150 V +12 1 V +13 -298 V +1273 782 L +12 1103 V +13 76 V +12 -338 V +13 252 V +12 357 V +12 86 V +13 -118 V +12 -341 V +12 -20 V +13 364 V +12 243 V +12 212 V +13 214 V +12 208 V +13 180 V +12 136 V +12 82 V +13 23 V +12 -40 V +12 -107 V +13 -177 V +12 -240 V +13 -259 V +12 -215 V +12 -220 V +13 -297 V +12 -196 V +12 -128 V +13 -701 V +12 632 V +12 329 V +13 -25 V +12 -470 V +13 -54 V +12 538 V +12 70 V +13 -246 V +1743 551 L +12 1111 V +13 185 V +12 -159 V +1793 652 L +12 893 V +12 321 V +13 103 V +12 164 V +12 262 V +13 239 V +12 190 V +12 141 V +stroke +1891 2965 M +13 91 V +12 39 V +13 -13 V +12 -62 V +12 -97 V +13 -110 V +12 -120 V +12 -161 V +13 -265 V +12 -453 V +12 -215 V +13 139 V +12 -195 V +2062 420 L +5 0 R +10 961 V +12 135 V +13 -422 V +12 167 V +12 491 V +13 101 V +12 -169 V +13 -737 V +12 482 V +12 299 V +13 -48 V +12 -421 V +12 -151 V +13 434 V +12 -3 V +12 -378 V +13 -12 V +12 298 V +13 -187 V +12 -44 V +12 658 V +13 272 V +12 90 V +12 -49 V +13 -191 V +12 -370 V +13 -579 V +12 -329 V +12 385 V +13 444 V +12 172 V +12 -57 V +13 -407 V +12 -311 V +12 617 V +13 97 V +12 -198 V +13 -469 V +12 446 V +12 177 V +13 -114 V +12 -483 V +12 196 V +13 269 V +12 -74 V +12 -404 V +13 263 V +12 248 V +13 -37 V +12 -66 V +12 339 V +13 312 V +12 244 V +12 215 V +13 176 V +12 125 V +13 69 V +12 15 V +12 -30 V +13 -64 V +12 -85 V +12 -104 V +13 -138 V +12 -195 V +12 -278 V +13 -354 V +12 -257 V +13 -43 V +12 -20 V +12 -73 V +13 -202 V +12 -25 V +12 318 V +13 132 V +12 -73 V +12 -242 V +13 107 V +12 220 V +13 7 V +12 -277 V +9 -811 V +6 0 R +10 887 V +12 241 V +12 20 V +13 -14 V +12 241 V +13 323 V +12 262 V +stroke +3153 2380 M +12 197 V +13 138 V +12 86 V +12 36 V +13 -10 V +12 -54 V +12 -92 V +13 -116 V +12 -108 V +13 -73 V +12 -63 V +12 -107 V +13 -195 V +12 -267 V +12 -88 V +13 50 V +12 -97 V +13 -367 V +12 -285 V +12 374 V +13 3 V +12 -352 V +12 88 V +13 347 V +12 47 V +12 -192 V +13 -264 V +12 200 V +13 16 V +12 -421 V +12 296 V +13 398 V +12 65 V +12 -212 V +13 69 V +12 453 V +12 240 V +13 104 V +12 12 V +13 -52 V +12 -82 V +12 -69 V +13 -34 V +12 -25 V +12 -64 V +13 -158 V +12 -346 V +13 -166 V +12 375 V +12 139 V +13 -46 V +12 -207 V +12 -187 V +13 102 V +12 -14 V +12 -357 V +13 -271 V +12 601 V +13 119 V +12 -172 V +12 -486 V +13 521 V +12 256 V +12 10 V +13 -219 V +12 -294 V +13 446 V +12 285 V +12 167 V +13 137 V +12 152 V +12 161 V +13 144 V +12 106 V +12 58 V +13 7 V +12 -44 V +13 -87 V +12 -116 V +12 -119 V +13 -118 V +12 -152 V +12 -241 V +13 -363 V +12 -109 V +12 172 V +13 43 V +12 -75 V +13 -176 V +12 -313 V +12 -344 V +13 236 V +12 93 V +12 -169 V +13 -102 V +12 320 V +13 123 V +12 17 V +12 207 V +13 270 V +12 201 V +12 186 V +13 217 V +12 213 V +stroke +4439 2543 M +12 174 V +13 125 V +12 79 V +13 42 V +12 14 V +12 -3 V +13 -17 V +12 -34 V +12 -62 V +13 -102 V +12 -149 V +12 -182 V +13 -151 V +12 -70 V +13 -73 V +12 -146 V +12 -150 V +13 43 V +12 81 V +12 -27 V +13 -148 V +12 -213 V +13 -14 V +12 246 V +12 262 V +13 190 V +12 94 V +12 -7 V +13 -56 V +12 149 V +12 312 V +13 269 V +12 212 V +13 169 V +12 136 V +12 105 V +13 76 V +12 45 V +12 15 V +13 -15 V +12 -43 V +13 -66 V +12 -80 V +12 -83 V +13 -79 V +12 -80 V +12 -99 V +13 -136 V +12 -193 V +12 -274 V +13 -400 V +12 -462 V +13 173 V +12 148 V +12 -21 V +13 -198 V +12 -146 V +12 391 V +13 253 V +12 99 V +12 -38 V +13 -208 V +12 -260 V +13 418 V +12 330 V +12 210 V +13 153 V +12 123 V +12 105 V +13 88 V +12 68 V +13 47 V +12 24 V +12 1 V +13 -19 V +12 -38 V +12 -54 V +13 -67 V +12 -80 V +12 -93 V +13 -111 V +12 -132 V +13 -152 V +12 -167 V +12 -183 V +13 -211 V +12 -236 V +12 -139 V +13 15 V +12 -22 V +13 -164 V +12 -405 V +12 -211 V +13 440 V +12 230 V +12 152 V +13 96 V +12 29 V +12 -28 V +13 -10 V +12 81 V +13 96 V +12 29 V +12 -69 V +stroke +5725 2104 M +13 -186 V +12 -239 V +12 142 V +13 249 V +12 155 V +12 88 V +13 49 V +12 35 V +13 39 V +12 38 V +12 13 V +13 -34 V +12 -87 V +12 -112 V +13 -72 V +12 -35 V +13 -100 V +12 -269 V +12 -452 V +13 296 V +12 99 V +12 -312 V +13 242 V +12 513 V +12 237 V +13 88 V +12 -21 V +13 -82 V +12 -1 V +12 153 V +13 177 V +12 156 V +12 145 V +13 134 V +12 114 V +12 87 V +13 56 V +12 26 V +13 -3 V +12 -30 V +12 -52 V +13 -74 V +12 -93 V +12 -108 V +13 -121 V +12 -130 V +13 -129 V +12 -118 V +12 -100 V +13 -92 V +12 -105 V +12 -135 V +13 -172 V +12 -195 V +12 -222 V +13 -353 V +12 -548 V +13 682 V +12 273 V +12 79 V +13 -59 V +12 -188 V +12 -225 V +13 39 V +12 80 V +13 -43 V +12 -44 V +12 184 V +13 213 V +12 127 V +12 42 V +13 -37 V +12 -115 V +12 -182 V +13 -179 V +12 -53 V +13 12 V +12 6 V +12 20 V +13 10 V +12 -65 V +12 -195 V +13 -296 V +12 56 V +12 100 V +13 -118 V +12 -182 V +13 253 V +12 155 V +12 -50 V +13 -222 V +12 21 V +12 197 V +13 7 V +12 -194 V +13 -77 V +12 240 V +12 73 V +13 -132 V +1.000 UL +LT1 +LTb +6311 4599 M +(LPC synthesis filter) Rshow +LT1 +6395 4599 M +399 0 V +630 4034 M +12 0 V +13 0 V +12 1 V +12 1 V +13 1 V +12 1 V +13 1 V +12 2 V +12 2 V +13 3 V +12 2 V +12 4 V +13 3 V +12 5 V +13 4 V +12 6 V +12 6 V +13 7 V +12 8 V +12 8 V +13 10 V +12 11 V +12 11 V +13 13 V +12 15 V +13 16 V +12 17 V +12 19 V +13 21 V +12 23 V +12 25 V +13 27 V +12 29 V +12 31 V +13 32 V +12 33 V +13 33 V +12 30 V +12 26 V +13 16 V +12 4 V +12 -11 V +13 -26 V +12 -38 V +13 -49 V +12 -54 V +12 -56 V +13 -58 V +12 -57 V +12 -55 V +13 -53 V +12 -52 V +12 -49 V +13 -47 V +12 -45 V +13 -44 V +12 -41 V +12 -40 V +13 -38 V +12 -37 V +12 -35 V +13 -35 V +12 -33 V +12 -31 V +13 -31 V +12 -30 V +13 -29 V +12 -28 V +12 -27 V +13 -26 V +12 -26 V +12 -24 V +13 -25 V +12 -23 V +13 -23 V +12 -22 V +12 -22 V +13 -21 V +12 -20 V +12 -20 V +13 -20 V +12 -19 V +12 -19 V +13 -18 V +12 -17 V +13 -18 V +12 -17 V +12 -16 V +13 -16 V +12 -16 V +12 -15 V +13 -15 V +12 -15 V +13 -14 V +12 -14 V +12 -14 V +13 -13 V +12 -13 V +12 -13 V +13 -12 V +12 -13 V +12 -11 V +stroke +1891 2822 M +13 -12 V +12 -11 V +13 -11 V +12 -11 V +12 -11 V +13 -10 V +12 -10 V +12 -10 V +13 -10 V +12 -9 V +12 -9 V +13 -9 V +12 -8 V +13 -9 V +12 -8 V +12 -8 V +13 -8 V +12 -7 V +12 -8 V +13 -7 V +12 -7 V +13 -7 V +12 -6 V +12 -6 V +13 -7 V +12 -6 V +12 -5 V +13 -6 V +12 -5 V +12 -6 V +13 -5 V +12 -5 V +13 -4 V +12 -5 V +12 -4 V +13 -5 V +12 -4 V +12 -4 V +13 -3 V +12 -4 V +13 -3 V +12 -4 V +12 -3 V +13 -3 V +12 -2 V +12 -3 V +13 -3 V +12 -2 V +12 -2 V +13 -2 V +12 -2 V +13 -2 V +12 -2 V +12 -1 V +13 -2 V +12 -1 V +12 -1 V +13 -2 V +12 -1 V +12 0 V +13 -1 V +12 -1 V +13 0 V +12 -1 V +12 0 V +13 0 V +12 -1 V +12 0 V +13 0 V +12 0 V +13 0 V +12 1 V +12 0 V +13 0 V +12 1 V +12 0 V +13 1 V +12 0 V +12 1 V +13 1 V +12 0 V +13 1 V +12 1 V +12 1 V +13 0 V +12 1 V +12 1 V +13 1 V +12 1 V +12 0 V +13 1 V +12 1 V +13 1 V +12 0 V +12 1 V +13 1 V +12 0 V +12 1 V +13 1 V +12 0 V +13 1 V +12 0 V +12 0 V +13 1 V +stroke +3178 2508 M +12 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +13 0 V +12 0 V +12 -1 V +13 0 V +12 -1 V +12 0 V +13 -1 V +12 0 V +13 -1 V +12 -1 V +12 0 V +13 -1 V +12 -1 V +12 -1 V +13 -1 V +12 -1 V +12 0 V +13 -1 V +12 -1 V +13 -1 V +12 -1 V +12 -1 V +13 -1 V +12 -1 V +12 -1 V +13 -1 V +12 -1 V +12 0 V +13 -1 V +12 -1 V +13 -1 V +12 0 V +12 -1 V +13 0 V +12 -1 V +12 0 V +13 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 1 V +12 1 V +12 0 V +13 1 V +12 1 V +13 1 V +12 2 V +12 1 V +13 1 V +12 2 V +12 2 V +13 2 V +12 2 V +13 2 V +12 3 V +12 2 V +13 3 V +12 3 V +12 3 V +13 4 V +12 3 V +12 4 V +13 4 V +12 4 V +13 4 V +12 4 V +12 5 V +13 5 V +12 5 V +12 5 V +13 6 V +12 6 V +12 6 V +13 6 V +12 6 V +13 7 V +12 7 V +12 7 V +13 8 V +12 8 V +12 8 V +13 8 V +12 9 V +13 9 V +12 9 V +12 9 V +13 10 V +12 10 V +12 11 V +13 11 V +12 11 V +12 12 V +13 12 V +stroke +4464 2759 M +12 12 V +13 13 V +12 13 V +12 14 V +13 14 V +12 15 V +12 15 V +13 16 V +12 16 V +12 17 V +13 17 V +12 18 V +13 18 V +12 19 V +12 20 V +13 21 V +12 21 V +12 22 V +13 23 V +12 23 V +13 24 V +12 26 V +12 26 V +13 26 V +12 28 V +12 28 V +13 30 V +12 29 V +12 31 V +13 30 V +12 31 V +13 30 V +12 29 V +12 27 V +13 26 V +12 22 V +12 18 V +13 13 V +12 8 V +13 2 V +12 -3 V +12 -9 V +13 -13 V +12 -16 V +12 -20 V +13 -21 V +12 -23 V +12 -24 V +13 -23 V +12 -24 V +13 -23 V +12 -23 V +12 -22 V +13 -21 V +12 -21 V +12 -20 V +13 -18 V +12 -18 V +12 -17 V +13 -16 V +12 -16 V +13 -14 V +12 -14 V +12 -13 V +13 -13 V +12 -11 V +12 -11 V +13 -11 V +12 -10 V +13 -9 V +12 -8 V +12 -8 V +13 -8 V +12 -6 V +12 -7 V +13 -6 V +12 -5 V +12 -5 V +13 -4 V +12 -4 V +13 -4 V +12 -3 V +12 -3 V +13 -2 V +12 -2 V +12 -2 V +13 -1 V +12 -1 V +13 0 V +12 0 V +12 0 V +13 0 V +12 1 V +12 1 V +13 1 V +12 2 V +12 2 V +13 2 V +12 2 V +13 2 V +12 3 V +12 3 V +13 2 V +12 3 V +stroke +5750 3038 M +12 3 V +13 3 V +12 3 V +12 3 V +13 3 V +12 2 V +13 3 V +12 2 V +12 2 V +13 2 V +12 2 V +12 1 V +13 0 V +12 1 V +13 0 V +12 -1 V +12 -1 V +13 -2 V +12 -2 V +12 -3 V +13 -4 V +12 -4 V +12 -4 V +13 -6 V +12 -5 V +13 -7 V +12 -6 V +12 -8 V +13 -7 V +12 -9 V +12 -8 V +13 -9 V +12 -9 V +12 -10 V +13 -9 V +12 -10 V +13 -10 V +12 -10 V +12 -11 V +13 -10 V +12 -10 V +12 -11 V +13 -10 V +12 -10 V +13 -11 V +12 -10 V +12 -10 V +13 -10 V +12 -10 V +12 -9 V +13 -10 V +12 -10 V +12 -9 V +13 -9 V +12 -9 V +13 -9 V +12 -8 V +12 -8 V +13 -9 V +12 -8 V +12 -7 V +13 -8 V +12 -7 V +13 -7 V +12 -7 V +12 -7 V +13 -7 V +12 -6 V +12 -6 V +13 -6 V +12 -6 V +12 -5 V +13 -5 V +12 -5 V +13 -5 V +12 -5 V +12 -4 V +13 -4 V +12 -4 V +12 -4 V +13 -4 V +12 -3 V +12 -3 V +13 -3 V +12 -3 V +13 -2 V +12 -3 V +12 -2 V +13 -2 V +12 -2 V +12 -1 V +13 -1 V +12 -2 V +13 0 V +12 -1 V +12 -1 V +13 0 V +1.000 UL +LT2 +LTb +6311 4459 M +(Reference shaping) Rshow +LT2 +6395 4459 M +399 0 V +630 3487 M +12 0 V +13 0 V +12 1 V +12 0 V +13 1 V +12 1 V +13 1 V +12 2 V +12 1 V +13 2 V +12 2 V +12 2 V +13 2 V +12 2 V +13 3 V +12 2 V +12 3 V +13 3 V +12 3 V +12 2 V +13 4 V +12 3 V +12 3 V +13 3 V +12 3 V +13 2 V +12 3 V +12 3 V +13 2 V +12 2 V +12 1 V +13 1 V +12 1 V +12 0 V +13 0 V +12 -2 V +13 -2 V +12 -2 V +12 -4 V +13 -4 V +12 -6 V +12 -6 V +13 -7 V +12 -8 V +13 -8 V +12 -10 V +12 -10 V +13 -11 V +12 -12 V +12 -12 V +13 -13 V +12 -13 V +12 -14 V +13 -14 V +12 -14 V +13 -15 V +12 -15 V +12 -15 V +13 -15 V +12 -15 V +12 -15 V +13 -14 V +12 -15 V +12 -15 V +13 -15 V +12 -14 V +13 -14 V +12 -15 V +12 -13 V +13 -14 V +12 -14 V +12 -13 V +13 -13 V +12 -13 V +13 -12 V +12 -12 V +12 -12 V +13 -12 V +12 -12 V +12 -11 V +13 -11 V +12 -11 V +12 -10 V +13 -10 V +12 -10 V +13 -10 V +12 -10 V +12 -9 V +13 -9 V +12 -9 V +12 -9 V +13 -8 V +12 -8 V +13 -8 V +12 -8 V +12 -8 V +13 -7 V +12 -7 V +12 -7 V +13 -7 V +12 -6 V +12 -7 V +stroke +1891 2847 M +13 -6 V +12 -6 V +13 -6 V +12 -5 V +12 -6 V +13 -5 V +12 -5 V +12 -5 V +13 -5 V +12 -5 V +12 -4 V +13 -5 V +12 -4 V +13 -4 V +12 -4 V +12 -4 V +13 -4 V +12 -3 V +12 -4 V +13 -3 V +12 -3 V +13 -3 V +12 -3 V +12 -3 V +13 -2 V +12 -3 V +12 -2 V +13 -3 V +12 -2 V +12 -2 V +13 -2 V +12 -2 V +13 -2 V +12 -1 V +12 -2 V +13 -1 V +12 -2 V +12 -1 V +13 -1 V +12 -1 V +13 -2 V +12 0 V +12 -1 V +13 -1 V +12 -1 V +12 -1 V +13 0 V +12 -1 V +12 0 V +13 0 V +12 -1 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +12 1 V +13 0 V +12 0 V +13 1 V +12 0 V +12 0 V +13 1 V +12 0 V +12 1 V +13 1 V +12 0 V +13 1 V +12 1 V +12 0 V +13 1 V +12 1 V +12 1 V +13 0 V +12 1 V +12 1 V +13 1 V +12 1 V +13 1 V +12 0 V +12 1 V +13 1 V +12 1 V +12 1 V +13 1 V +12 1 V +12 0 V +13 1 V +12 1 V +13 1 V +12 0 V +12 1 V +13 1 V +12 1 V +12 0 V +13 1 V +12 1 V +13 0 V +12 1 V +12 0 V +13 1 V +stroke +3178 2736 M +12 0 V +12 1 V +13 0 V +12 1 V +12 0 V +13 0 V +12 1 V +13 0 V +12 0 V +12 0 V +13 1 V +12 0 V +12 0 V +13 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 -1 V +12 0 V +13 0 V +12 0 V +13 0 V +12 1 V +12 0 V +13 0 V +12 0 V +12 0 V +13 0 V +12 0 V +13 1 V +12 0 V +12 0 V +13 1 V +12 0 V +12 1 V +13 1 V +12 0 V +12 1 V +13 1 V +12 1 V +13 0 V +12 1 V +12 2 V +13 1 V +12 1 V +12 1 V +13 2 V +12 1 V +13 2 V +12 1 V +12 2 V +13 2 V +12 2 V +12 2 V +13 2 V +12 3 V +12 2 V +13 3 V +12 2 V +13 3 V +12 3 V +12 3 V +13 3 V +12 3 V +12 4 V +13 3 V +12 4 V +12 4 V +13 4 V +12 4 V +13 4 V +12 5 V +12 4 V +13 5 V +12 5 V +12 5 V +13 5 V +12 5 V +13 6 V +12 6 V +12 6 V +13 6 V +12 6 V +12 6 V +13 7 V +12 6 V +12 7 V +13 7 V +stroke +4464 2918 M +12 8 V +13 7 V +12 8 V +12 7 V +13 8 V +12 8 V +12 9 V +13 8 V +12 9 V +12 8 V +13 9 V +12 9 V +13 9 V +12 9 V +12 9 V +13 9 V +12 10 V +12 9 V +13 9 V +12 10 V +13 9 V +12 9 V +12 9 V +13 9 V +12 9 V +12 8 V +13 8 V +12 8 V +12 8 V +13 7 V +12 7 V +13 6 V +12 6 V +12 6 V +13 4 V +12 5 V +12 3 V +13 3 V +12 3 V +13 1 V +12 1 V +12 1 V +13 0 V +12 -1 V +12 -1 V +13 -2 V +12 -2 V +12 -3 V +13 -4 V +12 -3 V +13 -4 V +12 -5 V +12 -4 V +13 -5 V +12 -5 V +12 -5 V +13 -5 V +12 -6 V +12 -5 V +13 -6 V +12 -5 V +13 -6 V +12 -5 V +12 -5 V +13 -5 V +12 -6 V +12 -5 V +13 -5 V +12 -4 V +13 -5 V +12 -4 V +12 -5 V +13 -4 V +12 -4 V +12 -4 V +13 -3 V +12 -4 V +12 -3 V +13 -3 V +12 -3 V +13 -3 V +12 -3 V +12 -2 V +13 -2 V +12 -2 V +12 -2 V +13 -2 V +12 -2 V +13 -1 V +12 -2 V +12 -1 V +13 -1 V +12 -1 V +12 -1 V +13 -1 V +12 0 V +12 -1 V +13 -1 V +12 0 V +13 -1 V +12 0 V +12 0 V +13 -1 V +12 0 V +stroke +5750 3036 M +12 0 V +13 -1 V +12 0 V +12 0 V +13 -1 V +12 0 V +13 -1 V +12 0 V +12 -1 V +13 -1 V +12 0 V +12 -1 V +13 -1 V +12 -2 V +13 -1 V +12 -1 V +12 -2 V +13 -1 V +12 -2 V +12 -2 V +13 -2 V +12 -3 V +12 -2 V +13 -3 V +12 -2 V +13 -3 V +12 -3 V +12 -3 V +13 -4 V +12 -3 V +12 -4 V +13 -3 V +12 -4 V +12 -4 V +13 -4 V +12 -4 V +13 -4 V +12 -4 V +12 -5 V +13 -4 V +12 -4 V +12 -5 V +13 -4 V +12 -5 V +13 -4 V +12 -5 V +12 -5 V +13 -4 V +12 -5 V +12 -4 V +13 -5 V +12 -4 V +12 -4 V +13 -5 V +12 -4 V +13 -4 V +12 -5 V +12 -4 V +13 -4 V +12 -4 V +12 -4 V +13 -4 V +12 -4 V +13 -3 V +12 -4 V +12 -4 V +13 -3 V +12 -3 V +12 -4 V +13 -3 V +12 -3 V +12 -3 V +13 -3 V +12 -3 V +13 -2 V +12 -3 V +12 -2 V +13 -3 V +12 -2 V +12 -2 V +13 -2 V +12 -2 V +12 -2 V +13 -1 V +12 -2 V +13 -1 V +12 -2 V +12 -1 V +13 -1 V +12 -1 V +12 -1 V +13 -1 V +12 0 V +13 -1 V +12 0 V +12 0 V +13 -1 V +1.000 UL +LTb +630 420 M +6332 0 V +0 4452 V +-6332 0 V +630 420 L +1.000 UP +stroke +grestore +end +showpage +%%Trailer +%%DocumentFonts: Helvetica diff --git a/native/codec/libraries/speex/doc/rtp.txt b/native/codec/libraries/speex/doc/rtp.txt new file mode 100644 index 0000000..1c25153 --- /dev/null +++ b/native/codec/libraries/speex/doc/rtp.txt @@ -0,0 +1,76 @@ +The Speex RTP payload is defined as a header, followed by any number of +requests to the remote encoder and all encoded speech frames. + ++--------+----------+----------------+ +| Header | Requests | Speech data... | ++--------+----------+----------------+ + +The header contains only the number of frames sent +encoded in 6 bits + + 0 1 2 3 4 5 ++-+-+-+-+-+-+ +| NB frames | ++-+-+-+-+-+-+ + +There can be any number of requests of the form + + 0 1 2 3 4 5 6 7 0 1 ++-+-+-+-+-+-+-+-+-+-+ +|R| ReqID | ReqVal | ++-+-+-+-+-+-+-+-+-+-+ + +where R is 1 when a request is following and 0 when there is no more +request. Each request (if R=1) is composed of a 4-bit request ID (ReqID) and +a 5-bit value (ReqVal) + +Possible values for ReqID are: + 0: REQ_PERSIST ReqVal=1 for persistent requests/mode selection, + 0 otherwise + 1: PERSIST_ACK Acknowledge a REQ_PERSIST from the other end, + ReqVal equals the value received + 2: MODE Choose the encoder mode directly + 3: QUALITY Choose the encoder quality + 4: VBR Set VBR on (ReqVal=1) or off (ReqVal=2) + 5: VBR_QUALITY Set the encoder quality for VBR mode + 6: LOW_MODE Set the encoder mode for low-band (wideband only) + 7: HIGH_MODE Set the encoder mode for high-band (wideband only) + +All requests should be considered at the receiver as a suggestion and +compliance is not mandatory. The PERSIST_ACK should be sent upon receiving a +REQ_PERSIST request to indicate that the request has been received. + +The speech data part contains speech frames one after the other. The size of +the encoded frames can be found since the mode is directly encoded into each +frame. + +For example, a frame where we request VBR to be on with quality 8 and we +transmit two frames encoded at 8.35 kbps (167 bits/frame) will be: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| NB=2 |1|ReqID=2| ReqVal=0|1|ReqID=3|ReqVal=8 |0| frame 1 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 1 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 1 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 1 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 1 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 1 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +|end| frame 2 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 2 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 2 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 2 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| frame 2 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| end frame 2 |P|P|P|P|P|P| ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ diff --git a/native/codec/libraries/speex/doc/sampledec.c b/native/codec/libraries/speex/doc/sampledec.c new file mode 100644 index 0000000..8e89e12 --- /dev/null +++ b/native/codec/libraries/speex/doc/sampledec.c @@ -0,0 +1,65 @@ +#include +#include + +/*The frame size in hardcoded for this sample code but it doesn't have to be*/ +#define FRAME_SIZE 160 +int main(int argc, char **argv) +{ + char *outFile; + FILE *fout; + /*Holds the audio that will be written to file (16 bits per sample)*/ + short out[FRAME_SIZE]; + /*Speex handle samples as float, so we need an array of floats*/ + float output[FRAME_SIZE]; + char cbits[200]; + int nbBytes; + /*Holds the state of the decoder*/ + void *state; + /*Holds bits so they can be read and written to by the Speex routines*/ + SpeexBits bits; + int i, tmp; + + /*Create a new decoder state in narrowband mode*/ + state = speex_decoder_init(&speex_nb_mode); + + /*Set the perceptual enhancement on*/ + tmp=1; + speex_decoder_ctl(state, SPEEX_SET_ENH, &tmp); + + outFile = argv[1]; + fout = fopen(outFile, "w"); + + /*Initialization of the structure that holds the bits*/ + speex_bits_init(&bits); + while (1) + { + /*Read the size encoded by sampleenc, this part will likely be + different in your application*/ + fread(&nbBytes, sizeof(int), 1, stdin); + fprintf (stderr, "nbBytes: %d\n", nbBytes); + if (feof(stdin)) + break; + + /*Read the "packet" encoded by sampleenc*/ + fread(cbits, 1, nbBytes, stdin); + /*Copy the data into the bit-stream struct*/ + speex_bits_read_from(&bits, cbits, nbBytes); + + /*Decode the data*/ + speex_decode(state, &bits, output); + + /*Copy from float to short (16 bits) for output*/ + for (i=0;i +#include + +/*The frame size in hardcoded for this sample code but it doesn't have to be*/ +#define FRAME_SIZE 160 +int main(int argc, char **argv) +{ + char *inFile; + FILE *fin; + short in[FRAME_SIZE]; + float input[FRAME_SIZE]; + char cbits[200]; + int nbBytes; + /*Holds the state of the encoder*/ + void *state; + /*Holds bits so they can be read and written to by the Speex routines*/ + SpeexBits bits; + int i, tmp; + + /*Create a new encoder state in narrowband mode*/ + state = speex_encoder_init(&speex_nb_mode); + + /*Set the quality to 8 (15 kbps)*/ + tmp=8; + speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp); + + inFile = argv[1]; + fin = fopen(inFile, "r"); + + /*Initialization of the structure that holds the bits*/ + speex_bits_init(&bits); + while (1) + { + /*Read a 16 bits/sample audio frame*/ + fread(in, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + /*Copy the 16 bits values to float so Speex can work on them*/ + for (i=0;i + + + + + + + + + + + + + + + + + + + + + + The Speex Speech Codec + + + + + + + + + + +
    +Speex +
    +
    +
    + + + The Speex project + aims to build an open-source (LGPL) patent-free voice codec. Unlike + other codecs like MP3 and Ogg Vorbis, +Speex is specially designed for compressing voice at low bit-rates in the +8-32 kbps/channel range. Possible applications include Voice over IP (VoIP), + Internet audio streaming, archiving of speech data (e.g. voice mail), and +audio books. In some sense, it is meant to be complementary to the +Ogg Vorbis codec. +

    If you are interested in participating to the project, contact us at + speex-devel@lists.sourceforge.net or + join our mailing list. Right now, we are mostly looking for + developers with signal processing and speech coding knowledge, as well + as people with knowledge about patents in that field. See the +task list for more details about what's left to do in Speex
    +

    + + + + +

    Download

    + + + + You can download Speex from + here.
    + + +

    Documentation

    +This Speex manual includes information about the +algorithms used in Speex, the bit-stream, the API and more. +
    +Speex manual (PDF) +
    +Speex manual (Postscript) +
    +Speex manual (HTML online) +
    +Speex manual (HTML tarball) +

    +There is also some API documentation generated by Doxygen directly from the header files +
    +Speex API (PDF) + +

    Samples

    + +You can listen to samples encoded with Speex here + +

    Who uses Speex

    + +LinPhone: A SIP-based VoIP phone written for GNOME +
    +Speex XMMS plugin written by Jens Burkal +
    +OpenH323: An open-source H.323 stack +
    +GnomeMeeting: A H323 Video Conferencing Program + +

    +In development: +
    +Asterisk: An open-source PBX + +

    News

    + +

    2002/09/04

    + +Speex 0.8.1 released. This release fixes a bug in the new 0.8 API (function +speex_mode_query). For those using only speexenc/speexdec, no need to upgrade +but those using libspeex (directly or through another application) should. + +

    2002/08/24

    + Speex 0.8.0 released. The speex_decode() function no longer uses the +'lost' parameter. Applications will need + to be updated. + +

    2002/08/09

    + Speex 0.7.0 released. The format of the bit stream has changed once again +and the bandwidth required has been + reduced slightly. + +

    2002/08/01

    + +Speex 0.6.0 has been released. This is a major release that contains many improvements and lots of bug-fixing. The post-filter that was causing problems throughout 0.5.x was replaced with a new perceptual enhancement system, which sounds better and consume much less CPU. Also many changes to Ogg encoder/decoder, including possibility to see the bit-rate being played/encoded. There is also a discontinuous transmission (DTX) mode. Last but not least, 0.6.0 now reports no error when being run with the valgrind memory debugger. + +

    2002/07/26

    + +Speex 0.5.2 is out and brings a number of improvements and bug fixes. First, +the search has been improved and it is now possible to choose the right +quality/encoding time tradeoff (--comp option). Is is also possible to pack +more that one frame in an Ogg packet (--nframes), reducing the overhead for +low bit-rates. Last but not least: there is now some documentation about +Speex! + + +

    2002/07/17

    + +Version 0.5.1 is released. This release brings quality improvements at very +low bit-rate (5.7 kbps) and a new post-filter. VBR should also be a bit +better though there's still a lot to do. Most of the modes are bit-rate +compatible with 0.5.0, with the exception of the very low bit-rate (which is +sometimes used in VBR, so expect some glitches). The source (and probably +binary) compatibility with 0.5.0 is maintained. + +

    2002/07/08

    + +Speex 0.5.0 is out. The most important new feature is Varible Bit-Rate +(VBR). It can be enabled by using the --vbr option to speexenc. When +encoding in VBR, the --quality option can still be used. Note VBR +implementation in this release is experimental and still requires lots of +tuning. + +

    2002/06/23

    + +Speex 0.4.0 is here, adding many more bit-rates to both narrowband and wideband, as +well as the ability to change bit-rate dynamically from frame to frame. The +narrowband modes now range from 8 kbps to 18 kbps, while wideband range from +10 kbps to 28 kbps. There is also a "noise coding" mode at 2 kbps for +narrowband and 3 kbps for wideband. All this will lead to real Variable +Bit-Rate (VBR) in the future. Also, worth mentioning the codec latency has +been reduced from 40 ms to 30 ms (20 ms frames + 10 ms lookahead). + +

    2002/06/12

    + +Speex 0.3.0 has been released. There is now a new "low bit-rate" narrowband +mode for coding speech at 8 kbps. There's also support for big-endian +machines (untested, please report bugs). Speex files now have real header +containing information like bit-stream version (revents from playing an +incompatible bit-stream), sampling rate, bit-rate and user comments. On the +quality side, the post-filter has been improved and there has been more +codebook optimization. Note that this release breaks bit-stream +compatibility with previous releases. + +

    2002/06/07

    + +Speex 0.2.0 is out. This is a major release with lots of improvements and +bugfixes. First, the encoder and decoder can work directly from wav files +(mono only for now) and the decoder can play directly to soundcard. Also, +most of the codebooks have been re-trained in order to improve quality (but +this also breaks format compatibility with previous versions), while +slightly decreasing complexity. Speex is now able to encode both DTMF and +music (not as good as Vorbis of course) after bugs were fixed in the pitch +prediction and LSP quantization. Last but not the least, the perceptual +post-filter has been improved. + +

    2002/06/04

    + +Speex 0.1.2 is out. This adds a perceptual post-filter at the decoder to +(hopefully) increase quality. It can be enabled with the --pf option to +speexdec. The Speex format remains the same for both narrowband +and wideband. + +

    2002/05/15

    + +Speex 0.1.0 has been released. Speex now uses the Ogg bitstream (using +libogg). That means that there is now (limited) bitstream error +recovery. Also, the narrowband bit-rate has been reduced from 15.7 kbps to +15.1 kbps and the wideband bit-rate has been reduced from 31.3 kbps to 27.7 +kbps. The quality remains roughly the same for both narrowband and +wideband. Once again, this breaks compatibility with previous versions. + +
    +
    +
    +SourceForge Logo +
    + +Jean-Mrc Valin
    + $Date: 2002/09/16 00:59:10 $
    + + + + + diff --git a/native/codec/libraries/speex/html/patents.html b/native/codec/libraries/speex/html/patents.html new file mode 100644 index 0000000..d81c961 --- /dev/null +++ b/native/codec/libraries/speex/html/patents.html @@ -0,0 +1,39 @@ + + + + Speex and patents + + + + + +
    +

    Position regarding patents

    + +
    The goal of Speex is to provide a codec that is open-source +(released under the LGPL) +and that can be used in open-source software. This implies that it also has +to be free from patent restrictions. Unfortunately, the field of speech coding +known to be a real patent minefield and to make the matter worse, each country +has its own patent laws and list of granted patents so tracking them all +would be next to impossible. This is why we cannot provide an absolute warranty +that Speex is indeed completely patent-free.
    +
    + That being said, we are doing our best to keep away from known patents and +we do not patent the algorithms we use. That's about all we can do about it. +If you are aware of a patent issue with Speex, please let us know.
    +
    +Normally there shouldn't be any problem when you use Speex. However for the +reasons explained above, if you are thinking about using Speex commercially, +we strongly suggest that you have a closer look at patent issues with respect +to your country. Note that this is not specific to Speex, since many "standardized" +codecs have an unclear patent status (like MP3, GSM and probably +others), not to mention the risks of a previously unknown patent holder claiming +rights on a standardized codec long after standardization (GIF, JPEG).
    +
    +
    + + diff --git a/native/codec/libraries/speex/html/speex.png b/native/codec/libraries/speex/html/speex.png new file mode 100644 index 0000000..4db2873 Binary files /dev/null and b/native/codec/libraries/speex/html/speex.png differ diff --git a/native/codec/libraries/speex/html/speex.webprj b/native/codec/libraries/speex/html/speex.webprj new file mode 100644 index 0000000..23139f6 --- /dev/null +++ b/native/codec/libraries/speex/html/speex.webprj @@ -0,0 +1,7 @@ + + + + + + + diff --git a/native/codec/libraries/speex/html/speex.xcf b/native/codec/libraries/speex/html/speex.xcf new file mode 100644 index 0000000..e554712 Binary files /dev/null and b/native/codec/libraries/speex/html/speex.xcf differ diff --git a/native/codec/libraries/speex/include/Makefile.am b/native/codec/libraries/speex/include/Makefile.am new file mode 100644 index 0000000..09613b6 --- /dev/null +++ b/native/codec/libraries/speex/include/Makefile.am @@ -0,0 +1,2 @@ + +SUBDIRS = speex diff --git a/native/codec/libraries/speex/include/speex/Makefile.am b/native/codec/libraries/speex/include/speex/Makefile.am new file mode 100644 index 0000000..dff69d6 --- /dev/null +++ b/native/codec/libraries/speex/include/speex/Makefile.am @@ -0,0 +1,9 @@ +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +nodist_pkginclude_HEADERS = speex_config_types.h + +pkginclude_HEADERS = speex.h speex_bits.h speex_callbacks.h \ + speex_header.h \ + speex_stereo.h speex_types.h + diff --git a/native/codec/libraries/speex/include/speex/speex.h b/native/codec/libraries/speex/include/speex/speex.h new file mode 100644 index 0000000..34919e2 --- /dev/null +++ b/native/codec/libraries/speex/include/speex/speex.h @@ -0,0 +1,425 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin*/ +/** + @file speex.h + @brief Describes the different modes of the codec +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SPEEX_H +#define SPEEX_H +/** @defgroup Codec Speex encoder and decoder + * This is the Speex codec itself. + * @{ + */ + +#include "speex_types.h" +#include "speex_bits.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Values allowed for *ctl() requests */ + +/** Set enhancement on/off (decoder only) */ +#define SPEEX_SET_ENH 0 +/** Get enhancement state (decoder only) */ +#define SPEEX_GET_ENH 1 + +/*Would be SPEEX_SET_FRAME_SIZE, but it's (currently) invalid*/ +/** Obtain frame size used by encoder/decoder */ +#define SPEEX_GET_FRAME_SIZE 3 + +/** Set quality value */ +#define SPEEX_SET_QUALITY 4 +/** Get current quality setting */ +/* #define SPEEX_GET_QUALITY 5 -- Doesn't make much sense, does it? */ + +/** Set sub-mode to use */ +#define SPEEX_SET_MODE 6 +/** Get current sub-mode in use */ +#define SPEEX_GET_MODE 7 + +/** Set low-band sub-mode to use (wideband only)*/ +#define SPEEX_SET_LOW_MODE 8 +/** Get current low-band mode in use (wideband only)*/ +#define SPEEX_GET_LOW_MODE 9 + +/** Set high-band sub-mode to use (wideband only)*/ +#define SPEEX_SET_HIGH_MODE 10 +/** Get current high-band mode in use (wideband only)*/ +#define SPEEX_GET_HIGH_MODE 11 + +/** Set VBR on (1) or off (0) */ +#define SPEEX_SET_VBR 12 +/** Get VBR status (1 for on, 0 for off) */ +#define SPEEX_GET_VBR 13 + +/** Set quality value for VBR encoding (0-10) */ +#define SPEEX_SET_VBR_QUALITY 14 +/** Get current quality value for VBR encoding (0-10) */ +#define SPEEX_GET_VBR_QUALITY 15 + +/** Set complexity of the encoder (0-10) */ +#define SPEEX_SET_COMPLEXITY 16 +/** Get current complexity of the encoder (0-10) */ +#define SPEEX_GET_COMPLEXITY 17 + +/** Set bit-rate used by the encoder (or lower) */ +#define SPEEX_SET_BITRATE 18 +/** Get current bit-rate used by the encoder or decoder */ +#define SPEEX_GET_BITRATE 19 + +/** Define a handler function for in-band Speex request*/ +#define SPEEX_SET_HANDLER 20 + +/** Define a handler function for in-band user-defined request*/ +#define SPEEX_SET_USER_HANDLER 22 + +/** Set sampling rate used in bit-rate computation */ +#define SPEEX_SET_SAMPLING_RATE 24 +/** Get sampling rate used in bit-rate computation */ +#define SPEEX_GET_SAMPLING_RATE 25 + +/** Reset the encoder/decoder memories to zero*/ +#define SPEEX_RESET_STATE 26 + +/** Get VBR info (mostly used internally) */ +#define SPEEX_GET_RELATIVE_QUALITY 29 + +/** Set VAD status (1 for on, 0 for off) */ +#define SPEEX_SET_VAD 30 + +/** Get VAD status (1 for on, 0 for off) */ +#define SPEEX_GET_VAD 31 + +/** Set Average Bit-Rate (ABR) to n bits per seconds */ +#define SPEEX_SET_ABR 32 +/** Get Average Bit-Rate (ABR) setting (in bps) */ +#define SPEEX_GET_ABR 33 + +/** Set DTX status (1 for on, 0 for off) */ +#define SPEEX_SET_DTX 34 +/** Get DTX status (1 for on, 0 for off) */ +#define SPEEX_GET_DTX 35 + +/** Set submode encoding in each frame (1 for yes, 0 for no, setting to no breaks the standard) */ +#define SPEEX_SET_SUBMODE_ENCODING 36 +/** Get submode encoding in each frame */ +#define SPEEX_GET_SUBMODE_ENCODING 37 + +/*#define SPEEX_SET_LOOKAHEAD 38*/ +/** Returns the lookahead used by Speex separately for an encoder and a decoder. + * Sum encoder and decoder lookahead values to get the total codec lookahead. */ +#define SPEEX_GET_LOOKAHEAD 39 + +/** Sets tuning for packet-loss concealment (expected loss rate) */ +#define SPEEX_SET_PLC_TUNING 40 +/** Gets tuning for PLC */ +#define SPEEX_GET_PLC_TUNING 41 + +/** Sets the max bit-rate allowed in VBR mode */ +#define SPEEX_SET_VBR_MAX_BITRATE 42 +/** Gets the max bit-rate allowed in VBR mode */ +#define SPEEX_GET_VBR_MAX_BITRATE 43 + +/** Turn on/off input/output high-pass filtering */ +#define SPEEX_SET_HIGHPASS 44 +/** Get status of input/output high-pass filtering */ +#define SPEEX_GET_HIGHPASS 45 + +/** Get "activity level" of the last decoded frame, i.e. + how much damage we cause if we remove the frame */ +#define SPEEX_GET_ACTIVITY 47 + + +/* Preserving compatibility:*/ +/** Equivalent to SPEEX_SET_ENH */ +#define SPEEX_SET_PF 0 +/** Equivalent to SPEEX_GET_ENH */ +#define SPEEX_GET_PF 1 + + + + +/* Values allowed for mode queries */ +/** Query the frame size of a mode */ +#define SPEEX_MODE_FRAME_SIZE 0 + +/** Query the size of an encoded frame for a particular sub-mode */ +#define SPEEX_SUBMODE_BITS_PER_FRAME 1 + + + +/** Get major Speex version */ +#define SPEEX_LIB_GET_MAJOR_VERSION 1 +/** Get minor Speex version */ +#define SPEEX_LIB_GET_MINOR_VERSION 3 +/** Get micro Speex version */ +#define SPEEX_LIB_GET_MICRO_VERSION 5 +/** Get extra Speex version */ +#define SPEEX_LIB_GET_EXTRA_VERSION 7 +/** Get Speex version string */ +#define SPEEX_LIB_GET_VERSION_STRING 9 + +/*#define SPEEX_LIB_SET_ALLOC_FUNC 10 +#define SPEEX_LIB_GET_ALLOC_FUNC 11 +#define SPEEX_LIB_SET_FREE_FUNC 12 +#define SPEEX_LIB_GET_FREE_FUNC 13 + +#define SPEEX_LIB_SET_WARNING_FUNC 14 +#define SPEEX_LIB_GET_WARNING_FUNC 15 +#define SPEEX_LIB_SET_ERROR_FUNC 16 +#define SPEEX_LIB_GET_ERROR_FUNC 17 +*/ + +/** Number of defined modes in Speex */ +#define SPEEX_NB_MODES 3 + +/** modeID for the defined narrowband mode */ +#define SPEEX_MODEID_NB 0 + +/** modeID for the defined wideband mode */ +#define SPEEX_MODEID_WB 1 + +/** modeID for the defined ultra-wideband mode */ +#define SPEEX_MODEID_UWB 2 + +struct SpeexMode; + + +/* Prototypes for mode function pointers */ + +/** Encoder state initialization function */ +typedef void *(*encoder_init_func)(const struct SpeexMode *mode); + +/** Encoder state destruction function */ +typedef void (*encoder_destroy_func)(void *st); + +/** Main encoding function */ +typedef int (*encode_func)(void *state, void *in, SpeexBits *bits); + +/** Function for controlling the encoder options */ +typedef int (*encoder_ctl_func)(void *state, int request, void *ptr); + +/** Decoder state initialization function */ +typedef void *(*decoder_init_func)(const struct SpeexMode *mode); + +/** Decoder state destruction function */ +typedef void (*decoder_destroy_func)(void *st); + +/** Main decoding function */ +typedef int (*decode_func)(void *state, SpeexBits *bits, void *out); + +/** Function for controlling the decoder options */ +typedef int (*decoder_ctl_func)(void *state, int request, void *ptr); + + +/** Query function for a mode */ +typedef int (*mode_query_func)(const void *mode, int request, void *ptr); + +/** Struct defining a Speex mode */ +typedef struct SpeexMode { + /** Pointer to the low-level mode data */ + const void *mode; + + /** Pointer to the mode query function */ + mode_query_func query; + + /** The name of the mode (you should not rely on this to identify the mode)*/ + const char *modeName; + + /**ID of the mode*/ + int modeID; + + /**Version number of the bitstream (incremented every time we break + bitstream compatibility*/ + int bitstream_version; + + /** Pointer to encoder initialization function */ + encoder_init_func enc_init; + + /** Pointer to encoder destruction function */ + encoder_destroy_func enc_destroy; + + /** Pointer to frame encoding function */ + encode_func enc; + + /** Pointer to decoder initialization function */ + decoder_init_func dec_init; + + /** Pointer to decoder destruction function */ + decoder_destroy_func dec_destroy; + + /** Pointer to frame decoding function */ + decode_func dec; + + /** ioctl-like requests for encoder */ + encoder_ctl_func enc_ctl; + + /** ioctl-like requests for decoder */ + decoder_ctl_func dec_ctl; + +} SpeexMode; + +/** + * Returns a handle to a newly created Speex encoder state structure. For now, + * the "mode" argument can be &nb_mode or &wb_mode . In the future, more modes + * may be added. Note that for now if you have more than one channels to + * encode, you need one state per channel. + * + * @param mode The mode to use (either speex_nb_mode or speex_wb.mode) + * @return A newly created encoder state or NULL if state allocation fails + */ +void *speex_encoder_init(const SpeexMode *mode); + +/** Frees all resources associated to an existing Speex encoder state. + * @param state Encoder state to be destroyed */ +void speex_encoder_destroy(void *state); + +/** Uses an existing encoder state to encode one frame of speech pointed to by + "in". The encoded bit-stream is saved in "bits". + @param state Encoder state + @param in Frame that will be encoded with a +-2^15 range. This data MAY be + overwritten by the encoder and should be considered uninitialised + after the call. + @param bits Bit-stream where the data will be written + @return 0 if frame needs not be transmitted (DTX only), 1 otherwise + */ +int speex_encode(void *state, float *in, SpeexBits *bits); + +/** Uses an existing encoder state to encode one frame of speech pointed to by + "in". The encoded bit-stream is saved in "bits". + @param state Encoder state + @param in Frame that will be encoded with a +-2^15 range + @param bits Bit-stream where the data will be written + @return 0 if frame needs not be transmitted (DTX only), 1 otherwise + */ +int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits); + +/** Used like the ioctl function to control the encoder parameters + * + * @param state Encoder state + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_encoder_ctl(void *state, int request, void *ptr); + + +/** Returns a handle to a newly created decoder state structure. For now, + * the mode argument can be &nb_mode or &wb_mode . In the future, more modes + * may be added. Note that for now if you have more than one channels to + * decode, you need one state per channel. + * + * @param mode Speex mode (one of speex_nb_mode or speex_wb_mode) + * @return A newly created decoder state or NULL if state allocation fails + */ +void *speex_decoder_init(const SpeexMode *mode); + +/** Frees all resources associated to an existing decoder state. + * + * @param state State to be destroyed + */ +void speex_decoder_destroy(void *state); + +/** Uses an existing decoder state to decode one frame of speech from + * bit-stream bits. The output speech is saved written to out. + * + * @param state Decoder state + * @param bits Bit-stream from which to decode the frame (NULL if the packet was lost) + * @param out Where to write the decoded frame + * @return return status (0 for no error, -1 for end of stream, -2 corrupt stream) + */ +int speex_decode(void *state, SpeexBits *bits, float *out); + +/** Uses an existing decoder state to decode one frame of speech from + * bit-stream bits. The output speech is saved written to out. + * + * @param state Decoder state + * @param bits Bit-stream from which to decode the frame (NULL if the packet was lost) + * @param out Where to write the decoded frame + * @return return status (0 for no error, -1 for end of stream, -2 corrupt stream) + */ +int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out); + +/** Used like the ioctl function to control the encoder parameters + * + * @param state Decoder state + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_decoder_ctl(void *state, int request, void *ptr); + + +/** Query function for mode information + * + * @param mode Speex mode + * @param request ioctl-type request (one of the SPEEX_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_mode_query(const SpeexMode *mode, int request, void *ptr); + +/** Functions for controlling the behavior of libspeex + * @param request ioctl-type request (one of the SPEEX_LIB_* macros) + * @param ptr Data exchanged to-from function + * @return 0 if no error, -1 if request in unknown, -2 for invalid parameter + */ +int speex_lib_ctl(int request, void *ptr); + +/** Default narrowband mode */ +extern const SpeexMode speex_nb_mode; + +/** Default wideband mode */ +extern const SpeexMode speex_wb_mode; + +/** Default "ultra-wideband" mode */ +extern const SpeexMode speex_uwb_mode; + +/** List of all modes available */ +extern const SpeexMode * const speex_mode_list[SPEEX_NB_MODES]; + +/** Obtain one of the modes available */ +const SpeexMode * speex_lib_get_mode (int mode); + +#ifndef _WIN32 +/* We actually override the function in the narrowband case so that we can avoid linking in the wideband stuff */ +#define speex_lib_get_mode(mode) ((mode)==SPEEX_MODEID_NB ? &speex_nb_mode : speex_lib_get_mode (mode)) +#endif + +#ifdef __cplusplus +} +#endif + +/** @}*/ +#endif diff --git a/native/codec/libraries/speex/include/speex/speex_bits.h b/native/codec/libraries/speex/include/speex/speex_bits.h new file mode 100644 index 0000000..f98b826 --- /dev/null +++ b/native/codec/libraries/speex/include/speex/speex_bits.h @@ -0,0 +1,174 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_bits.h + @brief Handles bit packing/unpacking +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef BITS_H +#define BITS_H +/** @defgroup SpeexBits SpeexBits: Bit-stream manipulations + * This is the structure that holds the bit-stream when encoding or decoding + * with Speex. It allows some manipulations as well. + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Bit-packing data structure representing (part of) a bit-stream. */ +typedef struct SpeexBits { + char *chars; /**< "raw" data */ + int nbBits; /**< Total number of bits stored in the stream*/ + int charPtr; /**< Position of the byte "cursor" */ + int bitPtr; /**< Position of the bit "cursor" within the current char */ + int owner; /**< Does the struct "own" the "raw" buffer (member "chars") */ + int overflow;/**< Set to one if we try to read past the valid data */ + int buf_size;/**< Allocated size for buffer */ + int reserved1; /**< Reserved for future use */ + void *reserved2; /**< Reserved for future use */ +} SpeexBits; + +/** Initializes and allocates resources for a SpeexBits struct */ +void speex_bits_init(SpeexBits *bits); + +/** Initializes SpeexBits struct using a pre-allocated buffer*/ +void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size); + +/** Sets the bits in a SpeexBits struct to use data from an existing buffer (for decoding without copying data) */ +void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size); + +/** Frees all resources associated to a SpeexBits struct. Right now this does nothing since no resources are allocated, but this could change in the future.*/ +void speex_bits_destroy(SpeexBits *bits); + +/** Resets bits to initial value (just after initialization, erasing content)*/ +void speex_bits_reset(SpeexBits *bits); + +/** Rewind the bit-stream to the beginning (ready for read) without erasing the content */ +void speex_bits_rewind(SpeexBits *bits); + +/** Initializes the bit-stream from the data in an area of memory */ +void speex_bits_read_from(SpeexBits *bits, const char *bytes, int len); + +/** Append bytes to the bit-stream + * + * @param bits Bit-stream to operate on + * @param bytes pointer to the bytes what will be appended + * @param len Number of bytes of append + */ +void speex_bits_read_whole_bytes(SpeexBits *bits, const char *bytes, int len); + +/** Write the content of a bit-stream to an area of memory + * + * @param bits Bit-stream to operate on + * @param bytes Memory location where to write the bits + * @param max_len Maximum number of bytes to write (i.e. size of the "bytes" buffer) + * @return Number of bytes written to the "bytes" buffer +*/ +int speex_bits_write(SpeexBits *bits, char *bytes, int max_len); + +/** Like speex_bits_write, but writes only the complete bytes in the stream. Also removes the written bytes from the stream */ +int speex_bits_write_whole_bytes(SpeexBits *bits, char *bytes, int max_len); + +/** Append bits to the bit-stream + * @param bits Bit-stream to operate on + * @param data Value to append as integer + * @param nbBits number of bits to consider in "data" + */ +void speex_bits_pack(SpeexBits *bits, int data, int nbBits); + +/** Interpret the next bits in the bit-stream as a signed integer + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to interpret + * @return A signed integer represented by the bits read + */ +int speex_bits_unpack_signed(SpeexBits *bits, int nbBits); + +/** Interpret the next bits in the bit-stream as an unsigned integer + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to interpret + * @return An unsigned integer represented by the bits read + */ +unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits); + +/** Returns the number of bytes in the bit-stream, including the last one even if it is not "full" + * + * @param bits Bit-stream to operate on + * @return Number of bytes in the stream + */ +int speex_bits_nbytes(SpeexBits *bits); + +/** Same as speex_bits_unpack_unsigned, but without modifying the cursor position + * + * @param bits Bit-stream to operate on + * @param nbBits Number of bits to look for + * @return Value of the bits peeked, interpreted as unsigned + */ +unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits); + +/** Get the value of the next bit in the stream, without modifying the + * "cursor" position + * + * @param bits Bit-stream to operate on + * @return Value of the bit peeked (one bit only) + */ +int speex_bits_peek(SpeexBits *bits); + +/** Advances the position of the "bit cursor" in the stream + * + * @param bits Bit-stream to operate on + * @param n Number of bits to advance + */ +void speex_bits_advance(SpeexBits *bits, int n); + +/** Returns the number of bits remaining to be read in a stream + * + * @param bits Bit-stream to operate on + * @return Number of bits that can still be read from the stream + */ +int speex_bits_remaining(SpeexBits *bits); + +/** Insert a terminator so that the data can be sent as a packet while auto-detecting + * the number of frames in each packet + * + * @param bits Bit-stream to operate on + */ +void speex_bits_insert_terminator(SpeexBits *bits); + +#ifdef __cplusplus +} +#endif + +/* @} */ +#endif diff --git a/native/codec/libraries/speex/include/speex/speex_callbacks.h b/native/codec/libraries/speex/include/speex/speex_callbacks.h new file mode 100644 index 0000000..3928c34 --- /dev/null +++ b/native/codec/libraries/speex/include/speex/speex_callbacks.h @@ -0,0 +1,134 @@ +/* Copyright (C) 2002 Jean-Marc Valin*/ +/** + @file speex_callbacks.h + @brief Describes callback handling and in-band signalling +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SPEEX_CALLBACKS_H +#define SPEEX_CALLBACKS_H +/** @defgroup SpeexCallbacks Various definitions for Speex callbacks supported by the decoder. + * @{ + */ + +#include "speex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Total number of callbacks */ +#define SPEEX_MAX_CALLBACKS 16 + +/* Describes all the in-band requests */ + +/*These are 1-bit requests*/ +/** Request for perceptual enhancement (1 for on, 0 for off) */ +#define SPEEX_INBAND_ENH_REQUEST 0 +/** Reserved */ +#define SPEEX_INBAND_RESERVED1 1 + +/*These are 4-bit requests*/ +/** Request for a mode change */ +#define SPEEX_INBAND_MODE_REQUEST 2 +/** Request for a low mode change */ +#define SPEEX_INBAND_LOW_MODE_REQUEST 3 +/** Request for a high mode change */ +#define SPEEX_INBAND_HIGH_MODE_REQUEST 4 +/** Request for VBR (1 on, 0 off) */ +#define SPEEX_INBAND_VBR_QUALITY_REQUEST 5 +/** Request to be sent acknowledge */ +#define SPEEX_INBAND_ACKNOWLEDGE_REQUEST 6 +/** Request for VBR (1 for on, 0 for off) */ +#define SPEEX_INBAND_VBR_REQUEST 7 + +/*These are 8-bit requests*/ +/** Send a character in-band */ +#define SPEEX_INBAND_CHAR 8 +/** Intensity stereo information */ +#define SPEEX_INBAND_STEREO 9 + +/*These are 16-bit requests*/ +/** Transmit max bit-rate allowed */ +#define SPEEX_INBAND_MAX_BITRATE 10 + +/*These are 32-bit requests*/ +/** Acknowledge packet reception */ +#define SPEEX_INBAND_ACKNOWLEDGE 12 + +/** Callback function type */ +typedef int (*speex_callback_func)(SpeexBits *bits, void *state, void *data); + +/** Callback information */ +typedef struct SpeexCallback { + int callback_id; /**< ID associated to the callback */ + speex_callback_func func; /**< Callback handler function */ + void *data; /**< Data that will be sent to the handler */ + void *reserved1; /**< Reserved for future use */ + int reserved2; /**< Reserved for future use */ +} SpeexCallback; + +/** Handle in-band request */ +int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state); + +/** Standard handler for mode request (change mode, no questions asked) */ +int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for high mode request (change high mode, no questions asked) */ +int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for in-band characters (write to stderr) */ +int speex_std_char_handler(SpeexBits *bits, void *state, void *data); + +/** Default handler for user-defined requests: in this case, just ignore */ +int speex_default_user_handler(SpeexBits *bits, void *state, void *data); + + + +/** Standard handler for low mode request (change low mode, no questions asked) */ +int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for VBR request (Set VBR, no questions asked) */ +int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for enhancer request (Turn enhancer on/off, no questions asked) */ +int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data); + +/** Standard handler for VBR quality request (Set VBR quality, no questions asked) */ +int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data); + + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/native/codec/libraries/speex/include/speex/speex_config_types.h.in b/native/codec/libraries/speex/include/speex/speex_config_types.h.in new file mode 100644 index 0000000..5ea7b55 --- /dev/null +++ b/native/codec/libraries/speex/include/speex/speex_config_types.h.in @@ -0,0 +1,12 @@ +#ifndef __SPEEX_TYPES_H__ +#define __SPEEX_TYPES_H__ + +@INCLUDE_STDINT@ + +typedef @SIZE16@ spx_int16_t; +typedef @USIZE16@ spx_uint16_t; +typedef @SIZE32@ spx_int32_t; +typedef @USIZE32@ spx_uint32_t; + +#endif + diff --git a/native/codec/libraries/speex/include/speex/speex_header.h b/native/codec/libraries/speex/include/speex/speex_header.h new file mode 100644 index 0000000..ffe8c47 --- /dev/null +++ b/native/codec/libraries/speex/include/speex/speex_header.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_header.h + @brief Describes the Speex header +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + + +#ifndef SPEEX_HEADER_H +#define SPEEX_HEADER_H +/** @defgroup SpeexHeader SpeexHeader: Makes it easy to write/parse an Ogg/Speex header + * This is the Speex header for the Ogg encapsulation. You don't need that if you just use RTP. + * @{ + */ + +#include "speex_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct SpeexMode; + +/** Length of the Speex header identifier */ +#define SPEEX_HEADER_STRING_LENGTH 8 + +/** Maximum number of characters for encoding the Speex version number in the header */ +#define SPEEX_HEADER_VERSION_LENGTH 20 + +/** Speex header info for file-based formats */ +typedef struct SpeexHeader { + char speex_string[SPEEX_HEADER_STRING_LENGTH]; /**< Identifies a Speex bit-stream, always set to "Speex " */ + char speex_version[SPEEX_HEADER_VERSION_LENGTH]; /**< Speex version */ + spx_int32_t speex_version_id; /**< Version for Speex (for checking compatibility) */ + spx_int32_t header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */ + spx_int32_t rate; /**< Sampling rate used */ + spx_int32_t mode; /**< Mode used (0 for narrowband, 1 for wideband) */ + spx_int32_t mode_bitstream_version; /**< Version ID of the bit-stream */ + spx_int32_t nb_channels; /**< Number of channels encoded */ + spx_int32_t bitrate; /**< Bit-rate used */ + spx_int32_t frame_size; /**< Size of frames */ + spx_int32_t vbr; /**< 1 for a VBR encoding, 0 otherwise */ + spx_int32_t frames_per_packet; /**< Number of frames stored per Ogg packet */ + spx_int32_t extra_headers; /**< Number of additional headers after the comments */ + spx_int32_t reserved1; /**< Reserved for future use, must be zero */ + spx_int32_t reserved2; /**< Reserved for future use, must be zero */ +} SpeexHeader; + +/** Initializes a SpeexHeader using basic information */ +void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const struct SpeexMode *m); + +/** Creates the header packet from the header itself (mostly involves endianness conversion) */ +char *speex_header_to_packet(SpeexHeader *header, int *size); + +/** Creates a SpeexHeader from a packet */ +SpeexHeader *speex_packet_to_header(char *packet, int size); + +/** Frees the memory allocated by either speex_header_to_packet() or speex_packet_to_header() */ +void speex_header_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/native/codec/libraries/speex/include/speex/speex_stereo.h b/native/codec/libraries/speex/include/speex/speex_stereo.h new file mode 100644 index 0000000..12af2bb --- /dev/null +++ b/native/codec/libraries/speex/include/speex/speex_stereo.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2002 Jean-Marc Valin*/ +/** + @file speex_stereo.h + @brief Describes the handling for intensity stereo +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STEREO_H +#define STEREO_H +/** @defgroup SpeexStereoState SpeexStereoState: Handling Speex stereo files + * This describes the Speex intensity stereo encoding/decoding + * @{ + */ + +#include "speex_types.h" +#include "speex_bits.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** If you access any of these fields directly, I'll personally come and bite you */ +typedef struct SpeexStereoState { + float balance; /**< Left/right balance info */ + float e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)] */ + float smooth_left; /**< Smoothed left channel gain */ + float smooth_right; /**< Smoothed right channel gain */ + float reserved1; /**< Reserved for future use */ + float reserved2; /**< Reserved for future use */ +} SpeexStereoState; + +/** Deprecated. Use speex_stereo_state_init() instead. */ +#define SPEEX_STEREO_STATE_INIT {1,.5,1,1,0,0} + +/** Initialise/create a stereo stereo state */ +SpeexStereoState *speex_stereo_state_init(void); + +/** Reset/re-initialise an already allocated stereo state */ +void speex_stereo_state_reset(SpeexStereoState *stereo); + +/** Destroy a stereo stereo state */ +void speex_stereo_state_destroy(SpeexStereoState *stereo); + +/** Transforms a stereo frame into a mono frame and stores intensity stereo info in 'bits' */ +void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits); + +/** Transforms a stereo frame into a mono frame and stores intensity stereo info in 'bits' */ +void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits); + +/** Transforms a mono frame into a stereo frame using intensity stereo info */ +void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *stereo); + +/** Transforms a mono frame into a stereo frame using intensity stereo info */ +void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *stereo); + +/** Callback handler for intensity stereo info */ +int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/native/codec/libraries/speex/include/speex/speex_types.h b/native/codec/libraries/speex/include/speex/speex_types.h new file mode 100644 index 0000000..bdc6329 --- /dev/null +++ b/native/codec/libraries/speex/include/speex/speex_types.h @@ -0,0 +1,126 @@ +/* speex_types.h taken from libogg */ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id: os_types.h 7524 2004-08-11 04:20:36Z conrad $ + + ********************************************************************/ +/** + @file speex_types.h + @brief Speex types +*/ +#ifndef _SPEEX_TYPES_H +#define _SPEEX_TYPES_H + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t spx_int32_t; + typedef _G_uint32_t spx_uint32_t; + typedef _G_int16_t spx_int16_t; + typedef _G_uint16_t spx_uint16_t; +# elif defined(__MINGW32__) + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; +# elif defined(__MWERKS__) + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; +# else + /* MSVC/Borland */ + typedef __int32 spx_int32_t; + typedef unsigned __int32 spx_uint32_t; + typedef __int16 spx_int16_t; + typedef unsigned __int16 spx_uint16_t; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 spx_int16_t; + typedef UInt16 spx_uint16_t; + typedef SInt32 spx_int32_t; + typedef UInt32 spx_uint32_t; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t spx_int16_t; + typedef u_int16_t spx_uint16_t; + typedef int32_t spx_int32_t; + typedef u_int32_t spx_uint32_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t spx_int16_t; + typedef u_int16_t spx_uint16_t; + typedef int32_t spx_int32_t; + typedef u_int32_t spx_uint32_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short spx_int16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int spx_int32_t; + typedef unsigned spx_uint32_t; + typedef short spx_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef signed int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef long spx_int32_t; + typedef unsigned long spx_uint32_t; + +#elif defined(CONFIG_TI_C6X) + + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#else + +#include "speex_config_types.h" + +#endif + +#endif /* _SPEEX_TYPES_H */ diff --git a/native/codec/libraries/speex/libspeex/.cvsignore b/native/codec/libraries/speex/libspeex/.cvsignore new file mode 100644 index 0000000..09a90ac --- /dev/null +++ b/native/codec/libraries/speex/libspeex/.cvsignore @@ -0,0 +1,11 @@ +.deps +.libs +*.la +*.lo +*.o +Makefile +Makefile.in +testdenoise +testenc +testenc_uwb +testenc_wb diff --git a/native/codec/libraries/speex/libspeex/Makefile.am b/native/codec/libraries/speex/libspeex/Makefile.am new file mode 100644 index 0000000..8fe9bff --- /dev/null +++ b/native/codec/libraries/speex/libspeex/Makefile.am @@ -0,0 +1,53 @@ +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +if BUILD_VORBIS_PSY + VPSY_SOURCE=vorbis_psy.c +if BUILD_KISS_FFT + FFTSRC=kiss_fft.c _kiss_fft_guts.h kiss_fft.h kiss_fftr.c kiss_fftr.h +else +if BUILD_SMALLFT + FFTSRC=smallft.c +else + FFTSRC= +endif +endif +else + VPSY_SOURCE= + FFTSRC= +endif + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include/speex -I$(top_builddir) @OGG_CFLAGS@ @FFT_CFLAGS@ + +lib_LTLIBRARIES = libspeex.la + +# Sources for compilation in the library +libspeex_la_SOURCES = $(VPSY_SOURCE) $(FFTSRC) cb_search.c exc_10_32_table.c exc_8_128_table.c \ + filters.c gain_table.c hexc_table.c high_lsp_tables.c lsp.c \ + ltp.c speex.c stereo.c vbr.c vq.c bits.c exc_10_16_table.c \ + exc_20_32_table.c exc_5_256_table.c exc_5_64_table.c gain_table_lbr.c hexc_10_32_table.c \ + lpc.c lsp_tables_nb.c modes.c modes_wb.c nb_celp.c quant_lsp.c sb_celp.c \ + speex_callbacks.c speex_header.c window.c + + +noinst_HEADERS = arch.h bfin.h cb_search_arm4.h cb_search_bfin.h cb_search_sse.h \ + filters.h filters_arm4.h filters_bfin.h filters_sse.h fixed_arm4.h \ + fixed_arm5e.h fixed_bfin.h fixed_debug.h lpc.h lpc_bfin.h ltp.h ltp_arm4.h \ + ltp_sse.h math_approx.h misc_bfin.h nb_celp.h quant_lsp.h sb_celp.h \ + stack_alloc.h vbr.h vq.h vq_arm4.h vq_bfin.h vq_sse.h cb_search.h fftwrap.h \ + fixed_generic.h lsp.h lsp_bfin.h ltp_bfin.h modes.h os_support.h \ + quant_lsp_bfin.h smallft.h vorbis_psy.h + + +libspeex_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@ +libspeex_la_LIBADD = $(LIBM) + +if BUILD_BINARIES +noinst_PROGRAMS = testenc testenc_wb testenc_uwb +testenc_SOURCES = testenc.c +testenc_LDADD = libspeex.la $(LIBM) +testenc_wb_SOURCES = testenc_wb.c +testenc_wb_LDADD = libspeex.la $(LIBM) +testenc_uwb_SOURCES = testenc_uwb.c +testenc_uwb_LDADD = libspeex.la $(LIBM) +endif diff --git a/native/codec/libraries/speex/libspeex/_kiss_fft_guts.h b/native/codec/libraries/speex/libspeex/_kiss_fft_guts.h new file mode 100644 index 0000000..6571e79 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/_kiss_fft_guts.h @@ -0,0 +1,160 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" +#include "math_approx.h" + +#define MAXFACTORS 32 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +struct kiss_fft_state{ + int nfft; + int inverse; + int factors[2*MAXFACTORS]; + kiss_fft_cpx twiddles[1]; +}; + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" +# define FRACBITS 15 +# define SAMPPROD spx_int32_t +#define SAMP_MAX 32767 + +#define SAMP_MIN -SAMP_MAX + +#if defined(CHECK_OVERFLOW) +# define CHECK_OVERFLOW_OP(a,op,b) \ + if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ + fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } +#endif + + +# define smul(a,b) ( (SAMPPROD)(a)*(b) ) +# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) + +# define S_MUL(a,b) sround( smul(a,b) ) + +# define C_MUL(m,a,b) \ + do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ + (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) + +# define C_MUL4(m,a,b) \ + do{ (m).r = PSHR32( smul((a).r,(b).r) - smul((a).i,(b).i),17 ); \ + (m).i = PSHR32( smul((a).r,(b).i) + smul((a).i,(b).r),17 ); }while(0) + +# define DIVSCALAR(x,k) \ + (x) = sround( smul( x, SAMP_MAX/k ) ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = sround( smul( (c).r , s ) ) ;\ + (c).i = sround( smul( (c).i , s ) ) ; }while(0) + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) + + +#ifdef FIXED_POINT +# define KISS_FFT_COS(phase) floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase)))) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = spx_cos_norm((phase));\ + (x)->i = spx_cos_norm((phase)-32768);\ +}while(0) + + +/* a debugging function */ +#define pcpx(c)\ + fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) diff --git a/native/codec/libraries/speex/libspeex/arch.h b/native/codec/libraries/speex/libspeex/arch.h new file mode 100644 index 0000000..291cab8 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/arch.h @@ -0,0 +1,237 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions Speex +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#ifndef SPEEX_VERSION +#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */ +#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */ +#define SPEEX_MICRO_VERSION 16 /**< Micro Speex version. */ +#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */ +#define SPEEX_VERSION "speex-1.2.0" /**< Speex version string. */ +#endif + +/* A couple test to catch stupid option combinations */ +#ifdef FIXED_POINT + +#ifdef FLOATING_POINT +#error You cannot compile as floating point and fixed point at the same time +#endif +#ifdef _USE_SSE +#error SSE is only for floating-point +#endif +#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM)) +#error Make up your mind. What CPU do you have? +#endif +#ifdef VORBIS_PSYCHO +#error Vorbis-psy model currently not implemented in fixed-point +#endif + +#else + +#ifndef FLOATING_POINT +#error You now need to define either FIXED_POINT or FLOATING_POINT +#endif +#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) +#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions? +#endif +#ifdef FIXED_POINT_DEBUG +#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?" +#endif + + +#endif + +#include "speex/speex_types.h" + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ + +#ifdef FIXED_POINT + +typedef spx_int16_t spx_word16_t; +typedef spx_int32_t spx_word32_t; +typedef spx_word32_t spx_mem_t; +typedef spx_word16_t spx_coef_t; +typedef spx_word16_t spx_lsp_t; +typedef spx_word32_t spx_sig_t; + +#define Q15ONE 32767 + +#define LPC_SCALING 8192 +#define SIG_SCALING 16384 +#define LSP_SCALING 8192. +#define GAMMA_SCALING 32768. +#define GAIN_SCALING 64 +#define GAIN_SCALING_1 0.015625 + +#define LPC_SHIFT 13 +#define LSP_SHIFT 13 +#define SIG_SHIFT 14 +#define GAIN_SHIFT 6 + +#define VERY_SMALL 0 +#define VERY_LARGE32 ((spx_word32_t)2147483647) +#define VERY_LARGE16 ((spx_word16_t)32767) +#define Q15_ONE ((spx_word16_t)32767) + + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef ARM5E_ASM +#include "fixed_arm5e.h" +#elif defined (ARM4_ASM) +#include "fixed_arm4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#endif + +#endif + + +#else + +typedef float spx_mem_t; +typedef float spx_coef_t; +typedef float spx_lsp_t; +typedef float spx_sig_t; +typedef float spx_word16_t; +typedef float spx_word32_t; + +#define Q15ONE 1.0f +#define LPC_SCALING 1.f +#define SIG_SCALING 1.f +#define LSP_SCALING 1.f +#define GAMMA_SCALING 1.f +#define GAIN_SCALING 1.f +#define GAIN_SCALING_1 1.f + + +#define VERY_SMALL 1e-15f +#define VERY_LARGE32 1e15f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((spx_word16_t)1.f) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR16(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) +#define SATURATE16(x,a) (x) +#define SATURATE32(x,a) (x) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) +#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) + +#define MULT16_32_Q11(a,b) ((a)*(b)) +#define MULT16_32_Q13(a,b) ((a)*(b)) +#define MULT16_32_Q14(a,b) ((a)*(b)) +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_P15(a,b) ((a)*(b)) + +#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) +#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) + + +#endif + + +#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + +/* 2 on TI C5x DSP */ +#define BYTES_PER_CHAR 2 +#define BITS_PER_CHAR 16 +#define LOG2_BITS_PER_CHAR 4 + +#else + +#define BYTES_PER_CHAR 1 +#define BITS_PER_CHAR 8 +#define LOG2_BITS_PER_CHAR 3 + +#endif + + + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + + +#endif diff --git a/native/codec/libraries/speex/libspeex/bfin.h b/native/codec/libraries/speex/libspeex/bfin.h new file mode 100644 index 0000000..b934cf2 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/bfin.h @@ -0,0 +1,15 @@ +/* Common Blackfin assembly defines + * + * Copyright (C) 2005-2009 Analog Devices + */ + +#if __GNUC__ <= 3 +/* GCC-3.4 and older did not use hardware loops and thus did not have + * register constraints for declaring clobbers. + */ +# define BFIN_HWLOOP0_REGS +# define BFIN_HWLOOP1_REGS +#else +# define BFIN_HWLOOP0_REGS , "LB0", "LT0", "LC0" +# define BFIN_HWLOOP1_REGS , "LB1", "LT1", "LC1" +#endif diff --git a/native/codec/libraries/speex/libspeex/bits.c b/native/codec/libraries/speex/libspeex/bits.c new file mode 100644 index 0000000..2d782a2 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/bits.c @@ -0,0 +1,372 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex_bits.c + + Handles bit packing/unpacking + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_bits.h" +#include "arch.h" +#include "os_support.h" + +/* Maximum size of the bit-stream (for fixed-size allocation) */ +#ifndef MAX_CHARS_PER_FRAME +#define MAX_CHARS_PER_FRAME (2000/BYTES_PER_CHAR) +#endif + +EXPORT void speex_bits_init(SpeexBits *bits) +{ + bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); + if (!bits->chars) + return; + + bits->buf_size = MAX_CHARS_PER_FRAME; + + bits->owner=1; + + speex_bits_reset(bits); +} + +EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) +{ + bits->chars = (char*)buff; + bits->buf_size = buf_size; + + bits->owner=0; + + speex_bits_reset(bits); +} + +EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) +{ + bits->chars = (char*)buff; + bits->buf_size = buf_size; + + bits->owner=0; + + bits->nbBits=buf_size<charPtr=0; + bits->bitPtr=0; + bits->overflow=0; + +} + +EXPORT void speex_bits_destroy(SpeexBits *bits) +{ + if (bits->owner) + speex_free(bits->chars); + /* Will do something once the allocation is dynamic */ +} + +EXPORT void speex_bits_reset(SpeexBits *bits) +{ + /* We only need to clear the first byte now */ + bits->chars[0]=0; + bits->nbBits=0; + bits->charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +EXPORT void speex_bits_rewind(SpeexBits *bits) +{ + bits->charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +EXPORT void speex_bits_read_from(SpeexBits *bits, const char *chars, int len) +{ + int i; + int nchars = len / BYTES_PER_CHAR; + if (nchars > bits->buf_size) + { + speex_notify("Packet is larger than allocated buffer"); + if (bits->owner) + { + char *tmp = (char*)speex_realloc(bits->chars, nchars); + if (tmp) + { + bits->buf_size=nchars; + bits->chars=tmp; + } else { + nchars=bits->buf_size; + speex_warning("Could not resize input buffer: truncating input"); + } + } else { + speex_warning("Do not own input buffer: truncating oversize input"); + nchars=bits->buf_size; + } + } +#if (BYTES_PER_CHAR==2) +/* Swap bytes to proper endian order (could be done externally) */ +#define HTOLS(A) ((((A) >> 8)&0xff)|(((A) & 0xff)<<8)) +#else +#define HTOLS(A) (A) +#endif + for (i=0;ichars[i]=HTOLS(chars[i]); + + bits->nbBits=nchars<charPtr=0; + bits->bitPtr=0; + bits->overflow=0; +} + +static void speex_bits_flush(SpeexBits *bits) +{ + int nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); + if (bits->charPtr>0) + SPEEX_MOVE(bits->chars, &bits->chars[bits->charPtr], nchars-bits->charPtr); + bits->nbBits -= bits->charPtr<charPtr=0; +} + +EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, const char *chars, int nbytes) +{ + int i,pos; + int nchars = nbytes/BYTES_PER_CHAR; + + if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size) + { + /* Packet is larger than allocated buffer */ + if (bits->owner) + { + char *tmp = (char*)speex_realloc(bits->chars, (bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1); + if (tmp) + { + bits->buf_size=(bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1; + bits->chars=tmp; + } else { + nchars=bits->buf_size-(bits->nbBits>>LOG2_BITS_PER_CHAR)-1; + speex_warning("Could not resize input buffer: truncating oversize input"); + } + } else { + speex_warning("Do not own input buffer: truncating oversize input"); + nchars=bits->buf_size; + } + } + + speex_bits_flush(bits); + pos=bits->nbBits>>LOG2_BITS_PER_CHAR; + for (i=0;ichars[pos+i]=HTOLS(chars[i]); + bits->nbBits+=nchars<bitPtr; + charPtr=bits->charPtr; + nbBits=bits->nbBits; + speex_bits_insert_terminator(bits); + bits->bitPtr=bitPtr; + bits->charPtr=charPtr; + bits->nbBits=nbBits; + + if (max_nchars > ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)) + max_nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); + + for (i=0;ichars[i]); + return max_nchars*BYTES_PER_CHAR; +} + +EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) +{ + int max_nchars = max_nbytes/BYTES_PER_CHAR; + int i; + if (max_nchars > ((bits->nbBits)>>LOG2_BITS_PER_CHAR)) + max_nchars = ((bits->nbBits)>>LOG2_BITS_PER_CHAR); + for (i=0;ichars[i]); + + if (bits->bitPtr>0) + bits->chars[0]=bits->chars[max_nchars]; + else + bits->chars[0]=0; + bits->charPtr=0; + bits->nbBits &= (BITS_PER_CHAR-1); + return max_nchars*BYTES_PER_CHAR; +} + +EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits) +{ + unsigned int d=data; + + if (bits->charPtr+((nbBits+bits->bitPtr)>>LOG2_BITS_PER_CHAR) >= bits->buf_size) + { + speex_notify("Buffer too small to pack bits"); + if (bits->owner) + { + int new_nchars = ((bits->buf_size+5)*3)>>1; + char *tmp = (char*)speex_realloc(bits->chars, new_nchars); + if (tmp) + { + bits->buf_size=new_nchars; + bits->chars=tmp; + } else { + speex_warning("Could not resize input buffer: not packing"); + return; + } + } else { + speex_warning("Do not own input buffer: not packing"); + return; + } + } + + while(nbBits) + { + int bit; + bit = (d>>(nbBits-1))&1; + bits->chars[bits->charPtr] |= bit<<(BITS_PER_CHAR-1-bits->bitPtr); + bits->bitPtr++; + + if (bits->bitPtr==BITS_PER_CHAR) + { + bits->bitPtr=0; + bits->charPtr++; + bits->chars[bits->charPtr] = 0; + } + bits->nbBits++; + nbBits--; + } +} + +EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) +{ + unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); + /* If number is negative */ + if (d>>(nbBits-1)) + { + d |= (-1)<charPtr<bitPtr+nbBits>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + while(nbBits) + { + d<<=1; + d |= (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; + bits->bitPtr++; + if (bits->bitPtr==BITS_PER_CHAR) + { + bits->bitPtr=0; + bits->charPtr++; + } + nbBits--; + } + return d; +} + +EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) +{ + unsigned int d=0; + int bitPtr, charPtr; + char *chars; + + if ((bits->charPtr<bitPtr+nbBits>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + + bitPtr=bits->bitPtr; + charPtr=bits->charPtr; + chars = bits->chars; + while(nbBits) + { + d<<=1; + d |= (chars[charPtr]>>(BITS_PER_CHAR-1 - bitPtr))&1; + bitPtr++; + if (bitPtr==BITS_PER_CHAR) + { + bitPtr=0; + charPtr++; + } + nbBits--; + } + return d; +} + +EXPORT int speex_bits_peek(SpeexBits *bits) +{ + if ((bits->charPtr<bitPtr+1>bits->nbBits) + bits->overflow=1; + if (bits->overflow) + return 0; + return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; +} + +EXPORT void speex_bits_advance(SpeexBits *bits, int n) +{ + if (((bits->charPtr<bitPtr+n>bits->nbBits) || bits->overflow){ + bits->overflow=1; + return; + } + bits->charPtr += (bits->bitPtr+n) >> LOG2_BITS_PER_CHAR; /* divide by BITS_PER_CHAR */ + bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ +} + +EXPORT int speex_bits_remaining(SpeexBits *bits) +{ + if (bits->overflow) + return -1; + else + return bits->nbBits-((bits->charPtr<bitPtr); +} + +EXPORT int speex_bits_nbytes(SpeexBits *bits) +{ + return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); +} + +EXPORT void speex_bits_insert_terminator(SpeexBits *bits) +{ + if (bits->bitPtr) + speex_bits_pack(bits, 0, 1); + while (bits->bitPtr) + speex_bits_pack(bits, 1, 1); +} diff --git a/native/codec/libraries/speex/libspeex/cb_search.c b/native/codec/libraries/speex/libspeex/cb_search.c new file mode 100644 index 0000000..a170fd6 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/cb_search.c @@ -0,0 +1,623 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: cb_search.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cb_search.h" +#include "filters.h" +#include "stack_alloc.h" +#include "vq.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" + +#ifdef _USE_SSE +#include "cb_search_sse.h" +#elif defined(ARM4_ASM) || defined(ARM5E_ASM) +#include "cb_search_arm4.h" +#elif defined(BFIN_ASM) +#include "cb_search_bfin.h" +#endif + +#ifndef DISABLE_ENCODER + +#ifndef OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK +static void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t *r, spx_word16_t *resp, spx_word16_t *resp2, spx_word32_t *E, int shape_cb_size, int subvect_size, char *stack) +{ + int i, j, k; + VARDECL(spx_word16_t *shape); + ALLOC(shape, subvect_size, spx_word16_t); + for (i=0;isubvect_size; + nb_subvect = params->nb_subvect; + shape_cb_size = 1<shape_bits; + shape_cb = params->shape_cb; + have_sign = params->have_sign; + ALLOC(resp, shape_cb_size*subvect_size, spx_word16_t); +#ifdef _USE_SSE + ALLOC(resp2, (shape_cb_size*subvect_size)>>2, __m128); + ALLOC(E, shape_cb_size>>2, __m128); +#else + resp2 = resp; + ALLOC(E, shape_cb_size, spx_word32_t); +#endif + ALLOC(t, nsf, spx_word16_t); + ALLOC(e, nsf, spx_sig_t); + + /* FIXME: Do we still need to copy the target? */ + SPEEX_COPY(t, target, nsf); + + compute_weighted_codebook(shape_cb, r, resp, resp2, E, shape_cb_size, subvect_size, stack); + + for (i=0;ishape_bits+have_sign); + + { + int rind; + spx_word16_t *res; + spx_word16_t sign=1; + rind = best_index; + if (rind>=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + res = resp+rind*subvect_size; + if (sign>0) + for (m=0;m=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + + q=subvect_size-m; +#ifdef FIXED_POINT + g=sign*shape_cb[rind*subvect_size+m]; +#else + g=sign*0.03125*shape_cb[rind*subvect_size+m]; +#endif + target_update(t+subvect_size*(i+1), g, r+q, nsf-subvect_size*(i+1)); + } + } + + /* Update excitation */ + /* FIXME: We could update the excitation directly above */ + for (j=0;j10) + N=10; + /* Complexity isn't as important for the codebooks as it is for the pitch */ + N=(2*N)/3; + if (N<1) + N=1; + if (N==1) + { + split_cb_search_shape_sign_N1(target,ak,awk1,awk2,par,p,nsf,exc,r,bits,stack,update_target); + return; + } + ALLOC(ot2, N, spx_word16_t*); + ALLOC(nt2, N, spx_word16_t*); + ALLOC(oind, N, int*); + ALLOC(nind, N, int*); + + params = (const split_cb_params *) par; + subvect_size = params->subvect_size; + nb_subvect = params->nb_subvect; + shape_cb_size = 1<shape_bits; + shape_cb = params->shape_cb; + have_sign = params->have_sign; + ALLOC(resp, shape_cb_size*subvect_size, spx_word16_t); +#ifdef _USE_SSE + ALLOC(resp2, (shape_cb_size*subvect_size)>>2, __m128); + ALLOC(E, shape_cb_size>>2, __m128); +#else + resp2 = resp; + ALLOC(E, shape_cb_size, spx_word32_t); +#endif + ALLOC(t, nsf, spx_word16_t); + ALLOC(e, nsf, spx_sig_t); + ALLOC(ind, nb_subvect, int); + + ALLOC(tmp, 2*N*nsf, spx_word16_t); + for (i=0;im;n--) + { + ndist[n] = ndist[n-1]; + best_nind[n] = best_nind[n-1]; + best_ntarget[n] = best_ntarget[n-1]; + } + /* n is equal to m here, so they're interchangeable */ + ndist[m] = err; + best_nind[n] = best_index[k]; + best_ntarget[n] = j; + break; + } + } + } + } + if (i==0) + break; + } + for (j=0;j=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } + + q=subvect_size-m; +#ifdef FIXED_POINT + g=sign*shape_cb[rind*subvect_size+m]; +#else + g=sign*0.03125*shape_cb[rind*subvect_size+m]; +#endif + target_update(nt[j]+subvect_size*(i+1), g, r+q, nsf-subvect_size*(i+1)); + } + + for (q=0;qshape_bits+have_sign); + } + + /* Put everything back together */ + for (i=0;i=shape_cb_size) + { + sign=-1; + rind-=shape_cb_size; + } +#ifdef FIXED_POINT + if (sign==1) + { + for (j=0;jsubvect_size; + nb_subvect = params->nb_subvect; + + shape_cb = params->shape_cb; + have_sign = params->have_sign; + + ALLOC(ind, nb_subvect, int); + ALLOC(signs, nb_subvect, int); + + /* Decode codewords and gains */ + for (i=0;ishape_bits); + } + /* Compute decoded excitation */ + for (i=0;i>>= 13;\n\t" + "A1 += R0.L*R0.L (IS);\n\t" + "W[P3++] = R0;\n\t" + "P0 += 1;\n\t" + "P2 += 2;\n\t" + "LOOP_END outter%=;\n\t" + "P4 = %4;\n\t" + "R1 = A1;\n\t" + "[P4] = R1;\n\t" + : + : "m" (subvect_size), "m" (shape_cb), "m" (r), "m" (resp), "m" (E) + : "A0", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "I0", "I1", "L0", + "L1", "A0", "A1", "memory", "ASTAT" BFIN_HWLOOP0_REGS BFIN_HWLOOP1_REGS + ); + shape_cb += subvect_size; + resp += subvect_size; + E++; + } +} + +#define OVERRIDE_TARGET_UPDATE +static inline void target_update(spx_word16_t *t, spx_word16_t g, spx_word16_t *r, int len) +{ + if (!len) + return; + __asm__ __volatile__ + ( + "I0 = %0;\n\t" + "I1 = %1;\n\t" + "L0 = 0;\n\t" + "L1 = 0;\n\t" + "R2 = 4096;\n\t" + "LOOP tupdate%= LC0 = %3;\n\t" + "LOOP_BEGIN tupdate%=;\n\t" + "R0.L = W[I0] || R1.L = W[I1++];\n\t" + "R1 = (A1 = R1.L*%2.L) (IS);\n\t" + "R1 = R1 + R2;\n\t" + "R1 >>>= 13;\n\t" + "R0.L = R0.L - R1.L;\n\t" + "W[I0++] = R0.L;\n\t" + "LOOP_END tupdate%=;\n\t" + : + : "a" (t), "a" (r), "d" (g), "a" (len) + : "R0", "R1", "R2", "A1", "I0", "I1", "L0", "L1", "ASTAT" BFIN_HWLOOP0_REGS + ); +} diff --git a/native/codec/libraries/speex/libspeex/cb_search_sse.h b/native/codec/libraries/speex/libspeex/cb_search_sse.h new file mode 100644 index 0000000..8b03968 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/cb_search_sse.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file cb_search_sse.h + @brief Fixed codebook functions (SSE version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +static inline void _spx_mm_getr_ps (__m128 U, float *__Z, float *__Y, float *__X, float *__W) +{ + union { + float __a[4]; + __m128 __v; + } __u; + + __u.__v = U; + + *__Z = __u.__a[0]; + *__Y = __u.__a[1]; + *__X = __u.__a[2]; + *__W = __u.__a[3]; + +} + +#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK +static void compute_weighted_codebook(const signed char *shape_cb, const spx_sig_t *_r, float *resp, __m128 *resp2, __m128 *E, int shape_cb_size, int subvect_size, char *stack) +{ + int i, j, k; + __m128 resj, EE; + VARDECL(__m128 *r); + VARDECL(__m128 *shape); + ALLOC(r, subvect_size, __m128); + ALLOC(shape, subvect_size, __m128); + for(j=0;j>2] = EE; + } +} diff --git a/native/codec/libraries/speex/libspeex/exc_10_16_table.c b/native/codec/libraries/speex/libspeex/exc_10_16_table.c new file mode 100644 index 0000000..f75ba30 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/exc_10_16_table.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_10_16_table.c + Codebook for excitation in narrowband CELP mode (3200 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_10_16_table[160] = { +22,39,14,44,11,35,-2,23,-4,6, +46,-28,13,-27,-23,12,4,20,-5,9, +37,-18,-23,23,0,9,-6,-20,4,-1, +-17,-5,-4,17,0,1,9,-2,1,2, +2,-12,8,-25,39,15,9,16,-55,-11, +9,11,5,10,-2,-60,8,13,-6,11, +-16,27,-47,-12,11,1,16,-7,9,-3, +-29,9,-14,25,-19,34,36,12,40,-10, +-3,-24,-14,-37,-21,-35,-2,-36,3,-6, +67,28,6,-17,-3,-12,-16,-15,-17,-7, +-59,-36,-13,1,7,1,2,10,2,11, +13,10,8,-2,7,3,5,4,2,2, +-3,-8,4,-5,6,7,-42,15,35,-2, +-46,38,28,-20,-9,1,7,-3,0,-2, +0,0,0,0,0,0,0,0,0,0, +-15,-28,52,32,5,-5,-17,-20,-10,-1}; diff --git a/native/codec/libraries/speex/libspeex/exc_10_32_table.c b/native/codec/libraries/speex/libspeex/exc_10_32_table.c new file mode 100644 index 0000000..89425f0 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/exc_10_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_10_32_table.c + Codebook for excitation in narrowband CELP mode (4000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_10_32_table[320] = { +7,17,17,27,25,22,12,4,-3,0, +28,-36,39,-24,-15,3,-9,15,-5,10, +31,-28,11,31,-21,9,-11,-11,-2,-7, +-25,14,-22,31,4,-14,19,-12,14,-5, +4,-7,4,-5,9,0,-2,42,-47,-16, +1,8,0,9,23,-57,0,28,-11,6, +-31,55,-45,3,-5,4,2,-2,4,-7, +-3,6,-2,7,-3,12,5,8,54,-10, +8,-7,-8,-24,-25,-27,-14,-5,8,5, +44,23,5,-9,-11,-11,-13,-9,-12,-8, +-29,-8,-22,6,-15,3,-12,-1,-5,-3, +34,-1,29,-16,17,-4,12,2,1,4, +-2,-4,2,-1,11,-3,-52,28,30,-9, +-32,25,44,-20,-24,4,6,-1,0,0, +0,0,0,0,0,0,0,0,0,0, +-25,-10,22,29,13,-13,-22,-13,-4,0, +-4,-16,10,15,-36,-24,28,25,-1,-3, +66,-33,-11,-15,6,0,3,4,-2,5, +24,-20,-47,29,19,-2,-4,-1,0,-1, +-2,3,1,8,-11,5,5,-57,28,28, +0,-16,4,-4,12,-6,-1,2,-20,61, +-9,24,-22,-42,29,6,17,8,4,2, +-65,15,8,10,5,6,5,3,2,-2, +-3,5,-9,4,-5,23,13,23,-3,-63, +3,-5,-4,-6,0,-3,23,-36,-46,9, +5,5,8,4,9,-5,1,-3,10,1, +-6,10,-11,24,-47,31,22,-12,14,-10, +6,11,-7,-7,7,-31,51,-12,-6,7, +6,-17,9,-11,-20,52,-19,3,-6,-6, +-8,-5,23,-41,37,1,-21,10,-14,8, +7,5,-15,-15,23,39,-26,-33,7,2, +-32,-30,-21,-8,4,12,17,15,14,11}; diff --git a/native/codec/libraries/speex/libspeex/exc_20_32_table.c b/native/codec/libraries/speex/libspeex/exc_20_32_table.c new file mode 100644 index 0000000..f7b3032 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/exc_20_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_20_32_table.c + Codebook for excitation in narrowband CELP mode (2000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_20_32_table[640] = { +12,32,25,46,36,33,9,14,-3,6,1,-8,0,-10,-5,-7,-7,-7,-5,-5, +31,-27,24,-32,-4,10,-11,21,-3,19,23,-9,22,24,-10,-1,-10,-13,-7,-11, +42,-33,31,19,-8,0,-10,-16,1,-21,-17,10,-8,14,8,4,11,-2,5,-2, +-33,11,-16,33,11,-4,9,-4,11,2,6,-5,8,-5,11,-4,-6,26,-36,-16, +0,4,-2,-8,12,6,-1,34,-46,-22,9,9,21,9,5,-66,-5,26,2,10, +13,2,19,9,12,-81,3,13,13,0,-14,22,-35,6,-7,-4,6,-6,10,-6, +-31,38,-33,0,-10,-11,5,-12,12,-17,5,0,-6,13,-9,10,8,25,33,2, +-12,8,-6,10,-2,21,7,17,43,5,11,-7,-9,-20,-36,-20,-23,-4,-4,-3, +27,-9,-9,-49,-39,-38,-11,-9,6,5,23,25,5,3,3,4,1,2,-3,-1, +87,39,17,-21,-9,-19,-9,-15,-13,-14,-17,-11,-10,-11,-8,-6,-1,-3,-3,-1, +-54,-34,-27,-8,-11,-4,-5,0,0,4,8,6,9,7,9,7,6,5,5,5, +48,10,19,-10,12,-1,9,-3,2,5,-3,2,-2,-2,0,-2,-26,6,9,-7, +-16,-9,2,7,7,-5,-43,11,22,-11,-9,34,37,-15,-13,-6,1,-1,1,1, +-64,56,52,-11,-27,5,4,3,1,2,1,3,-1,-4,-4,-10,-7,-4,-4,2, +-1,-7,-7,-12,-10,-15,-9,-5,-5,-11,-16,-13,6,16,4,-13,-16,-10,-4,2, +-47,-13,25,47,19,-14,-20,-8,-17,0,-3,-13,1,6,-17,-14,15,1,10,6, +-24,0,-10,19,-69,-8,14,49,17,-5,33,-29,3,-4,0,2,-8,5,-6,2, +120,-56,-12,-47,23,-9,6,-5,1,2,-5,1,-10,4,-1,-1,4,-1,0,-3, +30,-52,-67,30,22,11,-1,-4,3,0,7,2,0,1,-10,-4,-8,-13,5,1, +1,-1,5,13,-9,-3,-10,-62,22,48,-4,-6,2,3,5,1,1,4,1,13, +3,-20,10,-9,13,-2,-4,9,-20,44,-1,20,-32,-67,19,0,28,11,8,2, +-11,15,-19,-53,31,2,34,10,6,-4,-58,8,10,13,14,1,12,2,0,0, +-128,37,-8,44,-9,26,-3,18,2,6,11,-1,9,1,5,3,0,1,1,2, +12,3,-2,-3,7,25,9,18,-6,-37,3,-8,-16,3,-10,-7,17,-34,-44,11, +17,-15,-3,-16,-1,-13,11,-46,-65,-2,8,13,2,4,4,5,15,5,9,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-9,19,-12,12,-28,38,29,-1,12,2,5,23,-10,3,4,-15,21,-4,3,3, +6,17,-9,-4,-8,-20,26,5,-10,6,1,-19,18,-15,-12,47,-6,-2,-7,-9, +-1,-17,-2,-2,-14,30,-14,2,-7,-4,-1,-12,11,-25,16,-3,-12,11,-7,7, +-17,1,19,-28,31,-7,-10,7,-10,3,12,5,-16,6,24,41,-29,-54,0,1, +7,-1,5,-6,13,10,-4,-8,8,-9,-27,-53,-38,-1,10,19,17,16,12,12, +0,3,-7,-4,13,12,-31,-14,6,-5,3,5,17,43,50,25,10,1,-6,-2}; diff --git a/native/codec/libraries/speex/libspeex/exc_5_256_table.c b/native/codec/libraries/speex/libspeex/exc_5_256_table.c new file mode 100644 index 0000000..169b628 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/exc_5_256_table.c @@ -0,0 +1,290 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_5_256_table.c + Codebook for excitation in narrowband CELP mode (12800 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_5_256_table[1280] = { +-8,-37,5,-43,5, +73,61,39,12,-3, +-61,-32,2,42,30, +-3,17,-27,9,34, +20,-1,-5,2,23, +-7,-46,26,53,-47, +20,-2,-33,-89,-51, +-64,27,11,15,-34, +-5,-56,25,-9,-1, +-29,1,40,67,-23, +-16,16,33,19,7, +14,85,22,-10,-10, +-12,-7,-1,52,89, +29,11,-20,-37,-46, +-15,17,-24,-28,24, +2,1,0,23,-101, +23,14,-1,-23,-18, +9,5,-13,38,1, +-28,-28,4,27,51, +-26,34,-40,35,47, +54,38,-54,-26,-6, +42,-25,13,-30,-36, +18,41,-4,-33,23, +-32,-7,-4,51,-3, +17,-52,56,-47,36, +-2,-21,36,10,8, +-33,31,19,9,-5, +-40,10,-9,-21,19, +18,-78,-18,-5,0, +-26,-36,-47,-51,-44, +18,40,27,-2,29, +49,-26,2,32,-54, +30,-73,54,3,-5, +36,22,53,10,-1, +-84,-53,-29,-5,3, +-44,53,-51,4,22, +71,-35,-1,33,-5, +-27,-7,36,17,-23, +-39,16,-9,-55,-15, +-20,39,-35,6,-39, +-14,18,48,-64,-17, +-15,9,39,81,37, +-68,37,47,-21,-6, +-104,13,6,9,-2, +35,8,-23,18,42, +45,21,33,-5,-49, +9,-6,-43,-56,39, +2,-16,-25,87,1, +-3,-9,17,-25,-11, +-9,-1,10,2,-14, +-14,4,-1,-10,28, +-23,40,-32,26,-9, +26,4,-27,-23,3, +42,-60,1,49,-3, +27,10,-52,-40,-2, +18,45,-23,17,-44, +3,-3,17,-46,52, +-40,-47,25,75,31, +-49,53,30,-30,-32, +-36,38,-6,-15,-16, +54,-27,-48,3,38, +-29,-32,-22,-14,-4, +-23,-13,32,-39,9, +8,-45,-13,34,-16, +49,40,32,31,28, +23,23,32,47,59, +-68,8,62,44,25, +-14,-24,-65,-16,36, +67,-25,-38,-21,4, +-33,-2,42,5,-63, +40,11,26,-42,-23, +-61,79,-31,23,-20, +10,-32,53,-25,-36, +10,-26,-5,3,0, +-71,5,-10,-37,1, +-24,21,-54,-17,1, +-29,-25,-15,-27,32, +68,45,-16,-37,-18, +-5,1,0,-77,71, +-6,3,-20,71,-67, +29,-35,10,-30,19, +4,16,17,5,0, +-14,19,2,28,26, +59,3,2,24,39, +55,-50,-45,-18,-17, +33,-35,14,-1,1, +8,87,-35,-29,0, +-27,13,-7,23,-13, +37,-40,50,-35,14, +19,-7,-14,49,54, +-5,22,-2,-29,-8, +-27,38,13,27,48, +12,-41,-21,-15,28, +7,-16,-24,-19,-20, +11,-20,9,2,13, +23,-20,11,27,-27, +71,-69,8,2,-6, +22,12,16,16,9, +-16,-8,-17,1,25, +1,40,-37,-33,66, +94,53,4,-22,-25, +-41,-42,25,35,-16, +-15,57,31,-29,-32, +21,16,-60,45,15, +-1,7,57,-26,-47, +-29,11,8,15,19, +-105,-8,54,27,10, +-17,6,-12,-1,-10, +4,0,23,-10,31, +13,11,10,12,-64, +23,-3,-8,-19,16, +52,24,-40,16,10, +40,5,9,0,-13, +-7,-21,-8,-6,-7, +-21,59,16,-53,18, +-60,11,-47,14,-18, +25,-13,-24,4,-39, +16,-28,54,26,-67, +30,27,-20,-52,20, +-12,55,12,18,-16, +39,-14,-6,-26,56, +-88,-55,12,25,26, +-37,6,75,0,-34, +-81,54,-30,1,-7, +49,-23,-14,21,10, +-62,-58,-57,-47,-34, +15,-4,34,-78,31, +25,-11,7,50,-10, +42,-63,14,-36,-4, +57,55,57,53,42, +-42,-1,15,40,37, +15,25,-11,6,1, +31,-2,-6,-1,-7, +-64,34,28,30,-1, +3,21,0,-88,-12, +-56,25,-28,40,8, +-28,-14,9,12,2, +-6,-17,22,49,-6, +-26,14,28,-20,4, +-12,50,35,40,13, +-38,-58,-29,17,30, +22,60,26,-54,-39, +-12,58,-28,-63,10, +-21,-8,-12,26,-62, +6,-10,-11,-22,-6, +-7,4,1,18,2, +-70,11,14,4,13, +19,-24,-34,24,67, +17,51,-21,13,23, +54,-30,48,1,-13, +80,26,-16,-2,13, +-4,6,-30,29,-24, +73,-58,30,-27,20, +-2,-21,41,45,30, +-27,-3,-5,-18,-20, +-49,-3,-35,10,42, +-19,-67,-53,-11,9, +13,-15,-33,-51,-30, +15,7,25,-30,4, +28,-22,-34,54,-29, +39,-46,20,16,34, +-4,47,75,1,-44, +-55,-24,7,-1,9, +-42,50,-8,-36,41, +68,0,-4,-10,-23, +-15,-50,64,36,-9, +-27,12,25,-38,-47, +-37,32,-49,51,-36, +2,-4,69,-26,19, +7,45,67,46,13, +-63,46,15,-47,4, +-41,13,-6,5,-21, +37,26,-55,-7,33, +-1,-28,10,-17,-64, +-14,0,-36,-17,93, +-3,-9,-66,44,-21, +3,-12,38,-6,-13, +-12,19,13,43,-43, +-10,-12,6,-5,9, +-49,32,-5,2,4, +5,15,-16,10,-21, +8,-62,-8,64,8, +79,-1,-66,-49,-18, +5,40,-5,-30,-45, +1,-6,21,-32,93, +-18,-30,-21,32,21, +-18,22,8,5,-41, +-54,80,22,-10,-7, +-8,-23,-64,66,56, +-14,-30,-41,-46,-14, +-29,-37,27,-14,42, +-2,-9,-29,34,14, +33,-14,22,4,10, +26,26,28,32,23, +-72,-32,3,0,-14, +35,-42,-78,-32,6, +29,-18,-45,-5,7, +-33,-45,-3,-22,-34, +8,-8,4,-51,-25, +-9,59,-78,21,-5, +-25,-48,66,-15,-17, +-24,-49,-13,25,-23, +-64,-6,40,-24,-19, +-11,57,-33,-8,1, +10,-52,-54,28,39, +49,34,-11,-61,-41, +-43,10,15,-15,51, +30,15,-51,32,-34, +-2,-34,14,18,16, +1,1,-3,-3,1, +1,-18,6,16,48, +12,-5,-42,7,36, +48,7,-20,-10,7, +12,2,54,39,-38, +37,54,4,-11,-8, +-46,-10,5,-10,-34, +46,-12,29,-37,39, +36,-11,24,56,17, +14,20,25,0,-25, +-28,55,-7,-5,27, +3,9,-26,-8,6, +-24,-10,-30,-31,-34, +18,4,22,21,40, +-1,-29,-37,-8,-21, +92,-29,11,-3,11, +73,23,22,7,4, +-44,-9,-11,21,-13, +11,9,-78,-1,47, +114,-12,-37,-19,-5, +-11,-22,19,12,-30, +7,38,45,-21,-8, +-9,55,-45,56,-21, +7,17,46,-57,-87, +-6,27,31,31,7, +-56,-12,46,21,-5, +-12,36,3,3,-21, +43,19,12,-7,9, +-14,0,-9,-33,-91, +7,26,3,-11,64, +83,-31,-46,25,2, +9,5,2,2,-1, +20,-17,10,-5,-27, +-8,20,8,-19,16, +-21,-13,-31,5,5, +42,24,9,34,-20, +28,-61,22,11,-39, +64,-20,-1,-30,-9, +-20,24,-25,-24,-29, +22,-60,6,-5,41, +-9,-87,14,34,15, +-57,52,69,15,-3, +-102,58,16,3,6, +60,-75,-32,26,7, +-57,-27,-32,-24,-21, +-29,-16,62,-46,31, +30,-27,-15,7,15}; diff --git a/native/codec/libraries/speex/libspeex/exc_5_64_table.c b/native/codec/libraries/speex/libspeex/exc_5_64_table.c new file mode 100644 index 0000000..6d2ae2b --- /dev/null +++ b/native/codec/libraries/speex/libspeex/exc_5_64_table.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_5_64_table.c + Codebook for excitation in narrowband CELP mode (9600 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_5_64_table[320]={ +1,5,-15,49,-66, +-48,-4,50,-44,7, +37,16,-18,25,-26, +-26,-15,19,19,-27, +-47,28,57,5,-17, +-32,-41,68,21,-2, +64,56,8,-16,-13, +-26,-9,-16,11,6, +-39,25,-19,22,-31, +20,-45,55,-43,10, +-16,47,-40,40,-20, +-51,3,-17,-14,-15, +-24,53,-20,-46,46, +27,-68,32,3,-18, +-5,9,-31,16,-9, +-10,-1,-23,48,95, +47,25,-41,-32,-3, +15,-25,-55,36,41, +-27,20,5,13,14, +-22,5,2,-23,18, +46,-15,17,-18,-34, +-5,-8,27,-55,73, +16,2,-1,-17,40, +-78,33,0,2,19, +4,53,-16,-15,-16, +-28,-3,-13,49,8, +-7,-29,27,-13,32, +20,32,-61,16,14, +41,44,40,24,20, +7,4,48,-60,-77, +17,-6,-48,65,-15, +32,-30,-71,-10,-3, +-6,10,-2,-7,-29, +-56,67,-30,7,-5, +86,-6,-10,0,5, +-31,60,34,-38,-3, +24,10,-2,30,23, +24,-41,12,70,-43, +15,-17,6,13,16, +-13,8,30,-15,-8, +5,23,-34,-98,-4, +-13,13,-48,-31,70, +12,31,25,24,-24, +26,-7,33,-16,8, +5,-11,-14,-8,-65, +13,10,-2,-9,0, +-3,-68,5,35,7, +0,-31,-1,-17,-9, +-9,16,-37,-18,-1, +69,-48,-28,22,-21, +-11,5,49,55,23, +-86,-36,16,2,13, +63,-51,30,-11,13, +24,-18,-6,14,-19, +1,41,9,-5,27, +-36,-44,-34,-37,-21, +-26,31,-39,15,43, +5,-8,29,20,-8, +-20,-52,-28,-1,13, +26,-34,-10,-9,27, +-8,8,27,-66,4, +12,-22,49,10,-77, +32,-18,3,-38,12, +-3,-1,2,2,0}; diff --git a/native/codec/libraries/speex/libspeex/exc_8_128_table.c b/native/codec/libraries/speex/libspeex/exc_8_128_table.c new file mode 100644 index 0000000..fd05890 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/exc_8_128_table.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: exc_8_128_table.c + Codebook for excitation in narrowband CELP mode (7000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +const signed char exc_8_128_table[1024] = { +-14,9,13,-32,2,-10,31,-10, +-8,-8,6,-4,-1,10,-64,23, +6,20,13,6,8,-22,16,34, +7,42,-49,-28,5,26,4,-15, +41,34,41,32,33,24,23,14, +8,40,34,4,-24,-41,-19,-15, +13,-13,33,-54,24,27,-44,33, +27,-15,-15,24,-19,14,-36,14, +-9,24,-12,-4,37,-5,16,-34, +5,10,33,-15,-54,-16,12,25, +12,1,2,0,3,-1,-4,-4, +11,2,-56,54,27,-20,13,-6, +-46,-41,-33,-11,-5,7,12,14, +-14,-5,8,20,6,3,4,-8, +-5,-42,11,8,-14,25,-2,2, +13,11,-22,39,-9,9,5,-45, +-9,7,-9,12,-7,34,-17,-102, +7,2,-42,18,35,-9,-34,11, +-5,-2,3,22,46,-52,-25,-9, +-94,8,11,-5,-5,-5,4,-7, +-35,-7,54,5,-32,3,24,-9, +-22,8,65,37,-1,-12,-23,-6, +-9,-28,55,-33,14,-3,2,18, +-60,41,-17,8,-16,17,-11,0, +-11,29,-28,37,9,-53,33,-14, +-9,7,-25,-7,-11,26,-32,-8, +24,-21,22,-19,19,-10,29,-14, +0,0,0,0,0,0,0,0, +-5,-52,10,41,6,-30,-4,16, +32,22,-27,-22,32,-3,-28,-3, +3,-35,6,17,23,21,8,2, +4,-45,-17,14,23,-4,-31,-11, +-3,14,1,19,-11,2,61,-8, +9,-12,7,-10,12,-3,-24,99, +-48,23,50,-37,-5,-23,0,8, +-14,35,-64,-5,46,-25,13,-1, +-49,-19,-15,9,34,50,25,11, +-6,-9,-16,-20,-32,-33,-32,-27, +10,-8,12,-15,56,-14,-32,33, +3,-9,1,65,-9,-9,-10,-2, +-6,-23,9,17,3,-28,13,-32, +4,-2,-10,4,-16,76,12,-52, +6,13,33,-6,4,-14,-9,-3, +1,-15,-16,28,1,-15,11,16, +9,4,-21,-37,-40,-6,22,12, +-15,-23,-14,-17,-16,-9,-10,-9, +13,-39,41,5,-9,16,-38,25, +46,-47,4,49,-14,17,-2,6, +18,5,-6,-33,-22,44,50,-2, +1,3,-6,7,7,-3,-21,38, +-18,34,-14,-41,60,-13,6,16, +-24,35,19,-13,-36,24,3,-17, +-14,-10,36,44,-44,-29,-3,3, +-54,-8,12,55,26,4,-2,-5, +2,-11,22,-23,2,22,1,-25, +-39,66,-49,21,-8,-2,10,-14, +-60,25,6,10,27,-25,16,5, +-2,-9,26,-13,-20,58,-2,7, +52,-9,2,5,-4,-15,23,-1, +-38,23,8,27,-6,0,-27,-7, +39,-10,-14,26,11,-45,-12,9, +-5,34,4,-35,10,43,-22,-11, +56,-7,20,1,10,1,-26,9, +94,11,-27,-14,-13,1,-11,0, +14,-5,-6,-10,-4,-15,-8,-41, +21,-5,1,-28,-8,22,-9,33, +-23,-4,-4,-12,39,4,-7,3, +-60,80,8,-17,2,-6,12,-5, +1,9,15,27,31,30,27,23, +61,47,26,10,-5,-8,-12,-13, +5,-18,25,-15,-4,-15,-11,12, +-2,-2,-16,-2,-6,24,12,11, +-4,9,1,-9,14,-45,57,12, +20,-35,26,11,-64,32,-10,-10, +42,-4,-9,-16,32,24,7,10, +52,-11,-57,29,0,8,0,-6, +17,-17,-56,-40,7,20,18,12, +-6,16,5,7,-1,9,1,10, +29,12,16,13,-2,23,7,9, +-3,-4,-5,18,-64,13,55,-25, +9,-9,24,14,-25,15,-11,-40, +-30,37,1,-19,22,-5,-31,13, +-2,0,7,-4,16,-67,12,66, +-36,24,-8,18,-15,-23,19,0, +-45,-7,4,3,-13,13,35,5, +13,33,10,27,23,0,-7,-11, +43,-74,36,-12,2,5,-8,6, +-33,11,-16,-14,-5,-7,-3,17, +-34,27,-16,11,-9,15,33,-31, +8,-16,7,-6,-7,63,-55,-17, +11,-1,20,-46,34,-30,6,9, +19,28,-9,5,-24,-8,-23,-2, +31,-19,-16,-5,-15,-18,0,26, +18,37,-5,-15,-2,17,5,-27, +21,-33,44,12,-27,-9,17,11, +25,-21,-31,-7,13,33,-8,-25, +-7,7,-10,4,-6,-9,48,-82, +-23,-8,6,11,-23,3,-3,49, +-29,25,31,4,14,16,9,-4, +-18,10,-26,3,5,-44,-9,9, +-47,-55,15,9,28,1,4,-3, +46,6,-6,-38,-29,-31,-15,-6, +3,0,14,-6,8,-54,-50,33, +-5,1,-14,33,-48,26,-4,-5, +-3,-5,-3,-5,-28,-22,77,55, +-1,2,10,10,-9,-14,-66,-49, +11,-36,-6,-20,10,-10,16,12, +4,-1,-16,45,-44,-50,31,-2, +25,42,23,-32,-22,0,11,20, +-40,-35,-40,-36,-32,-26,-21,-13, +52,-22,6,-24,-20,17,-5,-8, +36,-25,-11,21,-26,6,34,-8, +7,20,-3,5,-25,-8,18,-5, +-9,-4,1,-9,20,20,39,48, +-24,9,5,-65,22,29,4,3, +-43,-11,32,-6,9,19,-27,-10, +-47,-14,24,10,-7,-36,-7,-1, +-4,-5,-5,16,53,25,-26,-29, +-4,-12,45,-58,-34,33,-5,2, +-1,27,-48,31,-15,22,-5,4, +7,7,-25,-3,11,-22,16,-12, +8,-3,7,-11,45,14,-73,-19, +56,-46,24,-20,28,-12,-2,-1, +-36,-3,-33,19,-6,7,2,-15, +5,-31,-45,8,35,13,20,0, +-9,48,-13,-43,-3,-13,2,-5, +72,-68,-27,2,1,-2,-7,5, +36,33,-40,-12,-4,-5,23,19}; diff --git a/native/codec/libraries/speex/libspeex/fftwrap.c b/native/codec/libraries/speex/libspeex/fftwrap.c new file mode 100644 index 0000000..4573479 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/fftwrap.c @@ -0,0 +1,448 @@ +/* Copyright (C) 2005-2006 Jean-Marc Valin + File: fftwrap.c + + Wrapper for various FFTs + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include "os_support.h" + +#define MAX_FFT_SIZE 2048 + +#ifdef FIXED_POINT +static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t bound, int len) +{ + int i, shift; + spx_word16_t max_val = 0; + for (i=0;imax_val) + max_val = in[i]; + if (-in[i]>max_val) + max_val = -in[i]; + } + shift=0; + while (max_val <= (bound>>1) && max_val != 0) + { + max_val <<= 1; + shift++; + } + for (i=0;i + +void *spx_fft_init(int size) +{ + struct drft_lookup *table; + table = speex_alloc(sizeof(struct drft_lookup)); + spx_drft_init((struct drft_lookup *)table, size); + return (void*)table; +} + +void spx_fft_destroy(void *table) +{ + spx_drft_clear(table); + speex_free(table); +} + +void spx_fft(void *table, float *in, float *out) +{ + if (in==out) + { + int i; + float scale = 1./((struct drft_lookup *)table)->n; + speex_warning("FFT should not be done in-place"); + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = scale*in[i]; + } else { + int i; + float scale = 1./((struct drft_lookup *)table)->n; + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = scale*in[i]; + } + spx_drft_forward((struct drft_lookup *)table, out); +} + +void spx_ifft(void *table, float *in, float *out) +{ + if (in==out) + { + speex_warning("FFT should not be done in-place"); + } else { + int i; + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = in[i]; + } + spx_drft_backward((struct drft_lookup *)table, out); +} + +#elif defined(USE_INTEL_MKL) +#include + +struct mkl_config { + DFTI_DESCRIPTOR_HANDLE desc; + int N; +}; + +void *spx_fft_init(int size) +{ + struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config)); + table->N = size; + DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size); + DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT); + DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE); + DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size); + DftiCommitDescriptor(table->desc); + return table; +} + +void spx_fft_destroy(void *table) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiFreeDescriptor(t->desc); + speex_free(table); +} + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeForward(t->desc, in, out); +} + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeBackward(t->desc, in, out); +} + +#elif defined(USE_INTEL_IPP) + +#include + +struct ipp_fft_config +{ + IppsDFTSpec_R_32f *dftSpec; + Ipp8u *buffer; +}; + +void *spx_fft_init(int size) +{ + int bufferSize = 0; + int hint; + struct ipp_fft_config *table; + + table = (struct ipp_fft_config *)speex_alloc(sizeof(struct ipp_fft_config)); + + /* there appears to be no performance difference between ippAlgHintFast and + ippAlgHintAccurate when using the with the floating point version + of the fft. */ + hint = ippAlgHintAccurate; + + ippsDFTInitAlloc_R_32f(&table->dftSpec, size, IPP_FFT_DIV_FWD_BY_N, hint); + + ippsDFTGetBufSize_R_32f(table->dftSpec, &bufferSize); + table->buffer = ippsMalloc_8u(bufferSize); + + return table; +} + +void spx_fft_destroy(void *table) +{ + struct ipp_fft_config *t = (struct ipp_fft_config *)table; + ippsFree(t->buffer); + ippsDFTFree_R_32f(t->dftSpec); + speex_free(t); +} + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct ipp_fft_config *t = (struct ipp_fft_config *)table; + ippsDFTFwd_RToPack_32f(in, out, t->dftSpec, t->buffer); +} + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct ipp_fft_config *t = (struct ipp_fft_config *)table; + ippsDFTInv_PackToR_32f(in, out, t->dftSpec, t->buffer); +} + +#elif defined(USE_GPL_FFTW3) + +#include + +struct fftw_config { + float *in; + float *out; + fftwf_plan fft; + fftwf_plan ifft; + int N; +}; + +void *spx_fft_init(int size) +{ + struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config)); + table->in = fftwf_malloc(sizeof(float) * (size+2)); + table->out = fftwf_malloc(sizeof(float) * (size+2)); + + table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT); + table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT); + + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct fftw_config *t = (struct fftw_config *) table; + fftwf_destroy_plan(t->fft); + fftwf_destroy_plan(t->ifft); + fftwf_free(t->in); + fftwf_free(t->out); + speex_free(table); +} + + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + struct fftw_config *t = (struct fftw_config *) table; + const int N = t->N; + float *iptr = t->in; + float *optr = t->out; + const float m = 1.0 / N; + for(i=0;ifft); + + out[0] = optr[0]; + for(i=1;iN; + float *iptr = t->in; + float *optr = t->out; + + iptr[0] = in[0]; + iptr[1] = 0.0f; + for(i=1;iifft); + + for(i=0;iforward = kiss_fftr_alloc(size,0,NULL,NULL); + table->backward = kiss_fftr_alloc(size,1,NULL,NULL); + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct kiss_config *t = (struct kiss_config *)table; + kiss_fftr_free(t->forward); + kiss_fftr_free(t->backward); + speex_free(table); +} + +#ifdef FIXED_POINT + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int shift; + struct kiss_config *t = (struct kiss_config *)table; + shift = maximize_range(in, in, 32000, t->N); + kiss_fftr2(t->forward, in, out); + renorm_range(in, in, shift, t->N); + renorm_range(out, out, shift, t->N); +} + +#else + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + float scale; + struct kiss_config *t = (struct kiss_config *)table; + scale = 1./t->N; + kiss_fftr2(t->forward, in, out); + for (i=0;iN;i++) + out[i] *= scale; +} +#endif + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct kiss_config *t = (struct kiss_config *)table; + kiss_fftri2(t->backward, in, out); +} + + +#else + +#error No other FFT implemented + +#endif + + +#ifdef FIXED_POINT +/*#include "smallft.h"*/ + + +void spx_fft_float(void *table, float *in, float *out) +{ + int i; +#ifdef USE_SMALLFT + int N = ((struct drft_lookup *)table)->n; +#elif defined(USE_KISS_FFT) + int N = ((struct kiss_config *)table)->N; +#else +#endif +#ifdef VAR_ARRAYS + spx_word16_t _in[N]; + spx_word16_t _out[N]; +#else + spx_word16_t _in[MAX_FFT_SIZE]; + spx_word16_t _out[MAX_FFT_SIZE]; +#endif + for (i=0;iN); + scale = 1./((struct kiss_config *)table)->N; + for (i=0;i<((struct kiss_config *)table)->N;i++) + out[i] = scale*in[i]; + spx_drft_forward(&t, out); + spx_drft_clear(&t); + } +#endif +} + +void spx_ifft_float(void *table, float *in, float *out) +{ + int i; +#ifdef USE_SMALLFT + int N = ((struct drft_lookup *)table)->n; +#elif defined(USE_KISS_FFT) + int N = ((struct kiss_config *)table)->N; +#else +#endif +#ifdef VAR_ARRAYS + spx_word16_t _in[N]; + spx_word16_t _out[N]; +#else + spx_word16_t _in[MAX_FFT_SIZE]; + spx_word16_t _out[MAX_FFT_SIZE]; +#endif + for (i=0;iN); + for (i=0;i<((struct kiss_config *)table)->N;i++) + out[i] = in[i]; + spx_drft_backward(&t, out); + spx_drft_clear(&t); + } +#endif +} + +#else + +void spx_fft_float(void *table, float *in, float *out) +{ + spx_fft(table, in, out); +} +void spx_ifft_float(void *table, float *in, float *out) +{ + spx_ifft(table, in, out); +} + +#endif diff --git a/native/codec/libraries/speex/libspeex/fftwrap.h b/native/codec/libraries/speex/libspeex/fftwrap.h new file mode 100644 index 0000000..dfaf489 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/fftwrap.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2005 Jean-Marc Valin + File: fftwrap.h + + Wrapper for various FFTs + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef FFTWRAP_H +#define FFTWRAP_H + +#include "arch.h" + +/** Compute tables for an FFT */ +void *spx_fft_init(int size); + +/** Destroy tables for an FFT */ +void spx_fft_destroy(void *table); + +/** Forward (real to half-complex) transform */ +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out); + +/** Backward (half-complex to real) transform */ +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out); + +/** Forward (real to half-complex) transform of float data */ +void spx_fft_float(void *table, float *in, float *out); + +/** Backward (half-complex to real) transform of float data */ +void spx_ifft_float(void *table, float *in, float *out); + +#endif diff --git a/native/codec/libraries/speex/libspeex/filters.c b/native/codec/libraries/speex/libspeex/filters.c new file mode 100644 index 0000000..5e1e45e --- /dev/null +++ b/native/codec/libraries/speex/libspeex/filters.c @@ -0,0 +1,836 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: filters.c + Various analysis/synthesis filters + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "filters.h" +#include "stack_alloc.h" +#include "arch.h" +#include "math_approx.h" +#include "ltp.h" +#include + +#ifdef _USE_SSE +#include "filters_sse.h" +#elif defined (ARM4_ASM) || defined(ARM5E_ASM) +#include "filters_arm4.h" +#elif defined (BFIN_ASM) +#include "filters_bfin.h" +#endif + + + +void bw_lpc(spx_word16_t gamma, const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order) +{ + int i; + spx_word16_t tmp=gamma; + for (i=0;i=min_val && vec[i] <= max_val)) + { + if (vec[i] < min_val) + vec[i] = min_val; + else if (vec[i] > max_val) + vec[i] = max_val; + else /* Has to be NaN */ + vec[i] = 0; + } + } +} + +void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem) +{ + int i; +#ifdef FIXED_POINT + const spx_word16_t Pcoef[5][3] = {{16384, -31313, 14991}, {16384, -31569, 15249}, {16384, -31677, 15328}, {16384, -32313, 15947}, {16384, -22446, 6537}}; + const spx_word16_t Zcoef[5][3] = {{15672, -31344, 15672}, {15802, -31601, 15802}, {15847, -31694, 15847}, {16162, -32322, 16162}, {14418, -28836, 14418}}; +#else + const spx_word16_t Pcoef[5][3] = {{1.00000f, -1.91120f, 0.91498f}, {1.00000f, -1.92683f, 0.93071f}, {1.00000f, -1.93338f, 0.93553f}, {1.00000f, -1.97226f, 0.97332f}, {1.00000f, -1.37000f, 0.39900f}}; + const spx_word16_t Zcoef[5][3] = {{0.95654f, -1.91309f, 0.95654f}, {0.96446f, -1.92879f, 0.96446f}, {0.96723f, -1.93445f, 0.96723f}, {0.98645f, -1.97277f, 0.98645f}, {0.88000f, -1.76000f, 0.88000f}}; +#endif + const spx_word16_t *den, *num; + if (filtID>4) + filtID=4; + + den = Pcoef[filtID]; num = Zcoef[filtID]; + /*return;*/ + for (i=0;i SHL32(EXTEND32(SIG_SCALING), 8)) + { + spx_word16_t scale_1; + scale = PSHR32(scale, SIG_SHIFT); + scale_1 = EXTRACT16(PDIV32_16(SHL32(EXTEND32(SIG_SCALING),7),scale)); + for (i=0;i SHR32(EXTEND32(SIG_SCALING), 2)) { + spx_word16_t scale_1; + scale = PSHR32(scale, SIG_SHIFT-5); + scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),3),scale); + for (i=0;i max_val) + max_val = tmp; + } + + sig_shift=0; + while (max_val>16383) + { + sig_shift++; + max_val >>= 1; + } + + for (i=0;i max_val) + max_val = tmp; + } + if (max_val>16383) + { + spx_word32_t sum=0; + for (i=0;i= max_val) + max_val = tmp; + } + + sig_shift=0; + while (max_val>max_scale) + { + sig_shift++; + max_val >>= 1; + } + + for (i=0;i>1; + for (i=0;i>1; + N2 = N>>1; + ALLOC(xx1, M2+N2, spx_word16_t); + ALLOC(xx2, M2+N2, spx_word16_t); + + for (i = 0; i < N2; i++) + xx1[i] = x1[N2-1-i]; + for (i = 0; i < M2; i++) + xx1[N2+i] = mem1[2*i+1]; + for (i = 0; i < N2; i++) + xx2[i] = x2[N2-1-i]; + for (i = 0; i < M2; i++) + xx2[N2+i] = mem2[2*i+1]; + + for (i = 0; i < N2; i += 2) { + spx_sig_t y0, y1, y2, y3; + spx_word16_t x10, x20; + + y0 = y1 = y2 = y3 = 0; + x10 = xx1[N2-2-i]; + x20 = xx2[N2-2-i]; + + for (j = 0; j < M2; j += 2) { + spx_word16_t x11, x21; + spx_word16_t a0, a1; + + a0 = a[2*j]; + a1 = a[2*j+1]; + x11 = xx1[N2-1+j-i]; + x21 = xx2[N2-1+j-i]; + +#ifdef FIXED_POINT + /* We multiply twice by the same coef to avoid overflows */ + y0 = MAC16_16(MAC16_16(y0, a0, x11), NEG16(a0), x21); + y1 = MAC16_16(MAC16_16(y1, a1, x11), a1, x21); + y2 = MAC16_16(MAC16_16(y2, a0, x10), NEG16(a0), x20); + y3 = MAC16_16(MAC16_16(y3, a1, x10), a1, x20); +#else + y0 = ADD32(y0,MULT16_16(a0, x11-x21)); + y1 = ADD32(y1,MULT16_16(a1, x11+x21)); + y2 = ADD32(y2,MULT16_16(a0, x10-x20)); + y3 = ADD32(y3,MULT16_16(a1, x10+x20)); +#endif + a0 = a[2*j+2]; + a1 = a[2*j+3]; + x10 = xx1[N2+j-i]; + x20 = xx2[N2+j-i]; + +#ifdef FIXED_POINT + /* We multiply twice by the same coef to avoid overflows */ + y0 = MAC16_16(MAC16_16(y0, a0, x10), NEG16(a0), x20); + y1 = MAC16_16(MAC16_16(y1, a1, x10), a1, x20); + y2 = MAC16_16(MAC16_16(y2, a0, x11), NEG16(a0), x21); + y3 = MAC16_16(MAC16_16(y3, a1, x11), a1, x21); +#else + y0 = ADD32(y0,MULT16_16(a0, x10-x20)); + y1 = ADD32(y1,MULT16_16(a1, x10+x20)); + y2 = ADD32(y2,MULT16_16(a0, x11-x21)); + y3 = ADD32(y3,MULT16_16(a1, x11+x21)); +#endif + } +#ifdef FIXED_POINT + y[2*i] = EXTRACT16(SATURATE32(PSHR32(y0,15),32767)); + y[2*i+1] = EXTRACT16(SATURATE32(PSHR32(y1,15),32767)); + y[2*i+2] = EXTRACT16(SATURATE32(PSHR32(y2,15),32767)); + y[2*i+3] = EXTRACT16(SATURATE32(PSHR32(y3,15),32767)); +#else + /* Normalize up explicitly if we're in float */ + y[2*i] = 2.f*y0; + y[2*i+1] = 2.f*y1; + y[2*i+2] = 2.f*y2; + y[2*i+3] = 2.f*y3; +#endif + } + + for (i = 0; i < M2; i++) + mem1[2*i+1] = xx1[i]; + for (i = 0; i < M2; i++) + mem2[2*i+1] = xx2[i]; +} +#endif /* DISABLE_WIDEBAND */ + + +#ifndef DISABLE_DECODER + +#ifdef FIXED_POINT +#if 0 +const spx_word16_t shift_filt[3][7] = {{-33, 1043, -4551, 19959, 19959, -4551, 1043}, + {-98, 1133, -4425, 29179, 8895, -2328, 444}, + {444, -2328, 8895, 29179, -4425, 1133, -98}}; +#else +const spx_word16_t shift_filt[3][7] = {{-390, 1540, -4993, 20123, 20123, -4993, 1540}, + {-1064, 2817, -6694, 31589, 6837, -990, -209}, + {-209, -990, 6837, 31589, -6694, 2817, -1064}}; +#endif +#else +#if 0 +const float shift_filt[3][7] = {{-9.9369e-04, 3.1831e-02, -1.3889e-01, 6.0910e-01, 6.0910e-01, -1.3889e-01, 3.1831e-02}, + {-0.0029937, 0.0345613, -0.1350474, 0.8904793, 0.2714479, -0.0710304, 0.0135403}, + {0.0135403, -0.0710304, 0.2714479, 0.8904793, -0.1350474, 0.0345613, -0.0029937}}; +#else +const float shift_filt[3][7] = {{-0.011915f, 0.046995f, -0.152373f, 0.614108f, 0.614108f, -0.152373f, 0.046995f}, + {-0.0324855f, 0.0859768f, -0.2042986f, 0.9640297f, 0.2086420f, -0.0302054f, -0.0063646f}, + {-0.0063646f, -0.0302054f, 0.2086420f, 0.9640297f, -0.2042986f, 0.0859768f, -0.0324855f}}; +#endif +#endif + +static int interp_pitch( +spx_word16_t *exc, /*decoded excitation*/ +spx_word16_t *interp, /*decoded excitation*/ +int pitch, /*pitch period*/ +int len +) +{ + int i,j,k; + spx_word32_t corr[4][7]; + spx_word32_t maxcorr; + int maxi, maxj; + for (i=0;i<7;i++) + { + corr[0][i] = inner_prod(exc, exc-pitch-3+i, len); + } + for (i=0;i<3;i++) + { + for (j=0;j<7;j++) + { + int i1, i2; + spx_word32_t tmp=0; + i1 = 3-j; + if (i1<0) + i1 = 0; + i2 = 10-j; + if (i2>7) + i2 = 7; + for (k=i1;k maxcorr) + { + maxcorr = corr[i][j]; + maxi=i; + maxj=j; + } + } + } + for (i=0;i0) + { + for (k=0;k<7;k++) + { + tmp += MULT16_16(exc[i-(pitch-maxj+3)+k-3],shift_filt[maxi-1][k]); + } + } else { + tmp = SHL32(exc[i-(pitch-maxj+3)],15); + } + interp[i] = PSHR32(tmp,15); + } + return pitch-maxj+3; +} + +void multicomb( +spx_word16_t *exc, /*decoded excitation*/ +spx_word16_t *new_exc, /*enhanced excitation*/ +spx_coef_t *ak, /*LPC filter coefs*/ +int p, /*LPC order*/ +int nsf, /*sub-frame size*/ +int pitch, /*pitch period*/ +int max_pitch, +spx_word16_t comb_gain, /*gain of comb filter*/ +char *stack +) +{ + int i; + VARDECL(spx_word16_t *iexc); + spx_word16_t old_ener, new_ener; + int corr_pitch; + + spx_word16_t iexc0_mag, iexc1_mag, exc_mag; + spx_word32_t corr0, corr1; + spx_word16_t gain0, gain1; + spx_word16_t pgain1, pgain2; + spx_word16_t c1, c2; + spx_word16_t g1, g2; + spx_word16_t ngain; + spx_word16_t gg1, gg2; +#ifdef FIXED_POINT + int scaledown=0; +#endif +#if 0 /* Set to 1 to enable full pitch search */ + int nol_pitch[6]; + spx_word16_t nol_pitch_coef[6]; + spx_word16_t ol_pitch_coef; + open_loop_nbest_pitch(exc, 20, 120, nsf, + nol_pitch, nol_pitch_coef, 6, stack); + corr_pitch=nol_pitch[0]; + ol_pitch_coef = nol_pitch_coef[0]; + /*Try to remove pitch multiples*/ + for (i=1;i<6;i++) + { +#ifdef FIXED_POINT + if ((nol_pitch_coef[i]>MULT16_16_Q15(nol_pitch_coef[0],19661)) && +#else + if ((nol_pitch_coef[i]>.6*nol_pitch_coef[0]) && +#endif + (ABS(2*nol_pitch[i]-corr_pitch)<=2 || ABS(3*nol_pitch[i]-corr_pitch)<=3 || + ABS(4*nol_pitch[i]-corr_pitch)<=4 || ABS(5*nol_pitch[i]-corr_pitch)<=5)) + { + corr_pitch = nol_pitch[i]; + } + } +#else + corr_pitch = pitch; +#endif + + ALLOC(iexc, 2*nsf, spx_word16_t); + + interp_pitch(exc, iexc, corr_pitch, 80); + if (corr_pitch>max_pitch) + interp_pitch(exc, iexc+nsf, 2*corr_pitch, 80); + else + interp_pitch(exc, iexc+nsf, -corr_pitch, 80); + +#ifdef FIXED_POINT + for (i=0;i16383) + { + scaledown = 1; + break; + } + } + if (scaledown) + { + for (i=0;i MULT16_16(iexc0_mag,exc_mag)) + pgain1 = QCONST16(1., 14); + else + pgain1 = PDIV32_16(SHL32(PDIV32(corr0, exc_mag),14),iexc0_mag); + if (corr1 > MULT16_16(iexc1_mag,exc_mag)) + pgain2 = QCONST16(1., 14); + else + pgain2 = PDIV32_16(SHL32(PDIV32(corr1, exc_mag),14),iexc1_mag); + gg1 = PDIV32_16(SHL32(EXTEND32(exc_mag),8), iexc0_mag); + gg2 = PDIV32_16(SHL32(EXTEND32(exc_mag),8), iexc1_mag); + if (comb_gain>0) + { +#ifdef FIXED_POINT + c1 = (MULT16_16_Q15(QCONST16(.4,15),comb_gain)+QCONST16(.07,15)); + c2 = QCONST16(.5,15)+MULT16_16_Q14(QCONST16(1.72,14),(c1-QCONST16(.07,15))); +#else + c1 = .4*comb_gain+.07; + c2 = .5+1.72*(c1-.07); +#endif + } else + { + c1=c2=0; + } +#ifdef FIXED_POINT + g1 = 32767 - MULT16_16_Q13(MULT16_16_Q15(c2, pgain1),pgain1); + g2 = 32767 - MULT16_16_Q13(MULT16_16_Q15(c2, pgain2),pgain2); +#else + g1 = 1-c2*pgain1*pgain1; + g2 = 1-c2*pgain2*pgain2; +#endif + if (g1max_pitch) + { + gain0 = MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q14(g1,gg1)); + gain1 = MULT16_16_Q15(QCONST16(.3,15),MULT16_16_Q14(g2,gg2)); + } else { + gain0 = MULT16_16_Q15(QCONST16(.6,15),MULT16_16_Q14(g1,gg1)); + gain1 = MULT16_16_Q15(QCONST16(.6,15),MULT16_16_Q14(g2,gg2)); + } + for (i=0;i new_ener) + old_ener = new_ener; + ngain = PDIV32_16(SHL32(EXTEND32(old_ener),14),new_ener); + + for (i=0;imax_scale) + { + sig_shift++; + max_val >>= 1; + } + + __asm__ __volatile__ ( + ".normalize16loop%=: \n" + + "\tldr %4, [%0], #4 \n" + "\tldr %5, [%0], #4 \n" + "\tmov %4, %4, asr %3 \n" + "\tstrh %4, [%1], #2 \n" + "\tldr %4, [%0], #4 \n" + "\tmov %5, %5, asr %3 \n" + "\tstrh %5, [%1], #2 \n" + "\tldr %5, [%0], #4 \n" + "\tmov %4, %4, asr %3 \n" + "\tstrh %4, [%1], #2 \n" + "\tsubs %2, %2, #1 \n" + "\tmov %5, %5, asr %3 \n" + "\tstrh %5, [%1], #2 \n" + + "\tbgt .normalize16loop%=\n" + : "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4), + "=r" (dead5), "=r" (dead6) + : "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift) + : "cc", "memory"); + return sig_shift; +} + diff --git a/native/codec/libraries/speex/libspeex/filters_bfin.h b/native/codec/libraries/speex/libspeex/filters_bfin.h new file mode 100644 index 0000000..ccd57b9 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/filters_bfin.h @@ -0,0 +1,520 @@ +/* Copyright (C) 2005 Analog Devices */ +/** + @file filters_bfin.h + @brief Various analysis/synthesis filters (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "bfin.h" + +#define OVERRIDE_NORMALIZE16 +int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int len) +{ + spx_sig_t max_val=1; + int sig_shift; + __asm__ + ( + "%0 = 0;\n\t" + "I0 = %1;\n\t" + "L0 = 0;\n\t" + "R1 = [I0++];\n\t" + "LOOP norm_max%= LC0 = %2;\n\t" + "LOOP_BEGIN norm_max%=;\n\t" + "R2 = ABS R1 || R1 = [I0++];\n\t" + "%0 = MAX(%0, R2);\n\t" + "LOOP_END norm_max%=;\n\t" + : "=&d" (max_val) + : "a" (x), "a" (len) + : "R1", "R2", "ASTAT" BFIN_HWLOOP0_REGS + ); + + sig_shift=0; + while (max_val>max_scale) + { + sig_shift++; + max_val >>= 1; + } + + __asm__ __volatile__ + ( + "I0 = %0;\n\t" + "L0 = 0;\n\t" + "P1 = %1;\n\t" + "R0 = [I0++];\n\t" + "LOOP norm_shift%= LC0 = %3;\n\t" + "LOOP_BEGIN norm_shift%=;\n\t" + "R1 = ASHIFT R0 by %2.L || R0 = [I0++];\n\t" + "W[P1++] = R1;\n\t" + "LOOP_END norm_shift%=;\n\t" + "R1 = ASHIFT R0 by %2.L;\n\t" + "W[P1++] = R1;\n\t" + : : "a" (x), "a" (y), "d" (-sig_shift), "a" (len-1) + : "I0", "L0", "P1", "R0", "R1", "memory", "ASTAT" BFIN_HWLOOP0_REGS + ); + return sig_shift; +} + + + +#define OVERRIDE_FILTER_MEM16 +void filter_mem16(const spx_word16_t *_x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *_y, int N, int ord, spx_mem_t *mem, char *stack) +{ + VARDECL(spx_word32_t *xy2); + VARDECL(spx_word32_t *numden_a); + spx_word32_t *xy; + spx_word16_t *numden; + int i; + + ALLOC(xy2, (N+1), spx_word32_t); + ALLOC(numden_a, (2*ord+2), spx_word32_t); + xy = xy2+1; + numden = (spx_word16_t*) numden_a; + + for (i=0;i>> 13;\n\t" + "W[%0] = R3.L;\n\t" + "R0 <<= 1;\n\t" + "R1 = R1 + R0;\n\t" + "R1 >>>= 13;\n\t" + "W[%1] = R1.L;\n\t" + "LOOP_END samples%=;\n\t" + : "=a" (ytmp2), "=a" (y) + : "a" (awk2), "a" (ak), "d" (ord), "m" (N), "0" (ytmp2), "1" (y) + : "A0", "A1", "R0", "R1", "R2", "R3", "I0", "I1", "I2", "I3", "L0", "L1", "L2", "L3", + "ASTAT" BFIN_HWLOOP0_REGS BFIN_HWLOOP1_REGS + ); +} + + + +#if 0 /* Equivalent C function for filter_mem2 and compute_impulse_response */ +#define min(a,b) ((a)<(b) ? (a):(b)) + +void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack) +{ + int i,j; + VARDECL(spx_word16_t *ytmp); + ALLOC(ytmp, N, spx_word16_t); + + y[0] = LPC_SCALING; + for (i=0;i + +void filter_mem16_10(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem) +{ + __m128 num[3], den[3], mem[3]; + + int i; + + /* Copy numerator, denominator and memory to aligned xmm */ + for (i=0;i<2;i++) + { + mem[i] = _mm_loadu_ps(_mem+4*i); + num[i] = _mm_loadu_ps(_num+4*i); + den[i] = _mm_loadu_ps(_den+4*i); + } + mem[2] = _mm_setr_ps(_mem[8], _mem[9], 0, 0); + num[2] = _mm_setr_ps(_num[8], _num[9], 0, 0); + den[2] = _mm_setr_ps(_den[8], _den[9], 0, 0); + + for (i=0;i>1; + __asm__ ( + "P0 = 15;\n\t" + "R0 = %1;\n\t" + "R1 = %2;\n\t" + //"R0 = R0 + R1;\n\t" + "R0 <<= 1;\n\t" + "DIVS (R0, R1);\n\t" + "LOOP divide%= LC0 = P0;\n\t" + "LOOP_BEGIN divide%=;\n\t" + "DIVQ (R0, R1);\n\t" + "LOOP_END divide%=;\n\t" + "R0 = R0.L;\n\t" + "%0 = R0;\n\t" + : "=m" (res) + : "m" (a), "m" (bb) + : "P0", "R0", "R1", "ASTAT" BFIN_HWLOOP0_REGS); + return res; +} + +#undef DIV32_16 +static inline spx_word16_t DIV32_16(spx_word32_t a, spx_word16_t b) +{ + spx_word32_t res, bb; + bb = b; + /* Make the roundinf consistent with the C version + (do we need to do that?)*/ + if (a<0) + a += (b-1); + __asm__ ( + "P0 = 15;\n\t" + "R0 = %1;\n\t" + "R1 = %2;\n\t" + "R0 <<= 1;\n\t" + "DIVS (R0, R1);\n\t" + "LOOP divide%= LC0 = P0;\n\t" + "LOOP_BEGIN divide%=;\n\t" + "DIVQ (R0, R1);\n\t" + "LOOP_END divide%=;\n\t" + "R0 = R0.L;\n\t" + "%0 = R0;\n\t" + : "=m" (res) + : "m" (a), "m" (bb) + : "P0", "R0", "R1", "ASTAT" BFIN_HWLOOP0_REGS); + return res; +} + +#undef MAX16 +static inline spx_word16_t MAX16(spx_word16_t a, spx_word16_t b) +{ + spx_word32_t res; + __asm__ ( + "%1 = %1.L (X);\n\t" + "%2 = %2.L (X);\n\t" + "%0 = MAX(%1,%2);" + : "=d" (res) + : "%d" (a), "d" (b) + : "ASTAT" + ); + return res; +} + +#undef MULT16_32_Q15 +static inline spx_word32_t MULT16_32_Q15(spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H) ;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b) + : "A1", "ASTAT" + ); + return res; +} + +#undef MAC16_32_Q15 +static inline spx_word32_t MAC16_32_Q15(spx_word32_t c, spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H);\n\t" + "%0 = %0 + %4;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b), "d" (c) + : "A1", "ASTAT" + ); + return res; +} + +#undef MULT16_32_Q14 +static inline spx_word32_t MULT16_32_Q14(spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "%2 <<= 1;\n\t" + "A1 = %1.L*%2.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %1.L*%2.H);\n\t" + : "=W" (res), "=d" (a), "=d" (b) + : "1" (a), "2" (b) + : "A1", "ASTAT" + ); + return res; +} + +#undef MAC16_32_Q14 +static inline spx_word32_t MAC16_32_Q14(spx_word32_t c, spx_word16_t a, spx_word32_t b) +{ + spx_word32_t res; + __asm__ + ( + "%1 <<= 1;\n\t" + "A1 = %2.L*%1.L (M);\n\t" + "A1 = A1 >>> 15;\n\t" + "%0 = (A1 += %2.L*%1.H);\n\t" + "%0 = %0 + %4;\n\t" + : "=&W" (res), "=&d" (b) + : "d" (a), "1" (b), "d" (c) + : "A1", "ASTAT" + ); + return res; +} + +#endif diff --git a/native/codec/libraries/speex/libspeex/fixed_debug.h b/native/codec/libraries/speex/libspeex/fixed_debug.h new file mode 100644 index 0000000..54f3866 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/fixed_debug.h @@ -0,0 +1,487 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include + +extern long long spx_mips; +#define MIPS_INC spx_mips++, + +#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) +#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) + + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) + +static inline short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); + } + res = -x; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); + spx_mips++; + return res; +} +static inline int NEG32(long long x) +{ + long long res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); + } + res = -x; + if (!VERIFY_INT(res)) + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); + spx_mips++; + return res; +} + +#define EXTRACT16(x) _EXTRACT16(x, __FILE__, __LINE__) +static inline short _EXTRACT16(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + spx_mips++; + return res; +} + +#define EXTEND32(x) _EXTEND32(x, __FILE__, __LINE__) +static inline int _EXTEND32(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); + } + res = x; + spx_mips++; + return res; +} + +#define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) +static inline short _SHR16(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); + spx_mips++; + return res; +} +#define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) +static inline short _SHL16(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); + } + spx_mips++; + return res; +} +static inline int SHL32(long long a, int shift) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift); + } + res = a<>1))),shift)) +#define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +//#define SHR(a,shift) ((a) >> (shift)) +//#define SHL(a,shift) ((a) << (shift)) + +#define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) +static inline short _ADD16(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); + } + spx_mips++; + return res; +} + +#define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) +static inline short _SUB16(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = a-b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); + spx_mips++; + return res; +} + +#define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) +static inline int _ADD32(long long a, long long b, char *file, int line) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); + } + spx_mips++; + return res; +} + +static inline int SUB32(long long a, long long b) +{ + long long res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d\n", (int)a, (int)b); + } + res = a-b; + if (!VERIFY_INT(res)) + fprintf (stderr, "SUB32: output is not int: %d\n", (int)res); + spx_mips++; + return res; +} + +#define ADD64(a,b) (MIPS_INC(a)+(b)) + +/* result fits in 16 bits */ +static inline short MULT16_16_16(int a, int b) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b); + } + res = a*b; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res); + spx_mips++; + return res; +} + +#define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) +static inline int _MULT16_16(int a, int b, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); + } + res = ((long long)a)*b; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line); + spx_mips++; + return res; +} + +#define MAC16_16(c,a,b) (spx_mips--,ADD32((c),MULT16_16((a),(b)))) +#define MAC16_16_Q11(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11))))) +#define MAC16_16_Q13(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13))))) +#define MAC16_16_P13(c,a,b) (EXTRACT16(ADD32((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13)))) + + +#define MULT16_32_QX(a, b, Q) _MULT16_32_QX(a, b, Q, __FILE__, __LINE__) +static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + } + if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + res = (((long long)a)*(long long)b) >> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); + spx_mips+=5; + return res; +} + +static inline int MULT16_32_PX(int a, long long b, int Q) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); + } + if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); + res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<>1))>> Q; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); + spx_mips+=5; + return res; +} + + +#define MULT16_32_Q11(a,b) MULT16_32_QX(a,b,11) +#define MAC16_32_Q11(c,a,b) ADD32((c),MULT16_32_Q11((a),(b))) +#define MULT16_32_Q12(a,b) MULT16_32_QX(a,b,12) +#define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13) +#define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14) +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MULT16_32_P15(a,b) MULT16_32_PX(a,b,15) +#define MAC16_32_Q15(c,a,b) ADD32((c),MULT16_32_Q15((a),(b))) + +static inline int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + return a; +} + +static inline int MULT16_16_Q11_32(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); + spx_mips+=3; + return res; +} +static inline short MULT16_16_Q15(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res); + } + spx_mips+=3; + return res; +} + +static inline short MULT16_16_P13(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 13; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} +static inline short MULT16_16_P14(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 14; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} +static inline short MULT16_16_P15(int a, int b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); + } + res = ((long long)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); + res >>= 15; + if (!VERIFY_SHORT(res)) + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); + spx_mips+=4; + return res; +} + +#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) + +static inline int _DIV32_16(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; + } + spx_mips+=20; + return res; +} + +#define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) +static inline int _DIV32(long long a, long long b, char *file, int line) +{ + long long res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); + } + res = a/b; + if (!VERIFY_INT(res)) + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); + spx_mips+=36; + return res; +} +#define PDIV32(a,b) DIV32(ADD32((a),(b)>>1),b) +#define PDIV32_16(a,b) DIV32_16(ADD32((a),(b)>>1),b) + +#endif diff --git a/native/codec/libraries/speex/libspeex/fixed_generic.h b/native/codec/libraries/speex/libspeex/fixed_generic.h new file mode 100644 index 0000000..3fb096e --- /dev/null +++ b/native/codec/libraries/speex/libspeex/fixed_generic.h @@ -0,0 +1,106 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) +#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) ((spx_word16_t)(x)) +#define EXTEND32(x) ((spx_word32_t)(x)) +#define SHR16(a,shift) ((a) >> (shift)) +#define SHL16(a,shift) ((a) << (shift)) +#define SHR32(a,shift) ((a) >> (shift)) +#define SHL32(a,shift) ((a) << (shift)) +#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) ((spx_word32_t)(a) << (shift)) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + + +#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b))) +#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b)) +#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b)) +#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b)) + + +/* result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b)))) + +/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */ +#define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b))) + +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) +#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) +#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14)) + +#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) +#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) + +#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + + +#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) +#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13))) +#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15)) + +#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b)))) +#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b)))) +#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b))) +#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b))) + +#endif diff --git a/native/codec/libraries/speex/libspeex/gain_table.c b/native/codec/libraries/speex/libspeex/gain_table.c new file mode 100644 index 0000000..63dc6e7 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/gain_table.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: gain_table.c + Codebook for 3-tap pitch prediction gain (128 entries) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char gain_cdbk_nb[512] = { +-32, -32, -32, 0, +-28, -67, -5, 33, +-42, -6, -32, 18, +-57, -10, -54, 35, +-16, 27, -41, 42, +19, -19, -40, 36, +-45, 24, -21, 40, +-8, -14, -18, 28, +1, 14, -58, 53, +-18, -88, -39, 39, +-38, 21, -18, 37, +-19, 20, -43, 38, +10, 17, -48, 54, +-52, -58, -13, 33, +-44, -1, -11, 32, +-12, -11, -34, 22, +14, 0, -46, 46, +-37, -35, -34, 5, +-25, 44, -30, 43, +6, -4, -63, 49, +-31, 43, -41, 43, +-23, 30, -43, 41, +-43, 26, -14, 44, +-33, 1, -13, 27, +-13, 18, -37, 37, +-46, -73, -45, 34, +-36, 24, -25, 34, +-36, -11, -20, 19, +-25, 12, -18, 33, +-36, -69, -59, 34, +-45, 6, 8, 46, +-22, -14, -24, 18, +-1, 13, -44, 44, +-39, -48, -26, 15, +-32, 31, -37, 34, +-33, 15, -46, 31, +-24, 30, -36, 37, +-41, 31, -23, 41, +-50, 22, -4, 50, +-22, 2, -21, 28, +-17, 30, -34, 40, +-7, -60, -28, 29, +-38, 42, -28, 42, +-44, -11, 21, 43, +-16, 8, -44, 34, +-39, -55, -43, 21, +-11, -35, 26, 41, +-9, 0, -34, 29, +-8, 121, -81, 113, +7, -16, -22, 33, +-37, 33, -31, 36, +-27, -7, -36, 17, +-34, 70, -57, 65, +-37, -11, -48, 21, +-40, 17, -1, 44, +-33, 6, -6, 33, +-9, 0, -20, 34, +-21, 69, -33, 57, +-29, 33, -31, 35, +-55, 12, -1, 49, +-33, 27, -22, 35, +-50, -33, -47, 17, +-50, 54, 51, 94, +-1, -5, -44, 35, +-4, 22, -40, 45, +-39, -66, -25, 24, +-33, 1, -26, 20, +-24, -23, -25, 12, +-11, 21, -45, 44, +-25, -45, -19, 17, +-43, 105, -16, 82, +5, -21, 1, 41, +-16, 11, -33, 30, +-13, -99, -4, 57, +-37, 33, -15, 44, +-25, 37, -63, 54, +-36, 24, -31, 31, +-53, -56, -38, 26, +-41, -4, 4, 37, +-33, 13, -30, 24, +49, 52, -94, 114, +-5, -30, -15, 23, +1, 38, -40, 56, +-23, 12, -36, 29, +-17, 40, -47, 51, +-37, -41, -39, 11, +-49, 34, 0, 58, +-18, -7, -4, 34, +-16, 17, -27, 35, +30, 5, -62, 65, +4, 48, -68, 76, +-43, 11, -11, 38, +-18, 19, -15, 41, +-23, -62, -39, 23, +-42, 10, -2, 41, +-21, -13, -13, 25, +-9, 13, -47, 42, +-23, -62, -24, 24, +-44, 60, -21, 58, +-18, -3, -52, 32, +-22, 22, -36, 34, +-75, 57, 16, 90, +-19, 3, 10, 45, +-29, 23, -38, 32, +-5, -62, -51, 38, +-51, 40, -18, 53, +-42, 13, -24, 32, +-34, 14, -20, 30, +-56, -75, -26, 37, +-26, 32, 15, 59, +-26, 17, -29, 29, +-7, 28, -52, 53, +-12, -30, 5, 30, +-5, -48, -5, 35, +2, 2, -43, 40, +21, 16, 16, 75, +-25, -45, -32, 10, +-43, 18, -10, 42, +9, 0, -1, 52, +-1, 7, -30, 36, +19, -48, -4, 48, +-28, 25, -29, 32, +-22, 0, -31, 22, +-32, 17, -10, 36, +-64, -41, -62, 36, +-52, 15, 16, 58, +-30, -22, -32, 6, +-7, 9, -38, 36}; diff --git a/native/codec/libraries/speex/libspeex/gain_table_lbr.c b/native/codec/libraries/speex/libspeex/gain_table_lbr.c new file mode 100644 index 0000000..be464f3 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/gain_table_lbr.c @@ -0,0 +1,64 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: gain_table_lbr.c + Codebook for 3-tap pitch prediction gain (32 entries) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char gain_cdbk_lbr[128] = { +-32, -32, -32, 0, +-31, -58, -16, 22, +-41, -24, -43, 14, +-56, -22, -55, 29, +-13, 33, -41, 47, +-4, -39, -9, 29, +-41, 15, -12, 38, +-8, -15, -12, 31, +1, 2, -44, 40, +-22, -66, -42, 27, +-38, 28, -23, 38, +-21, 14, -37, 31, +0, 21, -50, 52, +-53, -71, -27, 33, +-37, -1, -19, 25, +-19, -5, -28, 22, +6, 65, -44, 74, +-33, -48, -33, 9, +-40, 57, -14, 58, +-17, 4, -45, 32, +-31, 38, -33, 36, +-23, 28, -40, 39, +-43, 29, -12, 46, +-34, 13, -23, 28, +-16, 15, -27, 34, +-14, -82, -15, 43, +-31, 25, -32, 29, +-21, 5, -5, 38, +-47, -63, -51, 33, +-46, 12, 3, 47, +-28, -17, -29, 11, +-10, 14, -40, 38}; diff --git a/native/codec/libraries/speex/libspeex/hexc_10_32_table.c b/native/codec/libraries/speex/libspeex/hexc_10_32_table.c new file mode 100644 index 0000000..1c7f285 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/hexc_10_32_table.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: hexc_10_32_table.c + Codebook for high-band excitation in SB-CELP mode (4000 bps) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char hexc_10_32_table[320] = { +-3, -2, -1, 0, -4, 5, 35, -40, -9, 13, +-44, 5, -27, -1, -7, 6, -11, 7, -8, 7, +19, -14, 15, -4, 9, -10, 10, -8, 10, -9, +-1, 1, 0, 0, 2, 5, -18, 22, -53, 50, +1, -23, 50, -36, 15, 3, -13, 14, -10, 6, +1, 5, -3, 4, -2, 5, -32, 25, 5, -2, +-1, -4, 1, 11, -29, 26, -6, -15, 30, -18, +0, 15, -17, 40, -41, 3, 9, -2, -2, 3, +-3, -1, -5, 2, 21, -6, -16, -21, 23, 2, +60, 15, 16, -16, -9, 14, 9, -1, 7, -9, +0, 1, 1, 0, -1, -6, 17, -28, 54, -45, +-1, 1, -1, -6, -6, 2, 11, 26, -29, -2, +46, -21, 34, 12, -23, 32, -23, 16, -10, 3, +66, 19, -20, 24, 7, 11, -3, 0, -3, -1, +-50, -46, 2, -18, -3, 4, -1, -2, 3, -3, +-19, 41, -36, 9, 11, -24, 21, -16, 9, -3, +-25, -3, 10, 18, -9, -2, -5, -1, -5, 6, +-4, -3, 2, -26, 21, -19, 35, -15, 7, -13, +17, -19, 39, -43, 48, -31, 16, -9, 7, -2, +-5, 3, -4, 9, -19, 27, -55, 63, -35, 10, +26, -44, -2, 9, 4, 1, -6, 8, -9, 5, +-8, -1, -3, -16, 45, -42, 5, 15, -16, 10, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +-16, 24, -55, 47, -38, 27, -19, 7, -3, 1, +16, 27, 20, -19, 18, 5, -7, 1, -5, 2, +-6, 8, -22, 0, -3, -3, 8, -1, 7, -8, +1, -3, 5, 0, 17, -48, 58, -52, 29, -7, +-2, 3, -10, 6, -26, 58, -31, 1, -6, 3, +93, -29, 39, 3, 17, 5, 6, -1, -1, -1, +27, 13, 10, 19, -7, -34, 12, 10, -4, 9, +-76, 9, 8, -28, -2, -11, 2, -1, 3, 1, +-83, 38, -39, 4, -16, -6, -2, -5, 5, -2, +}; diff --git a/native/codec/libraries/speex/libspeex/hexc_table.c b/native/codec/libraries/speex/libspeex/hexc_table.c new file mode 100644 index 0000000..6e36069 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/hexc_table.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: hexc_table.c + Codebook for high-band excitation in SB-CELP mode (8000 bps with sign) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char hexc_table[1024] = { +-24, 21, -20, 5, -5, -7, 14, -10, +2, -27, 16, -20, 0, -32, 26, 19, +8, -11, -41, 31, 28, -27, -32, 34, +42, 34, -17, 22, -10, 13, -29, 18, +-12, -26, -24, 11, 22, 5, -5, -5, +54, -68, -43, 57, -25, 24, 4, 4, +26, -8, -12, -17, 54, 30, -45, 1, +10, -15, 18, -41, 11, 68, -67, 37, +-16, -24, -16, 38, -22, 6, -29, 30, +66, -27, 5, 7, -16, 13, 2, -12, +-7, -3, -20, 36, 4, -28, 9, 3, +32, 48, 26, 39, 3, 0, 7, -21, +-13, 5, -82, -7, 73, -20, 34, -9, +-5, 1, -1, 10, -5, -10, -1, 9, +1, -9, 10, 0, -14, 11, -1, -2, +-1, 11, 20, 96, -81, -22, -12, -9, +-58, 9, 24, -30, 26, -35, 27, -12, +13, -18, 56, -59, 15, -7, 23, -15, +-1, 6, -25, 14, -22, -20, 47, -11, +16, 2, 38, -23, -19, -30, -9, 40, +-11, 5, 4, -6, 8, 26, -21, -11, +127, 4, 1, 6, -9, 2, -7, -2, +-3, 7, -5, 10, -19, 7, -106, 91, +-3, 9, -4, 21, -8, 26, -80, 8, +1, -2, -10, -17, -17, -27, 32, 71, +6, -29, 11, -23, 54, -38, 29, -22, +39, 87, -31, -12, -20, 3, -2, -2, +2, 20, 0, -1, -35, 27, 9, -6, +-12, 3, -12, -6, 13, 1, 14, -22, +-59, -15, -17, -25, 13, -7, 7, 3, +0, 1, -7, 6, -3, 61, -37, -23, +-23, -29, 38, -31, 27, 1, -8, 2, +-27, 23, -26, 36, -34, 5, 24, -24, +-6, 7, 3, -59, 78, -62, 44, -16, +1, 6, 0, 17, 8, 45, 0, -110, +6, 14, -2, 32, -77, -56, 62, -3, +3, -13, 4, -16, 102, -15, -36, -1, +9, -113, 6, 23, 0, 9, 9, 5, +-8, -1, -14, 5, -12, 121, -53, -27, +-8, -9, 22, -13, 3, 2, -3, 1, +-2, -71, 95, 38, -19, 15, -16, -5, +71, 10, 2, -32, -13, -5, 15, -1, +-2, -14, -85, 30, 29, 6, 3, 2, +0, 0, 0, 0, 0, 0, 0, 0, +2, -65, -56, -9, 18, 18, 23, -14, +-2, 0, 12, -29, 26, -12, 1, 2, +-12, -64, 90, -6, 4, 1, 5, -5, +-110, -3, -31, 22, -29, 9, 0, 8, +-40, -5, 21, -5, -5, 13, 10, -18, +40, 1, 35, -20, 30, -28, 11, -6, +19, 7, 14, 18, -64, 9, -6, 16, +51, 68, 8, 16, 12, -8, 0, -9, +20, -22, 25, 7, -4, -13, 41, -35, +93, -18, -54, 11, -1, 1, -9, 4, +-66, 66, -31, 20, -22, 25, -23, 11, +10, 9, 19, 15, 11, -5, -31, -10, +-23, -28, -6, -6, -3, -4, 5, 3, +-28, 22, -11, -42, 25, -25, -16, 41, +34, 47, -6, 2, 42, -19, -22, 5, +-39, 32, 6, -35, 22, 17, -30, 8, +-26, -11, -11, 3, -12, 33, 33, -37, +21, -1, 6, -4, 3, 0, -5, 5, +12, -12, 57, 27, -61, -3, 20, -17, +2, 0, 4, 0, -2, -33, -58, 81, +-23, 39, -10, -5, 2, 6, -7, 5, +4, -3, -2, -13, -23, -72, 107, 15, +-5, 0, -7, -3, -6, 5, -4, 15, +47, 12, -31, 25, -16, 8, 22, -25, +-62, -56, -18, 14, 28, 12, 2, -11, +74, -66, 41, -20, -7, 16, -20, 16, +-8, 0, -16, 4, -19, 92, 12, -59, +-14, -39, 49, -25, -16, 23, -27, 19, +-3, -33, 19, 85, -29, 6, -7, -10, +16, -7, -12, 1, -6, 2, 4, -2, +64, 10, -25, 41, -2, -31, 15, 0, +110, 50, 69, 35, 28, 19, -10, 2, +-43, -49, -56, -15, -16, 10, 3, 12, +-1, -8, 1, 26, -12, -1, 7, -11, +-27, 41, 25, 1, -11, -18, 22, -7, +-1, -47, -8, 23, -3, -17, -7, 18, +-125, 59, -5, 3, 18, 1, 2, 3, +27, -35, 65, -53, 50, -46, 37, -21, +-28, 7, 14, -37, -5, -5, 12, 5, +-8, 78, -19, 21, -6, -16, 8, -7, +5, 2, 7, 2, 10, -6, 12, -60, +44, 11, -36, -32, 31, 0, 2, -2, +2, 1, -3, 7, -10, 17, -21, 10, +6, -2, 19, -2, 59, -38, -86, 38, +8, -41, -30, -45, -33, 7, 15, 28, +29, -7, 24, -40, 7, 7, 5, -2, +9, 24, -23, -18, 6, -29, 30, 2, +28, 49, -11, -46, 10, 43, -13, -9, +-1, -3, -7, -7, -17, -6, 97, -33, +-21, 3, 5, 1, 12, -43, -8, 28, +7, -43, -7, 17, -20, 19, -1, 2, +-13, 9, 54, 34, 9, -28, -11, -9, +-17, 110, -59, 44, -26, 0, 3, -12, +-47, 73, -34, -43, 38, -33, 16, -5, +-46, -4, -6, -2, -25, 19, -29, 28, +-13, 5, 14, 27, -40, -43, 4, 32, +-13, -2, -35, -4, 112, -42, 9, -12, +37, -28, 17, 14, -19, 35, -39, 23, +3, -14, -1, -57, -5, 94, -9, 3, +-39, 5, 30, -10, -32, 42, -13, -14, +-97, -63, 30, -9, 1, -7, 12, 5, +20, 17, -9, -36, -30, 25, 47, -9, +-15, 12, -22, 98, -8, -50, 15, -27, +21, -16, -11, 2, 12, -10, 10, -3, +33, 36, -96, 0, -17, 31, -9, 9, +3, -20, 13, -11, 8, -4, 10, -10, +9, 1, 112, -70, -27, 5, -21, 2, +-57, -3, -29, 10, 19, -21, 21, -10, +-66, -3, 91, -35, 30, -12, 0, -7, +59, -28, 26, 2, 14, -18, 1, 1, +11, 17, 20, -54, -59, 27, 4, 29, +32, 5, 19, 12, -4, 1, 7, -10, +5, -2, 10, 0, 23, -5, 28, -104, +46, 11, 16, 3, 29, 1, -8, -14, +1, 7, -50, 88, -62, 26, 8, -17, +-14, 50, 0, 32, -12, -3, -27, 18, +-8, -5, 8, 3, -20, -11, 37, -12, +9, 33, 46, -101, -1, -4, 1, 6, +-1, 28, -42, -15, 16, 5, -1, -2, +-55, 85, 38, -9, -4, 11, -2, -9, +-6, 3, -20, -10, -77, 89, 24, -3, +-104, -57, -26, -31, -20, -6, -9, 14, +20, -23, 46, -15, -31, 28, 1, -15, +-2, 6, -2, 31, 45, -76, 23, -25, +}; diff --git a/native/codec/libraries/speex/libspeex/high_lsp_tables.c b/native/codec/libraries/speex/libspeex/high_lsp_tables.c new file mode 100644 index 0000000..732c8b5 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/high_lsp_tables.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: high_lsp_tables.c + Codebooks for high-band LSPs in SB-CELP mode + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char high_lsp_cdbk[512]={ +39,12,-14,-20,-29,-61,-67,-76, +-32,-71,-67,68,77,46,34,5, +-13,-48,-46,-72,-81,-84,-60,-58, +-40,-28,82,93,68,45,29,3, +-19,-47,-28,-43,-35,-30,-8,-13, +-39,-91,-91,-123,-96,10,10,-6, +-18,-55,-60,-91,-56,-36,-27,-16, +-48,-75,40,28,-10,-28,35,9, +37,19,1,-20,-31,-41,-18,-25, +-35,-68,-80,45,27,-1,47,13, +0,-29,-35,-57,-50,-79,-73,-38, +-19,5,35,14,-10,-23,16,-8, +5,-24,-40,-62,-23,-27,-22,-16, +-18,-46,-72,-77,43,21,33,1, +-80,-70,-70,-64,-56,-52,-39,-33, +-31,-38,-19,-19,-15,32,33,-2, +7,-15,-15,-24,-23,-33,-41,-56, +-24,-57,5,89,64,41,27,5, +-9,-47,-60,-97,-97,-124,-20,-9, +-44,-73,31,29,-4,64,48,7, +-35,-57,0,-3,-26,-47,-3,-6, +-40,-76,-79,-48,12,81,55,10, +9,-24,-43,-73,-57,-69,16,5, +-28,-53,18,29,20,0,-4,-11, +6,-13,23,7,-17,-35,-37,-37, +-30,-68,-63,6,24,-9,-14,3, +21,-13,-27,-57,-49,-80,-24,-41, +-5,-16,-5,1,45,25,12,-7, +3,-15,-6,-16,-15,-8,6,-13, +-42,-81,-80,-87,14,1,-10,-3, +-43,-69,-46,-24,-28,-29,36,6, +-43,-56,-12,12,54,79,43,9, +54,22,2,8,-12,-43,-46,-52, +-38,-69,-89,-5,75,38,33,5, +-13,-53,-62,-87,-89,-113,-99,-55, +-34,-37,62,55,33,16,21,-2, +-17,-46,-29,-38,-38,-48,-39,-42, +-36,-75,-72,-88,-48,-30,21,2, +-15,-57,-64,-98,-84,-76,25,1, +-46,-80,-12,18,-7,3,34,6, +38,31,23,4,-1,20,14,-15, +-43,-78,-91,-24,14,-3,54,16, +0,-27,-28,-44,-56,-83,-92,-89, +-3,34,56,41,36,22,20,-8, +-7,-35,-42,-62,-49,3,12,-10, +-50,-87,-96,-66,92,70,38,9, +-70,-71,-62,-42,-39,-43,-11,-7, +-50,-79,-58,-50,-31,32,31,-6, +-4,-25,7,-17,-38,-70,-58,-27, +-43,-83,-28,59,36,20,31,2, +-27,-71,-80,-109,-98,-75,-33,-32, +-31,-2,33,15,-6,43,33,-5, +0,-22,-10,-27,-34,-49,-11,-20, +-41,-91,-100,-121,-39,57,41,10, +-19,-50,-38,-59,-60,-70,-18,-20, +-8,-31,-8,-15,1,-14,-26,-25, +33,21,32,17,1,-19,-19,-26, +-58,-81,-35,-22,45,30,11,-11, +3,-26,-48,-87,-67,-83,-58,3, +-1,-26,-20,44,10,25,39,5, +-9,-35,-27,-38,7,10,4,-9, +-42,-85,-102,-127,52,44,28,10, +-47,-61,-40,-39,-17,-1,-10,-33, +-42,-74,-48,21,-4,70,52,10}; + + +const signed char high_lsp_cdbk2[512]={ +-36,-62,6,-9,-10,-14,-56,23, +1,-26,23,-48,-17,12,8,-7, +23,29,-36,-28,-6,-29,-17,-5, +40,23,10,10,-46,-13,36,6, +4,-30,-29,62,32,-32,-1,22, +-14,1,-4,-22,-45,2,54,4, +-30,-57,-59,-12,27,-3,-31,8, +-9,5,10,-14,32,66,19,9, +2,-25,-37,23,-15,18,-38,-31, +5,-9,-21,15,0,22,62,30, +15,-12,-14,-46,77,21,33,3, +34,29,-19,50,2,11,9,-38, +-12,-37,62,1,-15,54,32,6, +2,-24,20,35,-21,2,19,24, +-13,55,4,9,39,-19,30,-1, +-21,73,54,33,8,18,3,15, +6,-19,-47,6,-3,-48,-50,1, +26,20,8,-23,-50,65,-14,-55, +-17,-31,-37,-28,53,-1,-17,-53, +1,57,11,-8,-25,-30,-37,64, +5,-52,-45,15,23,31,15,14, +-25,24,33,-2,-44,-56,-18,6, +-21,-43,4,-12,17,-37,20,-10, +34,15,2,15,55,21,-11,-31, +-6,46,25,16,-9,-25,-8,-62, +28,17,20,-32,-29,26,30,25, +-19,2,-16,-17,26,-51,2,50, +42,19,-66,23,29,-2,3,19, +-19,-37,32,15,6,30,-34,13, +11,-5,40,31,10,-42,4,-9, +26,-9,-70,17,-2,-23,20,-22, +-55,51,-24,-31,22,-22,15,-13, +3,-10,-28,-16,56,4,-63,11, +-18,-15,-18,-38,-35,16,-7,34, +-1,-21,-49,-47,9,-37,7,8, +69,55,20,6,-33,-45,-10,-9, +6,-9,12,71,15,-3,-42,-7, +-24,32,-35,-2,-42,-17,-5,0, +-2,-33,-54,13,-12,-34,47,23, +19,55,7,-8,74,31,14,16, +-23,-26,19,12,-18,-49,-28,-31, +-20,2,-14,-20,-47,78,40,13, +-23,-11,21,-6,18,1,47,5, +38,35,32,46,22,8,13,16, +-14,18,51,19,40,39,11,-26, +-1,-17,47,2,-53,-15,31,-22, +38,21,-15,-16,5,-33,53,15, +-38,86,11,-3,-24,49,13,-4, +-11,-18,28,20,-12,-27,-26,35, +-25,-35,-3,-20,-61,30,10,-55, +-12,-22,-52,-54,-14,19,-32,-12, +45,15,-8,-48,-9,11,-32,8, +-16,-34,-13,51,18,38,-2,-32, +-17,22,-2,-18,-28,-70,59,27, +-28,-19,-10,-20,-9,-9,-8,-21, +21,-8,35,-2,45,-3,-9,12, +0,30,7,-39,43,27,-38,-91, +30,26,19,-55,-4,63,14,-17, +13,9,13,2,7,4,6,61, +72,-1,-17,29,-1,-22,-17,8, +-28,-37,63,44,41,3,2,14, +9,-6,75,-8,-7,-12,-15,-12, +13,9,-4,30,-22,-65,15,0, +-45,4,-4,1,5,22,11,23}; diff --git a/native/codec/libraries/speex/libspeex/kiss_fft.c b/native/codec/libraries/speex/libspeex/kiss_fft.c new file mode 100644 index 0000000..285e557 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/kiss_fft.c @@ -0,0 +1,523 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding +Copyright (c) 2005-2007, Jean-Marc Valin + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + fixed or floating point complex numbers. It also delares the kf_ internal functions. + */ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + kiss_fft_cpx * tw1; + kiss_fft_cpx t; + if (!st->inverse) { + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jr , tw1->r),MULT16_16(Fout2->i , tw1->i)), 1); + ti = SHR32(ADD32(MULT16_16(Fout2->i , tw1->r),MULT16_16(Fout2->r , tw1->i)), 1); + tw1 += fstride; + Fout2->r = PSHR32(SUB32(SHL32(EXTEND32(Fout->r), 14), tr), 15); + Fout2->i = PSHR32(SUB32(SHL32(EXTEND32(Fout->i), 14), ti), 15); + Fout->r = PSHR32(ADD32(SHL32(EXTEND32(Fout->r), 14), tr), 15); + Fout->i = PSHR32(ADD32(SHL32(EXTEND32(Fout->i), 14), ti), 15); + ++Fout2; + ++Fout; + } + } + } else { + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jinverse) + { + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for (j=0;jtwiddles; + for (j=0;jr = PSHR16(Fout->r, 2); + Fout->i = PSHR16(Fout->i, 2); + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + Fout[m2].r = PSHR16(Fout[m2].r, 2); + Fout[m2].i = PSHR16(Fout[m2].i, 2); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + ++Fout; + } + } + } +} + +static void kf_bfly3( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + size_t m + ) +{ + size_t k=m; + const size_t m2 = 2*m; + kiss_fft_cpx *tw1,*tw2; + kiss_fft_cpx scratch[5]; + kiss_fft_cpx epi3; + epi3 = st->twiddles[fstride*m]; + + tw1=tw2=st->twiddles; + + do{ + if (!st->inverse) { + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); + } + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + }while(--k); +} + +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int u; + kiss_fft_cpx scratch[13]; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx *tw; + kiss_fft_cpx ya,yb; + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + + Fout0=Fout; + Fout1=Fout0+m; + Fout2=Fout0+2*m; + Fout3=Fout0+3*m; + Fout4=Fout0+4*m; + + tw=st->twiddles; + for ( u=0; uinverse) { + C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5); + } + scratch[0] = *Fout0; + + C_MUL(scratch[1] ,*Fout1, tw[u*fstride]); + C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]); + C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]); + C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]); + + C_ADD( scratch[7],scratch[1],scratch[4]); + C_SUB( scratch[10],scratch[1],scratch[4]); + C_ADD( scratch[8],scratch[2],scratch[3]); + C_SUB( scratch[9],scratch[2],scratch[3]); + + Fout0->r += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } +} + +/* perform the butterfly for one stage of a mixed radix FFT */ +static void kf_bfly_generic( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m, + int p + ) +{ + int u,k,q1,q; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx t; + kiss_fft_cpx scratchbuf[17]; + int Norig = st->nfft; + + /*CHECKBUF(scratchbuf,nscratchbuf,p);*/ + if (p>17) + speex_fatal("KissFFT: max radix supported is 17"); + + for ( u=0; uinverse) { + C_FIXDIV(scratchbuf[q1],p); + } + k += m; + } + + k=u; + for ( q1=0 ; q1

    =Norig) twidx-=Norig; + C_MUL(t,scratchbuf[q] , twiddles[twidx] ); + C_ADDTO( Fout[ k ] ,t); + } + k += m; + } + } +} + +static +void kf_shuffle( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + const size_t fstride, + int in_stride, + int * factors, + const kiss_fft_cfg st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (spx_int32_t)p*(spx_int32_t)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; + *facbuf++ = p; + *facbuf++ = n; + } while (n > 1); +} +/* + * + * User-callable function to allocate all necessary storage space for the fft. + * + * The return value is a contiguous block of memory, allocated with malloc. As such, + * It can be freed with free(), rather than a kiss_fft-specific function. + * */ +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem ) +{ + kiss_fft_cfg st=NULL; + size_t memneeded = sizeof(struct kiss_fft_state) + + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ + + if ( lenmem==NULL ) { + st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); + }else{ + if (mem != NULL && *lenmem >= memneeded) + st = (kiss_fft_cfg)mem; + *lenmem = memneeded; + } + if (st) { + int i; + st->nfft=nfft; + st->inverse = inverse_fft; +#ifdef FIXED_POINT + for (i=0;iinverse) + phase = -phase; + kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft)); + } +#else + for (i=0;iinverse) + phase *= -1; + kf_cexp(st->twiddles+i, phase ); + } +#endif + kf_factor(nfft,st->factors); + } + return st; +} + + + + +void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) +{ + if (fin == fout) + { + speex_fatal("In-place FFT not supported"); + /*CHECKBUF(tmpbuf,ntmpbuf,st->nfft); + kf_work(tmpbuf,fin,1,in_stride, st->factors,st); + SPEEX_MOVE(fout,tmpbuf,st->nfft);*/ + } else { + kf_shuffle( fout, fin, 1,in_stride, st->factors,st); + kf_work( fout, fin, 1,in_stride, st->factors,st, 1, in_stride, 1); + } +} + +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + kiss_fft_stride(cfg,fin,fout,1); +} + diff --git a/native/codec/libraries/speex/libspeex/kiss_fft.h b/native/codec/libraries/speex/libspeex/kiss_fft.h new file mode 100644 index 0000000..fa3f2c6 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/kiss_fft.h @@ -0,0 +1,108 @@ +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ATTENTION! + If you would like a : + -- a utility that will handle the caching of fft objects + -- real-only (no imaginary time component ) FFT + -- a multi-dimensional FFT + -- a command-line utility to perform ffts + -- a command-line utility to perform fast-convolution filtering + + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c + in the tools/ directory. +*/ + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC speex_alloc +#endif + + +#ifdef FIXED_POINT +#include "arch.h" +# define kiss_fft_scalar spx_int16_t +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct kiss_fft_state* kiss_fft_cfg; + +/* + * kiss_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); + +/* + * kiss_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +/* + A more generic version of the above function. It reads its input from every Nth sample. + * */ +void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); + +/* If kiss_fft_alloc allocated a buffer, it is one contiguous + buffer and can be simply free()d when no longer needed*/ +#define kiss_fft_free speex_free + +/* + Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up + your compiler output to call this before you exit. +*/ +void kiss_fft_cleanup(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/speex/libspeex/kiss_fftr.c b/native/codec/libraries/speex/libspeex/kiss_fftr.c new file mode 100644 index 0000000..827e0b1 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/kiss_fftr.c @@ -0,0 +1,297 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include "kiss_fftr.h" +#include "_kiss_fft_guts.h" + +struct kiss_fftr_state{ + kiss_fft_cfg substate; + kiss_fft_cpx * tmpbuf; + kiss_fft_cpx * super_twiddles; +#ifdef USE_SIMD + long pad; +#endif +}; + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem) +{ + int i; + kiss_fftr_cfg st = NULL; + size_t subsize, memneeded; + + if (nfft & 1) { + speex_warning("Real FFT optimization must be even.\n"); + return NULL; + } + nfft >>= 1; + + kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); + memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 2); + + if (lenmem == NULL) { + st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); + } else { + if (*lenmem >= memneeded) + st = (kiss_fftr_cfg) mem; + *lenmem = memneeded; + } + if (!st) + return NULL; + + st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */ + st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); + st->super_twiddles = st->tmpbuf + nfft; + kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); + +#ifdef FIXED_POINT + for (i=0;i>1); + if (!inverse_fft) + phase = -phase; + kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft)); + } +#else + for (i=0;isuper_twiddles+i, phase ); + } +#endif + return st; +} + +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; + + if ( st->substate->inverse) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0].r = tdc.r + tdc.i; + freqdata[ncfft].r = tdc.r - tdc.i; +#ifdef USE_SIMD + freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); +#else + freqdata[ncfft].i = freqdata[0].i = 0; +#endif + + for ( k=1;k <= ncfft/2 ; ++k ) { + fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[k].r = HALF_OF(f1k.r + tw.r); + freqdata[k].i = HALF_OF(f1k.i + tw.i); + freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); + freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); + } +} + +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; + st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; + /*C_FIXDIV(st->tmpbuf[0],2);*/ + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk = freqdata[k]; + fnkc.r = freqdata[ncfft - k].r; + fnkc.i = -freqdata[ncfft - k].i; + /*C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 );*/ + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} + +void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx f2k,tdc; + spx_word32_t f1kr, f1ki, twr, twi; + + if ( st->substate->inverse) { + speex_fatal("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0] = tdc.r + tdc.i; + freqdata[2*ncfft-1] = tdc.r - tdc.i; + + for ( k=1;k <= ncfft/2 ; ++k ) + { + /*fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); + freqdata[2*k] = HALF_OF(f1k.i + tw.i); + freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r); + freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i); + */ + + /*f1k.r = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f1k.i = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + f2k.r = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f2k.i = SHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + + C_MUL( tw , f2k , st->super_twiddles[k]); + + freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); + freqdata[2*k] = HALF_OF(f1k.i + tw.i); + freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r); + freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i); + */ + f2k.r = SHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); + f2k.i = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); + + f1kr = SHL32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),13); + f1ki = SHL32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),13); + + twr = SHR32(SUB32(MULT16_16(f2k.r,st->super_twiddles[k].r),MULT16_16(f2k.i,st->super_twiddles[k].i)), 1); + twi = SHR32(ADD32(MULT16_16(f2k.i,st->super_twiddles[k].r),MULT16_16(f2k.r,st->super_twiddles[k].i)), 1); + +#ifdef FIXED_POINT + freqdata[2*k-1] = PSHR32(f1kr + twr, 15); + freqdata[2*k] = PSHR32(f1ki + twi, 15); + freqdata[2*(ncfft-k)-1] = PSHR32(f1kr - twr, 15); + freqdata[2*(ncfft-k)] = PSHR32(twi - f1ki, 15); +#else + freqdata[2*k-1] = .5f*(f1kr + twr); + freqdata[2*k] = .5f*(f1ki + twi); + freqdata[2*(ncfft-k)-1] = .5f*(f1kr - twr); + freqdata[2*(ncfft-k)] = .5f*(twi - f1ki); + +#endif + } +} + +void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + speex_fatal ("kiss fft usage error: improper alloc\n"); + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0] + freqdata[2*ncfft-1]; + st->tmpbuf[0].i = freqdata[0] - freqdata[2*ncfft-1]; + /*C_FIXDIV(st->tmpbuf[0],2);*/ + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk.r = freqdata[2*k-1]; + fk.i = freqdata[2*k]; + fnkc.r = freqdata[2*(ncfft - k)-1]; + fnkc.i = -freqdata[2*(ncfft - k)]; + /*C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 );*/ + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} diff --git a/native/codec/libraries/speex/libspeex/kiss_fftr.h b/native/codec/libraries/speex/libspeex/kiss_fftr.h new file mode 100644 index 0000000..7bfb423 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/kiss_fftr.h @@ -0,0 +1,51 @@ +#ifndef KISS_FTR_H +#define KISS_FTR_H + +#include "kiss_fft.h" +#ifdef __cplusplus +extern "C" { +#endif + + +/* + + Real optimized version can save about 45% cpu time vs. complex fft of a real seq. + + + + */ + +typedef struct kiss_fftr_state *kiss_fftr_cfg; + + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem); +/* + nfft must be even + + If you don't care to allocate space, use mem = lenmem = NULL +*/ + + +void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata); +/* + input timedata has nfft scalar points + output freqdata has nfft/2+1 complex points +*/ + +void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata); + +void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); + +void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata, kiss_fft_scalar *timedata); + +/* + input freqdata has nfft/2+1 complex points + output timedata has nfft scalar points +*/ + +#define kiss_fftr_free speex_free + +#ifdef __cplusplus +} +#endif +#endif diff --git a/native/codec/libraries/speex/libspeex/lpc.c b/native/codec/libraries/speex/libspeex/lpc.c new file mode 100644 index 0000000..fca4d9e --- /dev/null +++ b/native/codec/libraries/speex/libspeex/lpc.c @@ -0,0 +1,198 @@ +/* + Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, + Technische Universitaet Berlin + + Any use of this software is permitted provided that this notice is not + removed and that neither the authors nor the Technische Universitaet Berlin + are deemed to have made any representations as to the suitability of this + software for any purpose nor are held responsible for any defects of + this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + + As a matter of courtesy, the authors request to be informed about uses + this software has found, about bugs in this software, and about any + improvements that may be of general interest. + + Berlin, 28.11.1994 + Jutta Degener + Carsten Bormann + + + Code modified by Jean-Marc Valin + + Speex License: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef DISABLE_ENCODER + +#include "lpc.h" + +#ifdef BFIN_ASM +#include "lpc_bfin.h" +#endif + +/* LPC analysis + * + * The next two functions calculate linear prediction coefficients + * and/or the related reflection coefficients from the first P_MAX+1 + * values of the autocorrelation function. + */ + +/* Invented by N. Levinson in 1947, modified by J. Durbin in 1959. + */ + +/* returns minimum mean square error */ +spx_word32_t _spx_lpc( +spx_coef_t *lpc, /* out: [0...p-1] LPC coefficients */ +const spx_word16_t *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + spx_word16_t r; + spx_word16_t error = ac[0]; + + for (i = 0; i < p; i++) { + + /* Sum up this iteration's reflection coefficient */ + spx_word32_t rr = NEG32(SHL32(EXTEND32(ac[i + 1]),13)); + for (j = 0; j < i; j++) + rr = SUB32(rr,MULT16_16(lpc[j],ac[i - j])); +#ifdef FIXED_POINT + r = DIV32_16(rr+PSHR32(error,1),ADD16(error,8)); +#else + r = rr/(error+.003*ac[0]); +#endif + /* Update LPC coefficients and total error */ + lpc[i] = r; + for (j = 0; j < (i+1)>>1; j++) + { + spx_word16_t tmp1, tmp2; + /* It could be that j == i-1-j, in which case, we're updating the same value twice, which is OK */ + tmp1 = lpc[j]; + tmp2 = lpc[i-1-j]; + lpc[j] = MAC16_16_P13(tmp1,r,tmp2); + lpc[i-1-j] = MAC16_16_P13(tmp2,r,tmp1); + } + + error = SUB16(error,MULT16_16_Q13(r,MULT16_16_Q13(error,r))); + } + return error; +} + + +#ifdef FIXED_POINT + +/* Compute the autocorrelation + * ,--, + * ac(i) = > x(n) * x(n-i) for all n + * `--' + * for lags between 0 and lag-1, and x == 0 outside 0...n-1 + */ + +#ifndef OVERRIDE_SPEEX_AUTOCORR +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +spx_word16_t *ac, /* out: [0...lag-1] ac values */ +int lag, +int n +) +{ + spx_word32_t d; + int i, j; + spx_word32_t ac0=1; + int shift, ac_shift; + + for (j=0;j x(n) * x(n-i) for all n + * `--' + * for lags between 0 and lag-1, and x == 0 outside 0...n-1 + */ +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +float *ac, /* out: [0...lag-1] ac values */ +int lag, +int n +) +{ + float d; + int i; + while (lag--) + { + for (i = lag, d = 0; i < n; i++) + d += x[i] * x[i-lag]; + ac[lag] = d; + } + ac[0] += 10; +} + +#endif + + +#endif /* DISABLE_ENCODER */ diff --git a/native/codec/libraries/speex/libspeex/lpc.h b/native/codec/libraries/speex/libspeex/lpc.h new file mode 100644 index 0000000..952ecdd --- /dev/null +++ b/native/codec/libraries/speex/libspeex/lpc.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file lpc.h + @brief Functions for LPC (Linear Prediction Coefficients) analysis +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef LPC_H +#define LPC_H + +#include "arch.h" + +void _spx_autocorr( + const spx_word16_t * x, /* in: [0...n-1] samples x */ + spx_word16_t *ac, /* out: [0...lag-1] ac values */ + int lag, int n); + +spx_word32_t /* returns minimum mean square error */ +_spx_lpc( + spx_coef_t * lpc, /* [0...p-1] LPC coefficients */ + const spx_word16_t * ac, /* in: [0...p] autocorrelation values */ + int p + ); + + +#endif diff --git a/native/codec/libraries/speex/libspeex/lpc_bfin.h b/native/codec/libraries/speex/libspeex/lpc_bfin.h new file mode 100644 index 0000000..d7d11c0 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/lpc_bfin.h @@ -0,0 +1,134 @@ +/* Copyright (C) 2005 Analog Devices */ +/** + @file lpc_bfin.h + @author Jean-Marc Valin + @brief Functions for LPC (Linear Prediction Coefficients) analysis (Blackfin version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "bfin.h" + +#define OVERRIDE_SPEEX_AUTOCORR +void _spx_autocorr( +const spx_word16_t *x, /* in: [0...n-1] samples x */ +spx_word16_t *ac, /* out: [0...lag-1] ac values */ +int lag, +int n + ) +{ + spx_word32_t d; + const spx_word16_t *xs; + int i, j; + spx_word32_t ac0=1; + spx_word32_t ac32[11], *ac32top; + int shift, ac_shift; + ac32top = ac32+lag-1; + int lag_1, N_lag; + int nshift; + lag_1 = lag-1; + N_lag = n-lag_1; + for (j=0;j> 1;\n\t" + "LOOP_BEGIN pitch%=;\n\t" + "I1 = P0;\n\t" + "A1 = A0 = 0;\n\t" + "R1 = [I1++];\n\t" + "LOOP inner_prod%= LC1 = P3 >> 1;\n\t" + "LOOP_BEGIN inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t" + "LOOP_END inner_prod%=;\n\t" + "A0 = ASHIFT A0 by R4.L;\n\t" + "A1 = ASHIFT A1 by R4.L;\n\t" + + "R2 = A0, R3 = A1;\n\t" + "[P1--] = R2;\n\t" + "[P1--] = R3;\n\t" + "P0 += 4;\n\t" + "LOOP_END pitch%=;\n\t" + : : "m" (xs), "m" (x), "m" (ac32top), "m" (N_lag), "m" (lag_1), "m" (nshift) + : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "R4", "I0", "I1", "L0", "L1", "B0", "B1", "memory", + "ASTAT" BFIN_HWLOOP0_REGS BFIN_HWLOOP1_REGS + ); + d=0; + for (j=0;j +#include "lsp.h" +#include "stack_alloc.h" +#include "math_approx.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef FIXED_POINT + +#define FREQ_SCALE 16384 + +/*#define ANGLE2X(a) (32768*cos(((a)/8192.)))*/ +#define ANGLE2X(a) (SHL16(spx_cos(a),2)) + +/*#define X2ANGLE(x) (acos(.00006103515625*(x))*LSP_SCALING)*/ +#define X2ANGLE(x) (spx_acos(x)) + +#ifdef BFIN_ASM +#include "lsp_bfin.h" +#endif + +#else + +/*#define C1 0.99940307 +#define C2 -0.49558072 +#define C3 0.03679168*/ + +#define FREQ_SCALE 1. +#define ANGLE2X(a) (spx_cos(a)) +#define X2ANGLE(x) (acos(x)) + +#endif + +#ifndef DISABLE_ENCODER + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: cheb_poly_eva() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + This function evaluates a series of Chebyshev polynomials + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT + +#ifndef OVERRIDE_CHEB_POLY_EVA +static inline spx_word32_t cheb_poly_eva( + spx_word16_t *coef, /* P or Q coefs in Q13 format */ + spx_word16_t x, /* cos of freq (-1.0 to 1.0) in Q14 format */ + int m, /* LPC order/2 */ + char *stack +) +{ + int i; + spx_word16_t b0, b1; + spx_word32_t sum; + + /*Prevents overflows*/ + if (x>16383) + x = 16383; + if (x<-16383) + x = -16383; + + /* Initialise values */ + b1=16384; + b0=x; + + /* Evaluate Chebyshev series formulation usin g iterative approach */ + sum = ADD32(EXTEND32(coef[m]), EXTEND32(MULT16_16_P14(coef[m-1],x))); + for(i=2;i<=m;i++) + { + spx_word16_t tmp=b0; + b0 = SUB16(MULT16_16_Q13(x,b0), b1); + b1 = tmp; + sum = ADD32(sum, EXTEND32(MULT16_16_P14(coef[m-i],b0))); + } + + return sum; +} +#endif + +#else + +static float cheb_poly_eva(spx_word32_t *coef, spx_word16_t x, int m, char *stack) +{ + int k; + float b0, b1, tmp; + + /* Initial conditions */ + b0=0; /* b_(m+1) */ + b1=0; /* b_(m+2) */ + + x*=2; + + /* Calculate the b_(k) */ + for(k=m;k>0;k--) + { + tmp=b0; /* tmp holds the previous value of b0 */ + b0=x*b0-b1+coef[m-k]; /* b0 holds its new value based on b0 and b1 */ + b1=tmp; /* b1 holds the previous value of b0 */ + } + + return(-b1+.5*x*b0+coef[m]); +} +#endif + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: lpc_to_lsp() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + This function converts LPC coefficients to LSP + coefficients. + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT +#define SIGN_CHANGE(a,b) ((((a)^(b))&0x80000000)||(b==0)) +#else +#define SIGN_CHANGE(a,b) (((a)*(b))<0.0) +#endif + + +int lpc_to_lsp (spx_coef_t *a,int lpcrdr,spx_lsp_t *freq,int nb,spx_word16_t delta, char *stack) +/* float *a lpc coefficients */ +/* int lpcrdr order of LPC coefficients (10) */ +/* float *freq LSP frequencies in the x domain */ +/* int nb number of sub-intervals (4) */ +/* float delta grid spacing interval (0.02) */ + + +{ + spx_word16_t temp_xr,xl,xr,xm=0; + spx_word32_t psuml,psumr,psumm,temp_psumr/*,temp_qsumr*/; + int i,j,m,k; + VARDECL(spx_word32_t *Q); /* ptrs for memory allocation */ + VARDECL(spx_word32_t *P); + VARDECL(spx_word16_t *Q16); /* ptrs for memory allocation */ + VARDECL(spx_word16_t *P16); + spx_word32_t *px; /* ptrs of respective P'(z) & Q'(z) */ + spx_word32_t *qx; + spx_word32_t *p; + spx_word32_t *q; + spx_word16_t *pt; /* ptr used for cheb_poly_eval() + whether P' or Q' */ + int roots=0; /* DR 8/2/94: number of roots found */ + m = lpcrdr/2; /* order of P'(z) & Q'(z) polynomials */ + + /* Allocate memory space for polynomials */ + ALLOC(Q, (m+1), spx_word32_t); + ALLOC(P, (m+1), spx_word32_t); + + /* determine P'(z)'s and Q'(z)'s coefficients where + P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */ + + px = P; /* initialise ptrs */ + qx = Q; + p = px; + q = qx; + +#ifdef FIXED_POINT + *px++ = LPC_SCALING; + *qx++ = LPC_SCALING; + for(i=0;i=32768) + speex_warning_int("px", *px); + if (fabs(*qx)>=32768) + speex_warning_int("qx", *qx);*/ + *px = PSHR32(*px,2); + *qx = PSHR32(*qx,2); + px++; + qx++; + } + /* The reason for this lies in the way cheb_poly_eva() is implemented for fixed-point */ + P[m] = PSHR32(P[m],3); + Q[m] = PSHR32(Q[m],3); +#else + *px++ = LPC_SCALING; + *qx++ = LPC_SCALING; + for(i=0;i= -FREQ_SCALE){ + spx_word16_t dd; + /* Modified by JMV to provide smaller steps around x=+-1 */ +#ifdef FIXED_POINT + dd = MULT16_16_Q15(delta,SUB16(FREQ_SCALE, MULT16_16_Q14(MULT16_16_Q14(xl,xl),14000))); + if (psuml<512 && psuml>-512) + dd = PSHR16(dd,1); +#else + dd=delta*(1-.9*xl*xl); + if (fabs(psuml)<.2) + dd *= .5; +#endif + xr = SUB16(xl, dd); /* interval spacing */ + psumr = cheb_poly_eva(pt,xr,m,stack);/* poly(xl-delta_x) */ + temp_psumr = psumr; + temp_xr = xr; + + /* if no sign change increment xr and re-evaluate poly(xr). Repeat til + sign change. + if a sign change has occurred the interval is bisected and then + checked again for a sign change which determines in which + interval the zero lies in. + If there is no sign change between poly(xm) and poly(xl) set interval + between xm and xr else set interval between xl and xr and repeat till + root is located within the specified limits */ + + if(SIGN_CHANGE(psumr,psuml)) + { + roots++; + + psumm=psuml; + for(k=0;k<=nb;k++){ +#ifdef FIXED_POINT + xm = ADD16(PSHR16(xl,1),PSHR16(xr,1)); /* bisect the interval */ +#else + xm = .5*(xl+xr); /* bisect the interval */ +#endif + psumm=cheb_poly_eva(pt,xm,m,stack); + /*if(psumm*psuml>0.)*/ + if(!SIGN_CHANGE(psumm,psuml)) + { + psuml=psumm; + xl=xm; + } else { + psumr=psumm; + xr=xm; + } + } + + /* once zero is found, reset initial interval to xr */ + freq[j] = X2ANGLE(xm); + xl = xm; + break; + } + else{ + psuml=temp_psumr; + xl=temp_xr; + } + } + } + return(roots); +} + +#endif /* DISABLE_ENCODER */ +/*---------------------------------------------------------------------------*\ + + FUNCTION....: lsp_to_lpc() + + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + Converts LSP coefficients to LPC coefficients. + +\*---------------------------------------------------------------------------*/ + +#ifdef FIXED_POINT + +void lsp_to_lpc(const spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) +/* float *freq array of LSP frequencies in the x domain */ +/* float *ak array of LPC coefficients */ +/* int lpcrdr order of LPC coefficients */ +{ + int i,j; + spx_word32_t xout1,xout2,xin; + spx_word32_t mult, a; + VARDECL(spx_word16_t *freqn); + VARDECL(spx_word32_t **xp); + VARDECL(spx_word32_t *xpmem); + VARDECL(spx_word32_t **xq); + VARDECL(spx_word32_t *xqmem); + int m = lpcrdr>>1; + + /* + + Reconstruct P(z) and Q(z) by cascading second order polynomials + in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency. + In the time domain this is: + + y(n) = x(n) - 2cos(w)x(n-1) + x(n-2) + + This is what the ALLOCS below are trying to do: + + int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP + int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP + + These matrices store the output of each stage on each row. The + final (m-th) row has the output of the final (m-th) cascaded + 2nd order filter. The first row is the impulse input to the + system (not written as it is known). + + The version below takes advantage of the fact that a lot of the + outputs are zero or known, for example if we put an inpulse + into the first section the "clock" it 10 times only the first 3 + outputs samples are non-zero (it's an FIR filter). + */ + + ALLOC(xp, (m+1), spx_word32_t*); + ALLOC(xpmem, (m+1)*(lpcrdr+1+2), spx_word32_t); + + ALLOC(xq, (m+1), spx_word32_t*); + ALLOC(xqmem, (m+1)*(lpcrdr+1+2), spx_word32_t); + + for(i=0; i<=m; i++) { + xp[i] = xpmem + i*(lpcrdr+1+2); + xq[i] = xqmem + i*(lpcrdr+1+2); + } + + /* work out 2cos terms in Q14 */ + + ALLOC(freqn, lpcrdr, spx_word16_t); + for (i=0;i 32767) a = 32767; + ak[j-1] = (short)a; + + } + +} + +#else + +void lsp_to_lpc(const spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) +/* float *freq array of LSP frequencies in the x domain */ +/* float *ak array of LPC coefficients */ +/* int lpcrdr order of LPC coefficients */ + + +{ + int i,j; + float xout1,xout2,xin1,xin2; + VARDECL(float *Wp); + float *pw,*n1,*n2,*n3,*n4=NULL; + VARDECL(float *x_freq); + int m = lpcrdr>>1; + + ALLOC(Wp, 4*m+2, float); + pw = Wp; + + /* initialise contents of array */ + + for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */ + *pw++ = 0.0; + } + + /* Set pointers up */ + + pw = Wp; + xin1 = 1.0; + xin2 = 1.0; + + ALLOC(x_freq, lpcrdr, float); + for (i=0;i0) + ak[j-1] = (xout1 + xout2)*0.5f; + *(n4+1) = xin1; + *(n4+2) = xin2; + + xin1 = 0.0; + xin2 = 0.0; + } + +} +#endif + + +#ifdef FIXED_POINT + + +void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *lsp, int len, int subframe, int nb_subframes, spx_word16_t margin) +{ + int i; + spx_word16_t m = margin; + spx_word16_t m2 = 25736-margin; + spx_word16_t tmp = DIV32_16(SHL32(EXTEND32(1 + subframe),14),nb_subframes); + spx_word16_t tmp2 = 16384-tmp; + for (i=0;im2) + lsp[len-1]=m2; + for (i=1;ilsp[i+1]-m) + lsp[i]= SHR16(lsp[i],1) + SHR16(lsp[i+1]-m,1); + } +} + +#else + + +void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *lsp, int len, int subframe, int nb_subframes, spx_word16_t margin) +{ + int i; + float tmp = (1.0f + subframe)/nb_subframes; + for (i=0;iLSP_SCALING*(M_PI-margin)) + lsp[len-1]=LSP_SCALING*(M_PI-margin); + for (i=1;ilsp[i+1]-LSP_SCALING*margin) + lsp[i]= .5f* (lsp[i] + lsp[i+1]-LSP_SCALING*margin); + } +} + +#endif diff --git a/native/codec/libraries/speex/libspeex/lsp.h b/native/codec/libraries/speex/libspeex/lsp.h new file mode 100644 index 0000000..6560f85 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/lsp.h @@ -0,0 +1,62 @@ +/*---------------------------------------------------------------------------*\ +Original Copyright + FILE........: AK2LSPD.H + TYPE........: Turbo C header file + COMPANY.....: Voicetronix + AUTHOR......: James Whitehall + DATE CREATED: 21/11/95 + +Modified by Jean-Marc Valin + + This file contains functions for converting Linear Prediction + Coefficients (LPC) to Line Spectral Pair (LSP) and back. Note that the + LSP coefficients are not in radians format but in the x domain of the + unit circle. + +\*---------------------------------------------------------------------------*/ +/** + @file lsp.h + @brief Line Spectral Pair (LSP) functions. +*/ +/* Speex License: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __AK2LSPD__ +#define __AK2LSPD__ + +#include "arch.h" + +int lpc_to_lsp (spx_coef_t *a, int lpcrdr, spx_lsp_t *freq, int nb, spx_word16_t delta, char *stack); +void lsp_to_lpc(const spx_lsp_t *freq, spx_coef_t *ak, int lpcrdr, char *stack); + +/*Added by JMV*/ +void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes, spx_word16_t margin); + +#endif /* __AK2LSPD__ */ diff --git a/native/codec/libraries/speex/libspeex/lsp_bfin.h b/native/codec/libraries/speex/libspeex/lsp_bfin.h new file mode 100644 index 0000000..530367c --- /dev/null +++ b/native/codec/libraries/speex/libspeex/lsp_bfin.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2006 David Rowe */ +/** + @file lsp_bfin.h + @author David Rowe + @brief LSP routines optimised for the Blackfin +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_CHEB_POLY_EVA +#ifdef OVERRIDE_CHEB_POLY_EVA +static inline spx_word32_t cheb_poly_eva( + spx_word16_t *coef, /* P or Q coefs in Q13 format */ + spx_word16_t x, /* cos of freq (-1.0 to 1.0) in Q14 format */ + int m, /* LPC order/2 */ + char *stack +) +{ + spx_word32_t sum; + + __asm__ __volatile__ + ( + "P0 = %2;\n\t" /* P0: coef[m], coef[m-1],..., coef[0] */ + "R4 = 8192;\n\t" /* R4: rounding constant */ + "R2 = %1;\n\t" /* R2: x */ + + "R5 = -16383;\n\t" + "R2 = MAX(R2,R5);\n\t" + "R5 = 16383;\n\t" + "R2 = MIN(R2,R5);\n\t" + + "R3 = W[P0--] (X);\n\t" /* R3: sum */ + "R5 = W[P0--] (X);\n\t" + "R5 = R5.L * R2.L (IS);\n\t" + "R5 = R5 + R4;\n\t" + "R5 >>>= 14;\n\t" + "R3 = R3 + R5;\n\t" + + "R0 = R2;\n\t" /* R0: b0 */ + "R1 = 16384;\n\t" /* R1: b1 */ + "LOOP cpe%= LC0 = %3;\n\t" + "LOOP_BEGIN cpe%=;\n\t" + "P1 = R0;\n\t" + "R0 = R2.L * R0.L (IS) || R5 = W[P0--] (X);\n\t" + "R0 >>>= 13;\n\t" + "R0 = R0 - R1;\n\t" + "R1 = P1;\n\t" + "R5 = R5.L * R0.L (IS);\n\t" + "R5 = R5 + R4;\n\t" + "R5 >>>= 14;\n\t" + "R3 = R3 + R5;\n\t" + "LOOP_END cpe%=;\n\t" + "%0 = R3;\n\t" + : "=&d" (sum) + : "a" (x), "a" (&coef[m]), "a" (m-1) + : "R0", "R1", "R3", "R2", "R4", "R5", "P0", "P1", "ASTAT" BFIN_HWLOOP0_REGS + ); + return sum; +} +#endif + + + diff --git a/native/codec/libraries/speex/libspeex/lsp_tables_nb.c b/native/codec/libraries/speex/libspeex/lsp_tables_nb.c new file mode 100644 index 0000000..8015b9a --- /dev/null +++ b/native/codec/libraries/speex/libspeex/lsp_tables_nb.c @@ -0,0 +1,360 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: lsp_tables_nb.c + Codebooks for LSPs in narrowband CELP mode + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +const signed char cdbk_nb[640]={ +30,19,38,34,40,32,46,43,58,43, +5,-18,-25,-40,-33,-55,-52,20,34,28, +-20,-63,-97,-92,61,53,47,49,53,75, +-14,-53,-77,-79,0,-3,-5,19,22,26, +-9,-53,-55,66,90,72,85,68,74,52, +-4,-41,-58,-31,-18,-31,27,32,30,18, +24,3,8,5,-12,-3,26,28,74,63, +-2,-39,-67,-77,-106,-74,59,59,73,65, +44,40,71,72,82,83,98,88,89,60, +-6,-31,-47,-48,-13,-39,-9,7,2,79, +-1,-39,-60,-17,87,81,65,50,45,19, +-21,-67,-91,-87,-41,-50,7,18,39,74, +10,-31,-28,39,24,13,23,5,56,45, +29,10,-5,-13,-11,-35,-18,-8,-10,-8, +-25,-71,-77,-21,2,16,50,63,87,87, +5,-32,-40,-51,-68,0,12,6,54,34, +5,-12,32,52,68,64,69,59,65,45, +14,-16,-31,-40,-65,-67,41,49,47,37, +-11,-52,-75,-84,-4,57,48,42,42,33, +-11,-51,-68,-6,13,0,8,-8,26,32, +-23,-53,0,36,56,76,97,105,111,97, +-1,-28,-39,-40,-43,-54,-44,-40,-18,35, +16,-20,-19,-28,-42,29,47,38,74,45, +3,-29,-48,-62,-80,-104,-33,56,59,59, +10,17,46,72,84,101,117,123,123,106, +-7,-33,-49,-51,-70,-67,-27,-31,70,67, +-16,-62,-85,-20,82,71,86,80,85,74, +-19,-58,-75,-45,-29,-33,-18,-25,45,57, +-12,-42,-5,12,28,36,52,64,81,82, +13,-9,-27,-28,22,3,2,22,26,6, +-6,-44,-51,2,15,10,48,43,49,34, +-19,-62,-84,-89,-102,-24,8,17,61,68, +39,24,23,19,16,-5,12,15,27,15, +-8,-44,-49,-60,-18,-32,-28,52,54,62, +-8,-48,-77,-70,66,101,83,63,61,37, +-12,-50,-75,-64,33,17,13,25,15,77, +1,-42,-29,72,64,46,49,31,61,44, +-8,-47,-54,-46,-30,19,20,-1,-16,0, +16,-12,-18,-9,-26,-27,-10,-22,53,45, +-10,-47,-75,-82,-105,-109,8,25,49,77, +50,65,114,117,124,118,115,96,90,61, +-9,-45,-63,-60,-75,-57,8,11,20,29, +0,-35,-49,-43,40,47,35,40,55,38, +-24,-76,-103,-112,-27,3,23,34,52,75, +8,-29,-43,12,63,38,35,29,24,8, +25,11,1,-15,-18,-43,-7,37,40,21, +-20,-56,-19,-19,-4,-2,11,29,51,63, +-2,-44,-62,-75,-89,30,57,51,74,51, +50,46,68,64,65,52,63,55,65,43, +18,-9,-26,-35,-55,-69,3,6,8,17, +-15,-61,-86,-97,1,86,93,74,78,67, +-1,-38,-66,-48,48,39,29,25,17,-1, +13,13,29,39,50,51,69,82,97,98, +-2,-36,-46,-27,-16,-30,-13,-4,-7,-4, +25,-5,-11,-6,-25,-21,33,12,31,29, +-8,-38,-52,-63,-68,-89,-33,-1,10,74, +-2,-15,59,91,105,105,101,87,84,62, +-7,-33,-50,-35,-54,-47,25,17,82,81, +-13,-56,-83,21,58,31,42,25,72,65, +-24,-66,-91,-56,9,-2,21,10,69,75, +2,-24,11,22,25,28,38,34,48,33, +7,-29,-26,17,15,-1,14,0,-2,0, +-6,-41,-67,6,-2,-9,19,2,85,74, +-22,-67,-84,-71,-50,3,11,-9,2,62}; + +const signed char cdbk_nb_low1[320]={ +-34,-52,-15,45,2, +23,21,52,24,-33, +-9,-1,9,-44,-41, +-13,-17,44,22,-17, +-6,-4,-1,22,38, +26,16,2,50,27, +-35,-34,-9,-41,6, +0,-16,-34,51,8, +-14,-31,-49,15,-33, +45,49,33,-11,-37, +-62,-54,45,11,-5, +-72,11,-1,-12,-11, +24,27,-11,-43,46, +43,33,-12,-9,-1, +1,-4,-23,-57,-71, +11,8,16,17,-8, +-20,-31,-41,53,48, +-16,3,65,-24,-8, +-23,-32,-37,-32,-49, +-10,-17,6,38,5, +-9,-17,-46,8,52, +3,6,45,40,39, +-7,-6,-34,-74,31, +8,1,-16,43,68, +-11,-19,-31,4,6, +0,-6,-17,-16,-38, +-16,-30,2,9,-39, +-16,-1,43,-10,48, +3,3,-16,-31,-3, +62,68,43,13,3, +-10,8,20,-56,12, +12,-2,-18,22,-15, +-40,-36,1,7,41, +0,1,46,-6,-62, +-4,-12,-2,-11,-83, +-13,-2,91,33,-10, +0,4,-11,-16,79, +32,37,14,9,51, +-21,-28,-56,-34,0, +21,9,-26,11,28, +-42,-54,-23,-2,-15, +31,30,8,-39,-66, +-39,-36,31,-28,-40, +-46,35,40,22,24, +33,48,23,-34,14, +40,32,17,27,-3, +25,26,-13,-61,-17, +11,4,31,60,-6, +-26,-41,-64,13,16, +-26,54,31,-11,-23, +-9,-11,-34,-71,-21, +-34,-35,55,50,29, +-22,-27,-50,-38,57, +33,42,57,48,26, +11,0,-49,-31,26, +-4,-14,5,78,37, +17,0,-49,-12,-23, +26,14,2,2,-43, +-17,-12,10,-8,-4, +8,18,12,-6,20, +-12,-6,-13,-25,34, +15,40,49,7,8, +13,20,20,-19,-22, +-2,-8,2,51,-51}; + +const signed char cdbk_nb_low2[320]={ +-6,53,-21,-24,4, +26,17,-4,-37,25, +17,-36,-13,31,3, +-6,27,15,-10,31, +28,26,-10,-10,-40, +16,-7,15,13,41, +-9,0,-4,50,-6, +-7,14,38,22,0, +-48,2,1,-13,-19, +32,-3,-60,11,-17, +-1,-24,-34,-1,35, +-5,-27,28,44,13, +25,15,42,-11,15, +51,35,-36,20,8, +-4,-12,-29,19,-47, +49,-15,-4,16,-29, +-39,14,-30,4,25, +-9,-5,-51,-14,-3, +-40,-32,38,5,-9, +-8,-4,-1,-22,71, +-3,14,26,-18,-22, +24,-41,-25,-24,6, +23,19,-10,39,-26, +-27,65,45,2,-7, +-26,-8,22,-12,16, +15,16,-35,-5,33, +-21,-8,0,23,33, +34,6,21,36,6, +-7,-22,8,-37,-14, +31,38,11,-4,-3, +-39,-32,-8,32,-23, +-6,-12,16,20,-28, +-4,23,13,-52,-1, +22,6,-33,-40,-6, +4,-62,13,5,-26, +35,39,11,2,57, +-11,9,-20,-28,-33, +52,-5,-6,-2,22, +-14,-16,-48,35,1, +-58,20,13,33,-1, +-74,56,-18,-22,-31, +12,6,-14,4,-2, +-9,-47,10,-3,29, +-17,-5,61,14,47, +-12,2,72,-39,-17, +92,64,-53,-51,-15, +-30,-38,-41,-29,-28, +27,9,36,9,-35, +-42,81,-21,20,25, +-16,-5,-17,-35,21, +15,-28,48,2,-2, +9,-19,29,-40,30, +-18,-18,18,-16,-57, +15,-20,-12,-15,-37, +-15,33,-39,21,-22, +-13,35,11,13,-38, +-63,29,23,-27,32, +18,3,-26,42,33, +-64,-66,-17,16,56, +2,36,3,31,21, +-41,-39,8,-57,14, +37,-2,19,-36,-19, +-23,-29,-16,1,-3, +-8,-10,31,64,-65}; + +const signed char cdbk_nb_high1[320]={ +-26,-8,29,21,4, +19,-39,33,-7,-36, +56,54,48,40,29, +-4,-24,-42,-66,-43, +-60,19,-2,37,41, +-10,-37,-60,-64,18, +-22,77,73,40,25, +4,19,-19,-66,-2, +11,5,21,14,26, +-25,-86,-4,18,1, +26,-37,10,37,-1, +24,-12,-59,-11,20, +-6,34,-16,-16,42, +19,-28,-51,53,32, +4,10,62,21,-12, +-34,27,4,-48,-48, +-50,-49,31,-7,-21, +-42,-25,-4,-43,-22, +59,2,27,12,-9, +-6,-16,-8,-32,-58, +-16,-29,-5,41,23, +-30,-33,-46,-13,-10, +-38,52,52,1,-17, +-9,10,26,-25,-6, +33,-20,53,55,25, +-32,-5,-42,23,21, +66,5,-28,20,9, +75,29,-7,-42,-39, +15,3,-23,21,6, +11,1,-29,14,63, +10,54,26,-24,-51, +-49,7,-23,-51,15, +-66,1,60,25,10, +0,-30,-4,-15,17, +19,59,40,4,-5, +33,6,-22,-58,-70, +-5,23,-6,60,44, +-29,-16,-47,-29,52, +-19,50,28,16,35, +31,36,0,-21,6, +21,27,22,42,7, +-66,-40,-8,7,19, +46,0,-4,60,36, +45,-7,-29,-6,-32, +-39,2,6,-9,33, +20,-51,-34,18,-6, +19,6,11,5,-19, +-29,-2,42,-11,-45, +-21,-55,57,37,2, +-14,-67,-16,-27,-38, +69,48,19,2,-17, +20,-20,-16,-34,-17, +-25,-61,10,73,45, +16,-40,-64,-17,-29, +-22,56,17,-39,8, +-11,8,-25,-18,-13, +-19,8,54,57,36, +-17,-26,-4,6,-21, +40,42,-4,20,31, +53,10,-34,-53,31, +-17,35,0,15,-6, +-20,-63,-73,22,25, +29,17,8,-29,-39, +-69,18,15,-15,-5}; + +const signed char cdbk_nb_high2[320]={ +11,47,16,-9,-46, +-32,26,-64,34,-5, +38,-7,47,20,2, +-73,-99,-3,-45,20, +70,-52,15,-6,-7, +-82,31,21,47,51, +39,-3,9,0,-41, +-7,-15,-54,2,0, +27,-31,9,-45,-22, +-38,-24,-24,8,-33, +23,5,50,-36,-17, +-18,-51,-2,13,19, +43,12,-15,-12,61, +38,38,7,13,0, +6,-1,3,62,9, +27,22,-33,38,-35, +-9,30,-43,-9,-32, +-1,4,-4,1,-5, +-11,-8,38,31,11, +-10,-42,-21,-37,1, +43,15,-13,-35,-19, +-18,15,23,-26,59, +1,-21,53,8,-41, +-50,-14,-28,4,21, +25,-28,-40,5,-40, +-41,4,51,-33,-8, +-8,1,17,-60,12, +25,-41,17,34,43, +19,45,7,-37,24, +-15,56,-2,35,-10, +48,4,-47,-2,5, +-5,-54,5,-3,-33, +-10,30,-2,-44,-24, +-38,9,-9,42,4, +6,-56,44,-16,9, +-40,-26,18,-20,10, +28,-41,-21,-4,13, +-18,32,-30,-3,37, +15,22,28,50,-40, +3,-29,-64,7,51, +-19,-11,17,-27,-40, +-64,24,-12,-7,-27, +3,37,48,-1,2, +-9,-38,-34,46,1, +27,-6,19,-13,26, +10,34,20,25,40, +50,-6,-7,30,9, +-24,0,-23,71,-61, +22,58,-34,-4,2, +-49,-33,25,30,-8, +-6,-16,77,2,38, +-8,-35,-6,-30,56, +78,31,33,-20,13, +-39,20,22,4,21, +-8,4,-6,10,-83, +-41,9,-25,-43,15, +-7,-12,-34,-39,-37, +-33,19,30,16,-33, +42,-25,25,-68,44, +-15,-11,-4,23,50, +14,4,-39,-43,20, +-30,60,9,-20,7, +16,19,-33,37,29, +16,-35,7,38,-27}; diff --git a/native/codec/libraries/speex/libspeex/ltp.c b/native/codec/libraries/speex/libspeex/ltp.c new file mode 100644 index 0000000..347a9db --- /dev/null +++ b/native/codec/libraries/speex/libspeex/ltp.c @@ -0,0 +1,850 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: ltp.c + Long-Term Prediction functions + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "ltp.h" +#include "stack_alloc.h" +#include "filters.h" +#include "math_approx.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + + +#ifdef _USE_SSE +#include "ltp_sse.h" +#elif defined (ARM4_ASM) || defined(ARM5E_ASM) +#include "ltp_arm4.h" +#elif defined (BFIN_ASM) +#include "ltp_bfin.h" +#endif + +#ifndef OVERRIDE_INNER_PROD +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len) +{ + spx_word32_t sum=0; + len >>= 2; + while(len--) + { + spx_word32_t part=0; + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + part = MAC16_16(part,*x++,*y++); + /* HINT: If you had a 40-bit accumulator, you could shift only at the end */ + sum = ADD32(sum,SHR32(part,6)); + } + return sum; +} +#endif + +#ifndef DISABLE_ENCODER + +#ifndef OVERRIDE_PITCH_XCORR +#if 0 /* HINT: Enable this for machines with enough registers (i.e. not x86) */ +static void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + int i,j; + for (i=0;i16383) + { + scaledown=1; + break; + } + } + /* If the weighted input is close to saturation, then we scale it down */ + if (scaledown) + { + for (i=-end;iMULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) + { + /* We can safely put it last and then check */ + best_score[N-1]=tmp; + best_ener[N-1]=ener16[i-start]+1; + pitch[N-1]=i; + /* Check if it comes in front of others */ + for (j=0;jMULT16_16(best_score[j],ADD16(1,ener16[i-start]))) + { + for (k=N-1;k>j;k--) + { + best_score[k]=best_score[k-1]; + best_ener[k]=best_ener[k-1]; + pitch[k]=pitch[k-1]; + } + best_score[j]=tmp; + best_ener[j]=ener16[i-start]+1; + pitch[j]=i; + break; + } + } + } + } + + /* Compute open-loop gain if necessary */ + if (gain) + { + for (j=0;jbest_sum && gain_sum<=max_gain) { + best_sum=sum; + best_cdbk=i; + } + } + + return best_cdbk; +} +#endif + +/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */ +static spx_word32_t pitch_gain_search_3tap( +const spx_word16_t target[], /* Target vector */ +const spx_coef_t ak[], /* LPCs for this subframe */ +const spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +const spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Excitation */ +const signed char *gain_cdbk, +int gain_cdbk_size, +int pitch, /* Pitch value */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +const spx_word16_t *exc2, +const spx_word16_t *r, +spx_word16_t *new_target, +int *cdbk_index, +int plc_tuning, +spx_word32_t cumul_gain, +int scaledown +) +{ + int i,j; + VARDECL(spx_word16_t *tmp1); + VARDECL(spx_word16_t *e); + spx_word16_t *x[3]; + spx_word32_t corr[3]; + spx_word32_t A[3][3]; + spx_word16_t gain[3]; + spx_word32_t err; + spx_word16_t max_gain=128; + int best_cdbk=0; + + ALLOC(tmp1, 3*nsf, spx_word16_t); + ALLOC(e, nsf, spx_word16_t); + + if (cumul_gain > 262144) + max_gain = 31; + + x[0]=tmp1; + x[1]=tmp1+nsf; + x[2]=tmp1+2*nsf; + + for (j=0;j0) + bound = pp; + for (j=0;j0) + bound = pp+pitch; + for (;j=0;i--) + { + spx_word16_t e0=exc2[-pitch-1+i]; +#ifdef FIXED_POINT + /* Scale excitation down if needed (avoiding overflow) */ + if (scaledown) + e0 = SHR16(e0,1); +#endif + x[i][0]=MULT16_16_Q14(r[0], e0); + for (j=0;j30) + plc_tuning=30; +#ifdef FIXED_POINT + C[0] = SHL32(C[0],1); + C[1] = SHL32(C[1],1); + C[2] = SHL32(C[2],1); + C[3] = SHL32(C[3],1); + C[4] = SHL32(C[4],1); + C[5] = SHL32(C[5],1); + C[6] = MAC16_32_Q15(C[6],MULT16_16_16(plc_tuning,655),C[6]); + C[7] = MAC16_32_Q15(C[7],MULT16_16_16(plc_tuning,655),C[7]); + C[8] = MAC16_32_Q15(C[8],MULT16_16_16(plc_tuning,655),C[8]); + normalize16(C, C16, 32767, 9); +#else + C[6]*=.5*(1+.02*plc_tuning); + C[7]*=.5*(1+.02*plc_tuning); + C[8]*=.5*(1+.02*plc_tuning); +#endif + + best_cdbk = pitch_gain_search_3tap_vq(gain_cdbk, gain_cdbk_size, C16, max_gain); + +#ifdef FIXED_POINT + gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4]); + gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+1]); + gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+2]); + /*printf ("%d %d %d %d\n",gain[0],gain[1],gain[2], best_cdbk);*/ +#else + gain[0] = 0.015625*gain_cdbk[best_cdbk*4] + .5; + gain[1] = 0.015625*gain_cdbk[best_cdbk*4+1]+ .5; + gain[2] = 0.015625*gain_cdbk[best_cdbk*4+2]+ .5; +#endif + *cdbk_index=best_cdbk; + } + + SPEEX_MEMSET(exc, 0, nsf); + for (i=0;i<3;i++) + { + int j; + int tmp1, tmp3; + int pp=pitch+1-i; + tmp1=nsf; + if (tmp1>pp) + tmp1=pp; + for (j=0;jpp+pitch) + tmp3=pp+pitch; + for (j=tmp1;jgain_bits; + gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset; + + N=complexity; + if (N>10) + N=10; + if (N<1) + N=1; + + ALLOC(nbest, N, int); + params = (const ltp_params*) par; + + if (endpitch_bits); + speex_bits_pack(bits, 0, params->gain_bits); + SPEEX_MEMSET(exc, 0, nsf); + return start; + } + +#ifdef FIXED_POINT + /* Check if we need to scale everything down in the pitch search to avoid overflows */ + for (i=0;i16383) + { + scaledown=1; + break; + } + } + for (i=-end;i<0;i++) + { + if (ABS16(exc2[i])>16383) + { + scaledown=1; + break; + } + } +#endif + if (N>end-start+1) + N=end-start+1; + if (end != start) + open_loop_nbest_pitch(sw, start, end, nsf, nbest, NULL, N, stack); + else + nbest[0] = start; + + ALLOC(best_exc, nsf, spx_sig_t); + ALLOC(new_target, nsf, spx_word16_t); + ALLOC(best_target, nsf, spx_word16_t); + + for (i=0;ipitch_bits); + speex_bits_pack(bits, best_gain_index, params->gain_bits); +#ifdef FIXED_POINT + *cumul_gain = MULT16_32_Q13(SHL16(params->gain_cdbk[4*best_gain_index+3],8), MAX32(1024,*cumul_gain)); +#else + *cumul_gain = 0.03125*MAX32(1024,*cumul_gain)*params->gain_cdbk[4*best_gain_index+3]; +#endif + /*printf ("%f\n", cumul_gain);*/ + /*printf ("encode pitch: %d %d\n", best_pitch, best_gain_index);*/ + SPEEX_COPY(exc, best_exc, nsf); + SPEEX_COPY(target, best_target, nsf); +#ifdef FIXED_POINT + /* Scale target back up if needed */ + if (scaledown) + { + for (i=0;igain_bits; + gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset; + + pitch = speex_bits_unpack_unsigned(bits, params->pitch_bits); + pitch += start; + gain_index = speex_bits_unpack_unsigned(bits, params->gain_bits); + /*printf ("decode pitch: %d %d\n", pitch, gain_index);*/ +#ifdef FIXED_POINT + gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4]); + gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+1]); + gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+2]); +#else + gain[0] = 0.015625*gain_cdbk[gain_index*4]+.5; + gain[1] = 0.015625*gain_cdbk[gain_index*4+1]+.5; + gain[2] = 0.015625*gain_cdbk[gain_index*4+2]+.5; +#endif + + if (count_lost && pitch > subframe_offset) + { + spx_word16_t gain_sum; + if (1) { +#ifdef FIXED_POINT + spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : SHR16(last_pitch_gain,1); + if (tmp>62) + tmp=62; +#else + spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : 0.5 * last_pitch_gain; + if (tmp>.95) + tmp=.95; +#endif + gain_sum = gain_3tap_to_1tap(gain); + + if (gain_sum > tmp) + { + spx_word16_t fact = DIV32_16(SHL32(EXTEND32(tmp),14),gain_sum); + for (i=0;i<3;i++) + gain[i]=MULT16_16_Q14(fact,gain[i]); + } + + } + + } + + *pitch_val = pitch; + gain_val[0]=gain[0]; + gain_val[1]=gain[1]; + gain_val[2]=gain[2]; + gain[0] = SHL16(gain[0],7); + gain[1] = SHL16(gain[1],7); + gain[2] = SHL16(gain[2],7); + SPEEX_MEMSET(exc_out, 0, nsf); + for (i=0;i<3;i++) + { + int j; + int tmp1, tmp3; + int pp=pitch+1-i; + tmp1=nsf; + if (tmp1>pp) + tmp1=pp; + for (j=0;jpp+pitch) + tmp3=pp+pitch; + for (j=tmp1;j63) + pitch_coef=63; +#else + if (pitch_coef>.99) + pitch_coef=.99; +#endif + for (i=0;i63) + pitch_coef=63; +#else + if (pitch_coef>.99) + pitch_coef=.99; +#endif + for (i=0;i0 ? g[0] : -SHR16(g[0],1)) + (g[2]>0 ? g[2] : -SHR16(g[2],1))) +#else +#define gain_3tap_to_1tap(g) (ABS(g[1]) + (g[0]>0 ? g[0] : -.5*g[0]) + (g[2]>0 ? g[2] : -.5*g[2])) +#endif + +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len); + +void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack); + + +/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */ +int pitch_search_3tap( +spx_word16_t target[], /* Target vector */ +spx_word16_t *sw, +spx_coef_t ak[], /* LPCs for this subframe */ +spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Overlapping codebook */ +const void *par, +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +spx_word16_t *exc2, +spx_word16_t *r, +int complexity, +int cdbk_offset, +int plc_tuning, +spx_word32_t *cumul_gain +); + +/*Unquantize adaptive codebook and update pitch contribution*/ +void pitch_unquant_3tap( +spx_word16_t exc[], /* Input excitation */ +spx_word32_t exc_out[], /* Output excitation */ +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +const void *par, +int nsf, /* Number of samples in subframe */ +int *pitch_val, +spx_word16_t *gain_val, +SpeexBits *bits, +char *stack, +int lost, +int subframe_offset, +spx_word16_t last_pitch_gain, +int cdbk_offset +); + +/** Forced pitch delay and gain */ +int forced_pitch_quant( +spx_word16_t target[], /* Target vector */ +spx_word16_t *sw, +spx_coef_t ak[], /* LPCs for this subframe */ +spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ +spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ +spx_sig_t exc[], /* Excitation */ +const void *par, +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +int p, /* Number of LPC coeffs */ +int nsf, /* Number of samples in subframe */ +SpeexBits *bits, +char *stack, +spx_word16_t *exc2, +spx_word16_t *r, +int complexity, +int cdbk_offset, +int plc_tuning, +spx_word32_t *cumul_gain +); + +/** Unquantize forced pitch delay and gain */ +void forced_pitch_unquant( +spx_word16_t exc[], /* Input excitation */ +spx_word32_t exc_out[], /* Output excitation */ +int start, /* Smallest pitch value allowed */ +int end, /* Largest pitch value allowed */ +spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ +const void *par, +int nsf, /* Number of samples in subframe */ +int *pitch_val, +spx_word16_t *gain_val, +SpeexBits *bits, +char *stack, +int lost, +int subframe_offset, +spx_word16_t last_pitch_gain, +int cdbk_offset +); + +#endif /* LTP_H */ diff --git a/native/codec/libraries/speex/libspeex/ltp_arm4.h b/native/codec/libraries/speex/libspeex/ltp_arm4.h new file mode 100644 index 0000000..cdb94e6 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/ltp_arm4.h @@ -0,0 +1,187 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file ltp_arm4.h + @brief Long-Term Prediction functions (ARM4 version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_INNER_PROD +spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len) +{ + spx_word32_t sum1=0,sum2=0; + spx_word16_t *deadx, *deady; + int deadlen, dead1, dead2, dead3, dead4, dead5, dead6; + __asm__ __volatile__ ( + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + ".inner_prod_loop%=:\n" + "\tsub %7, %7, %7\n" + "\tsub %10, %10, %10\n" + + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + "\tldrsh %8, [%0], #2 \n" + "\tldrsh %9, [%1], #2 \n" + "\tmla %7, %5, %6, %7\n" + "\tldrsh %5, [%0], #2 \n" + "\tldrsh %6, [%1], #2 \n" + "\tmla %10, %8, %9, %10\n" + + "\tsubs %4, %4, #1\n" + "\tadd %2, %2, %7, asr #5\n" + "\tadd %3, %3, %10, asr #5\n" + "\tbne .inner_prod_loop%=\n" + : "=r" (deadx), "=r" (deady), "+r" (sum1), "+r" (sum2), + "=r" (deadlen), "=r" (dead1), "=r" (dead2), "=r" (dead3), + "=r" (dead4), "=r" (dead5), "=r" (dead6) + : "0" (x), "1" (y), "4" (len>>3) + : "cc" + ); + return (sum1+sum2)>>1; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + int i,j; + for (i=0;i>> 6;\n\t" + "R0 = A0;\n\t" + "%0 = R0;\n\t" + : "=m" (sum) + : "m" (x), "m" (y), "d" (len-1) + : "P0", "P1", "P2", "R0", "R1", "A0", "I0", "I1", "L0", "L1", "R3", "ASTAT" BFIN_HWLOOP0_REGS + ); + return sum; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack) +{ + corr += nb_pitch - 1; + __asm__ __volatile__ ( + "P2 = %0;\n\t" + "I0 = P2;\n\t" /* x in I0 */ + "B0 = P2;\n\t" /* x in B0 */ + "R0 = %3;\n\t" /* len in R0 */ + "P3 = %3;\n\t" + "P3 += -2;\n\t" /* len in R0 */ + "P4 = %4;\n\t" /* nb_pitch in R0 */ + "R1 = R0 << 1;\n\t" /* number of bytes in x */ + "L0 = R1;\n\t" + "P0 = %1;\n\t" + + "P1 = %2;\n\t" + "B1 = P1;\n\t" + "L1 = 0;\n\t" /*Disable looping on I1*/ + + "r0 = [I0++];\n\t" + "LOOP pitch%= LC0 = P4 >> 1;\n\t" + "LOOP_BEGIN pitch%=;\n\t" + "I1 = P0;\n\t" + "A1 = A0 = 0;\n\t" + "R1 = [I1++];\n\t" + "LOOP inner_prod%= LC1 = P3 >> 1;\n\t" + "LOOP_BEGIN inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t" + "LOOP_END inner_prod%=;\n\t" + "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t" + "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R0 = [I0++];\n\t" + "A0 = A0 >>> 6;\n\t" + "A1 = A1 >>> 6;\n\t" + "R2 = A0, R3 = A1;\n\t" + "[P1--] = r2;\n\t" + "[P1--] = r3;\n\t" + "P0 += 4;\n\t" + "LOOP_END pitch%=;\n\t" + "L0 = 0;\n\t" + : : "m" (_x), "m" (_y), "m" (corr), "m" (len), "m" (nb_pitch) + : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "I0", "I1", "L0", "L1", "B0", "B1", "memory", + "ASTAT" BFIN_HWLOOP0_REGS BFIN_HWLOOP1_REGS + ); +} + +#define OVERRIDE_COMPUTE_PITCH_ERROR +static inline spx_word32_t compute_pitch_error(spx_word16_t *C, spx_word16_t *g, spx_word16_t pitch_control) +{ + spx_word32_t sum; + __asm__ __volatile__ + ( + "A0 = 0;\n\t" + + "R0 = W[%1++];\n\t" + "R1.L = %2.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %3.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%5.L (IS);\n\t" + "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %2.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%2.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %2.L*%2.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %3.L*%3.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" + + "R1.L = %4.L*%4.L (IS);\n\t" + "A0 -= R1.L*R0.L (IS);\n\t" + + "%0 = A0;\n\t" + : "=&D" (sum), "=a" (C) + : "d" (g[0]), "d" (g[1]), "d" (g[2]), "d" (pitch_control), "1" (C) + : "R0", "R1", "R2", "A0", "ASTAT" + ); + return sum; +} + +#define OVERRIDE_OPEN_LOOP_NBEST_PITCH +#ifdef OVERRIDE_OPEN_LOOP_NBEST_PITCH +void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack) +{ + int i,j,k; + VARDECL(spx_word32_t *best_score); + VARDECL(spx_word32_t *best_ener); + spx_word32_t e0; + VARDECL(spx_word32_t *corr); + VARDECL(spx_word32_t *energy); + + ALLOC(best_score, N, spx_word32_t); + ALLOC(best_ener, N, spx_word32_t); + ALLOC(corr, end-start+1, spx_word32_t); + ALLOC(energy, end-start+2, spx_word32_t); + + for (i=0;i>>= 6;\n\t" +" R1 = R1 + R2;\n\t" +" R0 >>>= 6;\n\t" +" R1 = R1 - R0;\n\t" +" R2 = MAX(R1,R3);\n\t" +"eu2: [P0++] = R2;\n\t" + : : "d" (energy), "d" (&sw[-start-1]), "d" (&sw[-start+len-1]), + "a" (end-start) + : "P0", "I1", "I2", "R0", "R1", "R2", "R3", "ASTAT" BFIN_HWLOOP1_REGS + ); + + pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack); + + /* FIXME: Fixed-point and floating-point code should be merged */ + { + VARDECL(spx_word16_t *corr16); + VARDECL(spx_word16_t *ener16); + ALLOC(corr16, end-start+1, spx_word16_t); + ALLOC(ener16, end-start+1, spx_word16_t); + /* Normalize to 180 so we can square it and it still fits in 16 bits */ + normalize16(corr, corr16, 180, end-start+1); + normalize16(energy, ener16, 180, end-start+1); + + if (N == 1) { + /* optimised asm to handle N==1 case */ + __asm__ __volatile__ + ( +" I0 = %1;\n\t" /* I0: corr16[] */ +" L0 = 0;\n\t" +" I1 = %2;\n\t" /* I1: energy */ +" L1 = 0;\n\t" +" R2 = -1;\n\t" /* R2: best score */ +" R3 = 0;\n\t" /* R3: best energy */ +" P0 = %4;\n\t" /* P0: best pitch */ +" P1 = %4;\n\t" /* P1: counter */ +" LSETUP (sl1, sl2) LC1 = %3;\n\t" +"sl1: R0.L = W [I0++] || R1.L = W [I1++];\n\t" +" R0 = R0.L * R0.L (IS);\n\t" +" R1 += 1;\n\t" +" R4 = R0.L * R3.L;\n\t" +" R5 = R2.L * R1.L;\n\t" +" cc = R5 < R4;\n\t" +" if cc R2 = R0;\n\t" +" if cc R3 = R1;\n\t" +" if cc P0 = P1;\n\t" +"sl2: P1 += 1;\n\t" +" %0 = P0;\n\t" + : "=&d" (pitch[0]) + : "a" (corr16), "a" (ener16), "a" (end+1-start), "d" (start) + : "P0", "P1", "I0", "I1", "R0", "R1", "R2", "R3", "R4", "R5", + "ASTAT", "CC" BFIN_HWLOOP1_REGS + ); + + } + else { + for (i=start;i<=end;i++) + { + spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]); + /* Instead of dividing the tmp by the energy, we multiply on the other side */ + if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) + { + /* We can safely put it last and then check */ + best_score[N-1]=tmp; + best_ener[N-1]=ener16[i-start]+1; + pitch[N-1]=i; + /* Check if it comes in front of others */ + for (j=0;jMULT16_16(best_score[j],ADD16(1,ener16[i-start]))) + { + for (k=N-1;k>j;k--) + { + best_score[k]=best_score[k-1]; + best_ener[k]=best_ener[k-1]; + pitch[k]=pitch[k-1]; + } + best_score[j]=tmp; + best_ener[j]=ener16[i-start]+1; + pitch[j]=i; + break; + } + } + } + } + } + } + + /* Compute open-loop gain */ + if (gain) + { + for (j=0;jbest_sum && gain_sum<=max_gain) ------ (1) + + if (sum>best_sum && !(gain_sum>max_gain)) ------ (2) + + if (max_gain<=gain_sum) { ------ (3) + sum = -VERY_LARGE32; + } + if (best_sum<=sum) + + The blackin cc instructions are all of the form: + + cc = x < y (or cc = x <= y) +*/ +" R1 = B0\n\t" +" R2 = %5\n\t" +" R3 = %6\n\t" +" cc = R2 <= R1;\n\t" +" if cc R0 = R3;\n\t" +" cc = %0 <= R0;\n\t" +" if cc %0 = R0;\n\t" +" if cc %1 = P1;\n\t" + +"pgs2: P1 += 1;\n\t" + + : "=&d" (best_sum), "=&d" (best_cdbk) + : "a" (gain_cdbk), "a" (C16), "a" (gain_cdbk_size), "a" (max_gain), + "b" (-VERY_LARGE32) + : "R0", "R1", "R2", "R3", "R4", "P0", + "P1", "I1", "L1", "A0", "B0", "CC", "ASTAT" BFIN_HWLOOP1_REGS + ); + + return best_cdbk; +} +#endif + diff --git a/native/codec/libraries/speex/libspeex/ltp_sse.h b/native/codec/libraries/speex/libspeex/ltp_sse.h new file mode 100644 index 0000000..bed6eaa --- /dev/null +++ b/native/codec/libraries/speex/libspeex/ltp_sse.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file ltp_sse.h + @brief Long-Term Prediction functions (SSE version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#define OVERRIDE_INNER_PROD +float inner_prod(const float *a, const float *b, int len) +{ + int i; + float ret; + __m128 sum = _mm_setzero_ps(); + for (i=0;i<(len>>2);i+=2) + { + sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+0), _mm_loadu_ps(b+0))); + sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+4), _mm_loadu_ps(b+4))); + a += 8; + b += 8; + } + sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum)); + sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55)); + _mm_store_ss(&ret, sum); + return ret; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const float *_x, const float *_y, float *corr, int len, int nb_pitch, char *stack) +{ + int i, offset; + VARDECL(__m128 *x); + VARDECL(__m128 *y); + int N, L; + N = len>>2; + L = nb_pitch>>2; + ALLOC(x, N, __m128); + ALLOC(y, N+L, __m128); + for (i=0;i=(spx_int32_t)65536) + { + x >>= 16; + r += 16; + } + if (x>=256) + { + x >>= 8; + r += 8; + } + if (x>=16) + { + x >>= 4; + r += 4; + } + if (x>=4) + { + x >>= 2; + r += 2; + } + if (x>=2) + { + r += 1; + } + return r; +} + +static inline spx_int16_t spx_ilog4(spx_uint32_t x) +{ + int r=0; + if (x>=(spx_int32_t)65536) + { + x >>= 16; + r += 8; + } + if (x>=256) + { + x >>= 8; + r += 4; + } + if (x>=16) + { + x >>= 4; + r += 2; + } + if (x>=4) + { + r += 1; + } + return r; +} + +#ifdef FIXED_POINT + +/** Generate a pseudo-random number */ +static inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) +{ + spx_word32_t res; + *seed = 1664525 * *seed + 1013904223; + res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std); + return EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14)); +} + +/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */ +/*#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4215*/ + +/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */ +#define C0 3634 +#define C1 21173 +#define C2 -12627 +#define C3 4204 + +static inline spx_word16_t spx_sqrt(spx_word32_t x) +{ + int k; + spx_word32_t rt; + k = spx_ilog4(x)-6; + x = VSHR32(x, (k<<1)); + rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +/* log(x) ~= -2.18151 + 4.20592*x - 2.88938*x^2 + 0.86535*x^3 (for .5 < x < 1) */ + + +#define A1 16469 +#define A2 2242 +#define A3 1486 + +static inline spx_word16_t spx_acos(spx_word16_t x) +{ + int s=0; + spx_word16_t ret; + spx_word16_t sq; + if (x<0) + { + s=1; + x = NEG16(x); + } + x = SUB16(16384,x); + + x = x >> 1; + sq = MULT16_16_Q13(x, ADD16(A1, MULT16_16_Q13(x, ADD16(A2, MULT16_16_Q13(x, (A3)))))); + ret = spx_sqrt(SHL32(EXTEND32(sq),13)); + + /*ret = spx_sqrt(67108864*(-1.6129e-04 + 2.0104e+00*f + 2.7373e-01*f*f + 1.8136e-01*f*f*f));*/ + if (s) + ret = SUB16(25736,ret); + return ret; +} + + +#define K1 8192 +#define K2 -4096 +#define K3 340 +#define K4 -10 + +static inline spx_word16_t spx_cos(spx_word16_t x) +{ + spx_word16_t x2; + + if (x<12868) + { + x2 = MULT16_16_P13(x,x); + return ADD32(K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2)))))); + } else { + x = SUB16(25736,x); + x2 = MULT16_16_P13(x,x); + return SUB32(-K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2)))))); + } +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static inline spx_word16_t _spx_cos_pi_2(spx_word16_t x) +{ + spx_word16_t x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2)))))))); +} + +static inline spx_word16_t spx_cos_norm(spx_word32_t x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x14) + return 0x7fffffff; + else if (integer < -15) + return 0; + frac = SHL16(x-SHL16(integer,11),3); + frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac)))))); + return VSHR32(EXTEND32(frac), -integer-2); +} + +/* Input in Q11 format, output in Q16 */ +static inline spx_word32_t spx_exp(spx_word16_t x) +{ + if (x>21290) + return 0x7fffffff; + else if (x<-21290) + return 0; + else + return spx_exp2(MULT16_16_P14(23637,x)); +} +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +static inline spx_word16_t spx_atan01(spx_word16_t x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* Input in Q15, output in Q14 */ +static inline spx_word16_t spx_atan(spx_word32_t x) +{ + if (x <= 32767) + { + return SHR16(spx_atan01(x),1); + } else { + int e = spx_ilog2(x); + if (e>=29) + return 25736; + x = DIV32_16(SHL32(EXTEND32(32767),29-e), EXTRACT16(SHR32(x, e-14))); + return SUB16(25736, SHR16(spx_atan01(x),1)); + } +} +#else + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +#define C1 0.9999932946f +#define C2 -0.4999124376f +#define C3 0.0414877472f +#define C4 -0.0012712095f + + +#define SPX_PI_2 1.5707963268 +static inline spx_word16_t spx_cos(spx_word16_t x) +{ + if (x>2)-1), "0" (src), "1" (dest) + : "R0", "I0", "L0", "memory" BFIN_HWLOOP0_REGS + ); + return dest; +} diff --git a/native/codec/libraries/speex/libspeex/modes.c b/native/codec/libraries/speex/libspeex/modes.c new file mode 100644 index 0000000..88e431a --- /dev/null +++ b/native/codec/libraries/speex/libspeex/modes.c @@ -0,0 +1,390 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: modes.c + + Describes the different modes of the codec + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "sb_celp.h" +#include "nb_celp.h" +#include "vbr.h" +#include "arch.h" +#include + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef DISABLE_ENCODER +#define nb_encoder_init NULL +#define nb_encoder_destroy NULL +#define nb_encode NULL +#define nb_encoder_ctl NULL + +#define split_cb_search_shape_sign NULL +#define noise_codebook_quant NULL +#define pitch_search_3tap NULL +#define forced_pitch_quant NULL +#define lsp_quant_nb NULL +#define lsp_quant_lbr NULL +#endif /* DISABLE_ENCODER */ + +#ifdef DISABLE_DECODER +#define nb_decoder_init NULL +#define nb_decoder_destroy NULL +#define nb_decode NULL +#define nb_decoder_ctl NULL + +#define noise_codebook_unquant NULL +#define split_cb_shape_sign_unquant NULL +#define lsp_unquant_nb NULL +#define lsp_unquant_lbr NULL +#define pitch_unquant_3tap NULL +#define forced_pitch_unquant NULL +#endif /* DISABLE_DECODER */ + +/* Extern declarations for all codebooks we use here */ +extern const signed char gain_cdbk_nb[]; +extern const signed char gain_cdbk_lbr[]; +extern const signed char exc_5_256_table[]; +extern const signed char exc_5_64_table[]; +extern const signed char exc_8_128_table[]; +extern const signed char exc_10_32_table[]; +extern const signed char exc_10_16_table[]; +extern const signed char exc_20_32_table[]; + + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_nb = { + gain_cdbk_nb, + 7, + 7 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_vlbr = { + gain_cdbk_lbr, + 5, + 0 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_lbr = { + gain_cdbk_lbr, + 5, + 7 +}; + +/* Parameters for Long-Term Prediction (LTP)*/ +static const ltp_params ltp_params_med = { + gain_cdbk_lbr, + 5, + 7 +}; + +/* Split-VQ innovation parameters for very low bit-rate narrowband */ +static const split_cb_params split_cb_nb_vlbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + exc_10_16_table, /*shape_cb*/ + 4, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters for very low bit-rate narrowband */ +static const split_cb_params split_cb_nb_ulbr = { + 20, /*subvect_size*/ + 2, /*nb_subvect*/ + exc_20_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters for low bit-rate narrowband */ +static const split_cb_params split_cb_nb_lbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + exc_10_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + + +/* Split-VQ innovation parameters narrowband */ +static const split_cb_params split_cb_nb = { + 5, /*subvect_size*/ + 8, /*nb_subvect*/ + exc_5_64_table, /*shape_cb*/ + 6, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation parameters narrowband */ +static const split_cb_params split_cb_nb_med = { + 8, /*subvect_size*/ + 5, /*nb_subvect*/ + exc_8_128_table, /*shape_cb*/ + 7, /*shape_bits*/ + 0, +}; + +/* Split-VQ innovation for low-band wideband */ +static const split_cb_params split_cb_sb = { + 5, /*subvect_size*/ + 8, /*nb_subvect*/ + exc_5_256_table, /*shape_cb*/ + 8, /*shape_bits*/ + 0, +}; + + + +/* 2150 bps "vocoder-like" mode for comfort noise */ +static const SpeexSubmode nb_submode1 = { + 0, + 1, + 0, + 0, + /* LSP quantization */ + lsp_quant_lbr, + lsp_unquant_lbr, + /* No pitch quantization */ + forced_pitch_quant, + forced_pitch_unquant, + NULL, + /* No innovation quantization (noise only) */ + noise_codebook_quant, + noise_codebook_unquant, + NULL, + -1, + 43 +}; + +/* 3.95 kbps very low bit-rate mode */ +static const SpeexSubmode nb_submode8 = { + 0, + 1, + 0, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*No pitch quantization*/ + forced_pitch_quant, + forced_pitch_unquant, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_ulbr, + QCONST16(.5,15), + 79 +}; + +/* 5.95 kbps very low bit-rate mode */ +static const SpeexSubmode nb_submode2 = { + 0, + 0, + 0, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*No pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_vlbr, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_vlbr, + QCONST16(.6,15), + 119 +}; + +/* 8 kbps low bit-rate mode */ +static const SpeexSubmode nb_submode3 = { + -1, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_lbr, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_lbr, + QCONST16(.55,15), + 160 +}; + +/* 11 kbps medium bit-rate mode */ +static const SpeexSubmode nb_submode4 = { + -1, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_lbr, + lsp_unquant_lbr, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_med, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb_med, + QCONST16(.45,15), + 220 +}; + +/* 15 kbps high bit-rate mode */ +static const SpeexSubmode nb_submode5 = { + -1, + 0, + 3, + 0, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb, + QCONST16(.25,15), + 300 +}; + +/* 18.2 high bit-rate mode */ +static const SpeexSubmode nb_submode6 = { + -1, + 0, + 3, + 0, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_sb, + QCONST16(.15,15), + 364 +}; + +/* 24.6 kbps high bit-rate mode */ +static const SpeexSubmode nb_submode7 = { + -1, + 0, + 3, + 1, + /*LSP quantization*/ + lsp_quant_nb, + lsp_unquant_nb, + /*Pitch quantization*/ + pitch_search_3tap, + pitch_unquant_3tap, + <p_params_nb, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, + &split_cb_nb, + QCONST16(.05,15), + 492 +}; + + +/* Default mode for narrowband */ +static const SpeexNBMode nb_mode = { + NB_FRAME_SIZE, /*frameSize*/ + NB_SUBFRAME_SIZE, /*subframeSize*/ + NB_ORDER, /*lpcSize*/ + NB_PITCH_START, /*pitchStart*/ + NB_PITCH_END, /*pitchEnd*/ + QCONST16(0.92,15), /* gamma1 */ + QCONST16(0.6,15), /* gamma2 */ + QCONST16(.0002,15), /*lpc_floor*/ + {NULL, &nb_submode1, &nb_submode2, &nb_submode3, &nb_submode4, &nb_submode5, &nb_submode6, &nb_submode7, + &nb_submode8, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + 5, + {1, 8, 2, 3, 3, 4, 4, 5, 5, 6, 7} +}; + + +/* Default mode for narrowband */ +EXPORT const SpeexMode speex_nb_mode = { + &nb_mode, + nb_mode_query, + "narrowband", + 0, + 4, + nb_encoder_init, + nb_encoder_destroy, + nb_encode, + nb_decoder_init, + nb_decoder_destroy, + nb_decode, + nb_encoder_ctl, + nb_decoder_ctl, +}; + + + +EXPORT int speex_mode_query(const SpeexMode *mode, int request, void *ptr) +{ + return mode->query(mode->mode, request, ptr); +} + +#ifdef FIXED_DEBUG +long long spx_mips=0; +#endif + diff --git a/native/codec/libraries/speex/libspeex/modes.h b/native/codec/libraries/speex/libspeex/modes.h new file mode 100644 index 0000000..0977a57 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/modes.h @@ -0,0 +1,160 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file modes.h + @brief Describes the different modes of the codec +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef MODES_H +#define MODES_H + +#include "speex/speex.h" +#include "arch.h" + +#define NB_SUBMODES 16 +#define NB_SUBMODE_BITS 4 + +#define SB_SUBMODES 8 +#define SB_SUBMODE_BITS 3 + +/* Used internally, NOT TO BE USED in applications */ +/** Used internally*/ +#define SPEEX_GET_PI_GAIN 100 +/** Used internally*/ +#define SPEEX_GET_EXC 101 +/** Used internally*/ +#define SPEEX_GET_INNOV 102 +/** Used internally*/ +#define SPEEX_GET_DTX_STATUS 103 +/** Used internally*/ +#define SPEEX_SET_INNOVATION_SAVE 104 +/** Used internally*/ +#define SPEEX_SET_WIDEBAND 105 + +/** Used internally*/ +#define SPEEX_GET_STACK 106 + + +/** Quantizes LSPs */ +typedef void (*lsp_quant_func)(spx_lsp_t *, spx_lsp_t *, int, SpeexBits *); + +/** Decodes quantized LSPs */ +typedef void (*lsp_unquant_func)(spx_lsp_t *, int, SpeexBits *); + + +/** Long-term predictor quantization */ +typedef int (*ltp_quant_func)(spx_word16_t *, spx_word16_t *, spx_coef_t *, spx_coef_t *, + spx_coef_t *, spx_sig_t *, const void *, int, int, spx_word16_t, + int, int, SpeexBits*, char *, spx_word16_t *, spx_word16_t *, int, int, int, spx_word32_t *); + +/** Long-term un-quantize */ +typedef void (*ltp_unquant_func)(spx_word16_t *, spx_word32_t *, int, int, spx_word16_t, const void *, int, int *, + spx_word16_t *, SpeexBits*, char*, int, int, spx_word16_t, int); + + +/** Innovation quantization function */ +typedef void (*innovation_quant_func)(spx_word16_t *, spx_coef_t *, spx_coef_t *, spx_coef_t *, const void *, int, int, + spx_sig_t *, spx_word16_t *, SpeexBits *, char *, int, int); + +/** Innovation unquantization function */ +typedef void (*innovation_unquant_func)(spx_sig_t *, const void *, int, SpeexBits*, char *, spx_int32_t *); + +/** Description of a Speex sub-mode (wither narrowband or wideband */ +typedef struct SpeexSubmode { + int lbr_pitch; /**< Set to -1 for "normal" modes, otherwise encode pitch using a global pitch and allowing a +- lbr_pitch variation (for low not-rates)*/ + int forced_pitch_gain; /**< Use the same (forced) pitch gain for all sub-frames */ + int have_subframe_gain; /**< Number of bits to use as sub-frame innovation gain */ + int double_codebook; /**< Apply innovation quantization twice for higher quality (and higher bit-rate)*/ + /*LSP functions*/ + lsp_quant_func lsp_quant; /**< LSP quantization function */ + lsp_unquant_func lsp_unquant; /**< LSP unquantization function */ + + /*Long-term predictor functions*/ + ltp_quant_func ltp_quant; /**< Long-term predictor (pitch) quantizer */ + ltp_unquant_func ltp_unquant; /**< Long-term predictor (pitch) un-quantizer */ + const void *ltp_params; /**< Pitch parameters (options) */ + + /*Quantization of innovation*/ + innovation_quant_func innovation_quant; /**< Innovation quantization */ + innovation_unquant_func innovation_unquant; /**< Innovation un-quantization */ + const void *innovation_params; /**< Innovation quantization parameters*/ + + spx_word16_t comb_gain; /**< Gain of enhancer comb filter */ + + int bits_per_frame; /**< Number of bits per frame after encoding*/ +} SpeexSubmode; + +/** Struct defining the encoding/decoding mode*/ +typedef struct SpeexNBMode { + int frameSize; /**< Size of frames used for encoding */ + int subframeSize; /**< Size of sub-frames used for encoding */ + int lpcSize; /**< Order of LPC filter */ + int pitchStart; /**< Smallest pitch value allowed */ + int pitchEnd; /**< Largest pitch value allowed */ + + spx_word16_t gamma1; /**< Perceptual filter parameter #1 */ + spx_word16_t gamma2; /**< Perceptual filter parameter #2 */ + spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */ + + const SpeexSubmode *submodes[NB_SUBMODES]; /**< Sub-mode data for the mode */ + int defaultSubmode; /**< Default sub-mode to use when encoding */ + int quality_map[11]; /**< Mode corresponding to each quality setting */ +} SpeexNBMode; + + +/** Struct defining the encoding/decoding mode for SB-CELP (wideband) */ +typedef struct SpeexSBMode { + const SpeexMode *nb_mode; /**< Embedded narrowband mode */ + int frameSize; /**< Size of frames used for encoding */ + int subframeSize; /**< Size of sub-frames used for encoding */ + int lpcSize; /**< Order of LPC filter */ + spx_word16_t gamma1; /**< Perceptual filter parameter #1 */ + spx_word16_t gamma2; /**< Perceptual filter parameter #1 */ + spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */ + spx_word16_t folding_gain; + + const SpeexSubmode *submodes[SB_SUBMODES]; /**< Sub-mode data for the mode */ + int defaultSubmode; /**< Default sub-mode to use when encoding */ + int low_quality_map[11]; /**< Mode corresponding to each quality setting */ + int quality_map[11]; /**< Mode corresponding to each quality setting */ +#ifndef DISABLE_VBR + const float (*vbr_thresh)[11]; +#endif + int nb_modes; +} SpeexSBMode; + +int speex_encode_native(void *state, spx_word16_t *in, SpeexBits *bits); +int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out); + +int nb_mode_query(const void *mode, int request, void *ptr); +int wb_mode_query(const void *mode, int request, void *ptr); + +#endif diff --git a/native/codec/libraries/speex/libspeex/modes_wb.c b/native/codec/libraries/speex/libspeex/modes_wb.c new file mode 100644 index 0000000..aef5fdf --- /dev/null +++ b/native/codec/libraries/speex/libspeex/modes_wb.c @@ -0,0 +1,322 @@ +/* Copyright (C) 2002-2007 Jean-Marc Valin + File: modes.c + + Describes the wideband modes of the codec + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "sb_celp.h" +#include "nb_celp.h" +#include "vbr.h" +#include "arch.h" +#include +#include "os_support.h" + + +#ifndef NULL +#define NULL 0 +#endif + +#if defined(DISABLE_ENCODER) || defined(DISABLE_WIDEBAND) +#define split_cb_search_shape_sign NULL +#define noise_codebook_quant NULL +#define pitch_search_3tap NULL +#define forced_pitch_quant NULL +#define sb_encoder_init NULL +#define sb_encoder_destroy NULL +#define sb_encode NULL +#define sb_encoder_ctl NULL +#define lsp_quant_high NULL +#endif /* DISABLE_ENCODER */ + +#if defined(DISABLE_DECODER) || defined(DISABLE_WIDEBAND) +#define noise_codebook_unquant NULL +#define split_cb_shape_sign_unquant NULL +#define lsp_unquant_high NULL +#define sb_decoder_init NULL +#define sb_decoder_destroy NULL +#define sb_decode NULL +#define sb_decoder_ctl NULL +#endif /* DISABLE_DECODER */ + +EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; + +extern const signed char hexc_table[]; +extern const signed char hexc_10_32_table[]; + +#ifndef DISABLE_WIDEBAND + +/* Split-VQ innovation for high-band wideband */ +static const split_cb_params split_cb_high = { + 8, /*subvect_size*/ + 5, /*nb_subvect*/ + hexc_table, /*shape_cb*/ + 7, /*shape_bits*/ + 1, +}; + + +/* Split-VQ innovation for high-band wideband */ +static const split_cb_params split_cb_high_lbr = { + 10, /*subvect_size*/ + 4, /*nb_subvect*/ + hexc_10_32_table, /*shape_cb*/ + 5, /*shape_bits*/ + 0, +}; + +#endif + + +static const SpeexSubmode wb_submode1 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*No innovation quantization*/ + NULL, + NULL, + NULL, + -1, + 36 +}; + + +static const SpeexSubmode wb_submode2 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high_lbr, +#endif + -1, + 112 +}; + + +static const SpeexSubmode wb_submode3 = { + 0, + 0, + 1, + 0, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high, +#endif + -1, + 192 +}; + +static const SpeexSubmode wb_submode4 = { + 0, + 0, + 1, + 1, + /*LSP quantization*/ + lsp_quant_high, + lsp_unquant_high, + /*Pitch quantization*/ + NULL, + NULL, + NULL, + /*Innovation quantization*/ + split_cb_search_shape_sign, + split_cb_shape_sign_unquant, +#ifdef DISABLE_WIDEBAND + NULL, +#else + &split_cb_high, +#endif + -1, + 352 +}; + + +/* Split-band wideband CELP mode*/ +static const SpeexSBMode sb_wb_mode = { + &speex_nb_mode, + 160, /*frameSize*/ + 40, /*subframeSize*/ + 8, /*lpcSize*/ +#ifdef FIXED_POINT + 29491, 19661, /* gamma1, gamma2 */ +#else + 0.9, 0.6, /* gamma1, gamma2 */ +#endif + QCONST16(.0002,15), /*lpc_floor*/ + QCONST16(0.9f,15), + {NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4, NULL, NULL, NULL}, + 3, + {1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7}, + {1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4}, +#ifndef DISABLE_VBR + vbr_hb_thresh, +#endif + 5 +}; + + +EXPORT const SpeexMode speex_wb_mode = { + &sb_wb_mode, + wb_mode_query, + "wideband (sub-band CELP)", + 1, + 4, + sb_encoder_init, + sb_encoder_destroy, + sb_encode, + sb_decoder_init, + sb_decoder_destroy, + sb_decode, + sb_encoder_ctl, + sb_decoder_ctl, +}; + + + +/* "Ultra-wideband" mode stuff */ + + + +/* Split-band "ultra-wideband" (32 kbps) CELP mode*/ +static const SpeexSBMode sb_uwb_mode = { + &speex_wb_mode, + 320, /*frameSize*/ + 80, /*subframeSize*/ + 8, /*lpcSize*/ +#ifdef FIXED_POINT + 29491, 19661, /* gamma1, gamma2 */ +#else + 0.9, 0.6, /* gamma1, gamma2 */ +#endif + QCONST16(.0002,15), /*lpc_floor*/ + QCONST16(0.7f,15), + {NULL, &wb_submode1, NULL, NULL, NULL, NULL, NULL, NULL}, + 1, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, +#ifndef DISABLE_VBR + vbr_uhb_thresh, +#endif + 2 +}; + +int wb_mode_query(const void *mode, int request, void *ptr) +{ + const SpeexSBMode *m = (const SpeexSBMode*)mode; + + switch (request) + { + case SPEEX_MODE_FRAME_SIZE: + *((int*)ptr)=2*m->frameSize; + break; + case SPEEX_SUBMODE_BITS_PER_FRAME: + if (*((int*)ptr)==0) + *((int*)ptr) = SB_SUBMODE_BITS+1; + else if (m->submodes[*((int*)ptr)]==NULL) + *((int*)ptr) = -1; + else + *((int*)ptr) = m->submodes[*((int*)ptr)]->bits_per_frame; + break; + default: + speex_warning_int("Unknown wb_mode_query request: ", request); + return -1; + } + return 0; +} + + +EXPORT const SpeexMode speex_uwb_mode = { + &sb_uwb_mode, + wb_mode_query, + "ultra-wideband (sub-band CELP)", + 2, + 4, + sb_encoder_init, + sb_encoder_destroy, + sb_encode, + sb_decoder_init, + sb_decoder_destroy, + sb_decode, + sb_encoder_ctl, + sb_decoder_ctl, +}; + +/* We have defined speex_lib_get_mode() as a macro in speex.h */ +#undef speex_lib_get_mode + +EXPORT const SpeexMode * speex_lib_get_mode (int mode) +{ + if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL; + + return speex_mode_list[mode]; +} + + + diff --git a/native/codec/libraries/speex/libspeex/nb_celp.c b/native/codec/libraries/speex/libspeex/nb_celp.c new file mode 100644 index 0000000..b68d507 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/nb_celp.c @@ -0,0 +1,1821 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: nb_celp.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "nb_celp.h" +#include "lpc.h" +#include "lsp.h" +#include "ltp.h" +#include "quant_lsp.h" +#include "cb_search.h" +#include "filters.h" +#include "stack_alloc.h" +#include "vq.h" +#include "vbr.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" + +#ifdef VORBIS_PSYCHO +#include "vorbis_psy.h" +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define SUBMODE(x) st->submodes[st->submodeID]->x + +/* Default size for the encoder and decoder stack (can be changed at compile time). + This does not apply when using variable-size arrays or alloca. */ +#ifndef NB_ENC_STACK +#define NB_ENC_STACK (8000*sizeof(spx_sig_t)) +#endif + +#ifndef NB_DEC_STACK +#define NB_DEC_STACK (4000*sizeof(spx_sig_t)) +#endif + + +#ifdef FIXED_POINT +static const spx_word32_t ol_gain_table[32]={18900, 25150, 33468, 44536, 59265, 78865, 104946, 139653, 185838, 247297, 329081, 437913, 582736, 775454, 1031906, 1373169, 1827293, 2431601, 3235761, 4305867, 5729870, 7624808, 10146425, 13501971, 17967238, 23909222, 31816294, 42338330, 56340132, 74972501, 99766822, 132760927}; +static const spx_word16_t exc_gain_quant_scal3_bound[7]={1841, 3883, 6051, 8062, 10444, 13580, 18560}; +static const spx_word16_t exc_gain_quant_scal3[8]={1002, 2680, 5086, 7016, 9108, 11781, 15380, 21740}; +static const spx_word16_t exc_gain_quant_scal1_bound[1]={14385}; +static const spx_word16_t exc_gain_quant_scal1[2]={11546, 17224}; + +#define LSP_MARGIN 16 +#define LSP_DELTA1 6553 +#define LSP_DELTA2 1638 + +#else + +static const float exc_gain_quant_scal3_bound[7]={0.112338f, 0.236980f, 0.369316f, 0.492054f, 0.637471f, 0.828874f, 1.132784f}; +static const float exc_gain_quant_scal3[8]={0.061130f, 0.163546f, 0.310413f, 0.428220f, 0.555887f, 0.719055f, 0.938694f, 1.326874f}; +static const float exc_gain_quant_scal1_bound[1]={0.87798f}; +static const float exc_gain_quant_scal1[2]={0.70469f, 1.05127f}; + +#define LSP_MARGIN .002f +#define LSP_DELTA1 .2f +#define LSP_DELTA2 .05f + +#endif + +#ifdef VORBIS_PSYCHO +#define EXTRA_BUFFER 100 +#else +#define EXTRA_BUFFER 0 +#endif + + +extern const spx_word16_t lag_window[]; +extern const spx_word16_t lpc_window[]; + +#ifndef DISABLE_ENCODER +void *nb_encoder_init(const SpeexMode *m) +{ + EncState *st; + const SpeexNBMode *mode; + int i; + + mode=(const SpeexNBMode *)m->mode; + st = (EncState*)speex_alloc(sizeof(EncState)); + if (!st) + return NULL; +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + st->stack = (char*)speex_alloc_scratch(NB_ENC_STACK); +#endif + + st->mode=m; + + st->gamma1=mode->gamma1; + st->gamma2=mode->gamma2; + st->lpc_floor = mode->lpc_floor; + + st->submodes=mode->submodes; + st->submodeID=st->submodeSelect=mode->defaultSubmode; + st->bounded_pitch = 1; + + st->encode_submode = 1; + +#ifdef VORBIS_PSYCHO + st->psy = vorbis_psy_init(8000, 256); + st->curve = (float*)speex_alloc(128*sizeof(float)); + st->old_curve = (float*)speex_alloc(128*sizeof(float)); + st->psy_window = (float*)speex_alloc(256*sizeof(float)); +#endif + + st->cumul_gain = 1024; + + st->window= lpc_window; + + /* Create the window for autocorrelation (lag-windowing) */ + st->lagWindow = lag_window; + + st->first = 1; + for (i=0;iold_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), NB_ORDER+1); + + st->innov_rms_save = NULL; + +#ifndef DISABLE_VBR + vbr_init(&st->vbr); + st->vbr_quality = 8; + st->vbr_enabled = 0; + st->vbr_max = 0; + st->vad_enabled = 0; + st->dtx_enabled = 0; + st->dtx_count=0; + st->abr_enabled = 0; + st->abr_drift = 0; + st->abr_drift2 = 0; +#endif /* #ifndef DISABLE_VBR */ + + st->plc_tuning = 2; + st->complexity=2; + st->sampling_rate=8000; + st->isWideband = 0; + st->highpass_enabled = 1; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, NB_ENC_STACK); +#endif + return st; +} + +void nb_encoder_destroy(void *state) +{ + EncState *st=(EncState *)state; + /* Free all allocated memory */ +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + speex_free_scratch(st->stack); +#endif + +#ifndef DISABLE_VBR + vbr_destroy(&st->vbr); +#endif /* #ifndef DISABLE_VBR */ + +#ifdef VORBIS_PSYCHO + vorbis_psy_destroy(st->psy); + speex_free (st->curve); + speex_free (st->old_curve); + speex_free (st->psy_window); +#endif + + /*Free state memory... should be last*/ + speex_free(st); +} + + +int nb_encoder_ctl(void *state, int request, void *ptr) +{ + EncState *st; + st=(EncState*)state; + switch(request) + { + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = NB_FRAME_SIZE; + break; + case SPEEX_SET_LOW_MODE: + case SPEEX_SET_MODE: + st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_LOW_MODE: + case SPEEX_GET_MODE: + (*(spx_int32_t*)ptr) = st->submodeID; + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR: + st->vbr_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VBR: + (*(spx_int32_t*)ptr) = st->vbr_enabled; + break; + case SPEEX_SET_VAD: + st->vad_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VAD: + (*(spx_int32_t*)ptr) = st->vad_enabled; + break; + case SPEEX_SET_DTX: + st->dtx_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_DTX: + (*(spx_int32_t*)ptr) = st->dtx_enabled; + break; + case SPEEX_SET_ABR: + st->abr_enabled = (*(spx_int32_t*)ptr); + st->vbr_enabled = st->abr_enabled!=0; + if (st->vbr_enabled) + { + spx_int32_t i=10; + spx_int32_t rate, target; + float vbr_qual; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + vbr_qual=i; + if (vbr_qual<0) + vbr_qual=0; + speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_qual); + st->abr_count=0; + st->abr_drift=0; + st->abr_drift2=0; + } + + break; + case SPEEX_GET_ABR: + (*(spx_int32_t*)ptr) = st->abr_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ +#if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) + case SPEEX_SET_VBR_QUALITY: + st->vbr_quality = (*(float*)ptr); + break; + case SPEEX_GET_VBR_QUALITY: + (*(float*)ptr) = st->vbr_quality; + break; +#endif /* !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) */ + case SPEEX_SET_QUALITY: + { + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeSelect = st->submodeID = ((const SpeexNBMode*)(st->mode->mode))->quality_map[quality]; + } + break; + case SPEEX_SET_COMPLEXITY: + st->complexity = (*(spx_int32_t*)ptr); + if (st->complexity<0) + st->complexity=0; + break; + case SPEEX_GET_COMPLEXITY: + (*(spx_int32_t*)ptr) = st->complexity; + break; + case SPEEX_SET_BITRATE: + { + spx_int32_t i=10; + spx_int32_t rate, target; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + } + break; + case SPEEX_GET_BITRATE: + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/NB_FRAME_SIZE; + else + (*(spx_int32_t*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/NB_FRAME_SIZE; + break; + case SPEEX_SET_SAMPLING_RATE: + st->sampling_rate = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_RESET_STATE: + { + int i; + st->bounded_pitch = 1; + st->first = 1; + for (i=0;iold_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), NB_ORDER+1); + for (i=0;imem_sw[i]=st->mem_sw_whole[i]=st->mem_sp[i]=st->mem_exc[i]=0; + for (i=0;iexcBuf[i]=st->swBuf[i]=0; + for (i=0;iwinBuf[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + (*(spx_int32_t*)ptr)=(NB_WINDOW_SIZE-NB_FRAME_SIZE); + break; + case SPEEX_SET_PLC_TUNING: + st->plc_tuning = (*(spx_int32_t*)ptr); + if (st->plc_tuning>100) + st->plc_tuning=100; + break; + case SPEEX_GET_PLC_TUNING: + (*(spx_int32_t*)ptr)=(st->plc_tuning); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR_MAX_BITRATE: + st->vbr_max = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_VBR_MAX_BITRATE: + (*(spx_int32_t*)ptr) = st->vbr_max; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_HIGHPASS: + st->highpass_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_HIGHPASS: + (*(spx_int32_t*)ptr) = st->highpass_enabled; + break; + + /* This is all internal stuff past this point */ + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;ipi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;iexc+i*NB_SUBFRAME_SIZE, NB_SUBFRAME_SIZE); + } + break; +#ifndef DISABLE_VBR + case SPEEX_GET_RELATIVE_QUALITY: + (*(float*)ptr)=st->relative_quality; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_INNOVATION_SAVE: + st->innov_rms_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + st->isWideband = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + + +int nb_encode(void *state, void *vin, SpeexBits *bits) +{ + EncState *st; + int i, sub, roots; + int ol_pitch; + spx_word16_t ol_pitch_coef; + spx_word32_t ol_gain; + VARDECL(spx_word16_t *target); + VARDECL(spx_sig_t *innov); + VARDECL(spx_word32_t *exc32); + VARDECL(spx_mem_t *mem); + VARDECL(spx_coef_t *bw_lpc1); + VARDECL(spx_coef_t *bw_lpc2); + VARDECL(spx_coef_t *lpc); + VARDECL(spx_lsp_t *lsp); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_lsp); + VARDECL(spx_lsp_t *interp_qlsp); + VARDECL(spx_coef_t *interp_lpc); + VARDECL(spx_coef_t *interp_qlpc); + char *stack; + VARDECL(spx_word16_t *syn_resp); + + spx_word32_t ener=0; + spx_word16_t fine_gain; + spx_word16_t *in = (spx_word16_t*)vin; + + st=(EncState *)state; + stack=st->stack; + + ALLOC(lpc, NB_ORDER, spx_coef_t); + ALLOC(bw_lpc1, NB_ORDER, spx_coef_t); + ALLOC(bw_lpc2, NB_ORDER, spx_coef_t); + ALLOC(lsp, NB_ORDER, spx_lsp_t); + ALLOC(qlsp, NB_ORDER, spx_lsp_t); + ALLOC(interp_lsp, NB_ORDER, spx_lsp_t); + ALLOC(interp_qlsp, NB_ORDER, spx_lsp_t); + ALLOC(interp_lpc, NB_ORDER, spx_coef_t); + ALLOC(interp_qlpc, NB_ORDER, spx_coef_t); + + st->exc = st->excBuf + NB_PITCH_END + 2; + st->sw = st->swBuf + NB_PITCH_END + 2; + /* Move signals 1 frame towards the past */ + SPEEX_MOVE(st->excBuf, st->excBuf+NB_FRAME_SIZE, NB_PITCH_END+2); + SPEEX_MOVE(st->swBuf, st->swBuf+NB_FRAME_SIZE, NB_PITCH_END+2); + + if (st->highpass_enabled) + highpass(in, in, NB_FRAME_SIZE, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_INPUT, st->mem_hp); + + { + VARDECL(spx_word16_t *w_sig); + VARDECL(spx_word16_t *autocorr); + ALLOC(w_sig, NB_WINDOW_SIZE, spx_word16_t); + ALLOC(autocorr, NB_ORDER+1, spx_word16_t); + /* Window for analysis */ + for (i=0;iwinBuf[i],st->window[i]); + for (;iwindow[i]); + /* Compute auto-correlation */ + _spx_autocorr(w_sig, autocorr, NB_ORDER+1, NB_WINDOW_SIZE); + autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ + + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i=0;ilagWindow[i]); + autocorr[0] = ADD16(autocorr[0],1); + + /* Levinson-Durbin */ + _spx_lpc(lpc, autocorr, NB_ORDER); + /* LPC to LSPs (x-domain) transform */ + roots=lpc_to_lsp (lpc, NB_ORDER, lsp, 10, LSP_DELTA1, stack); + /* Check if we found all the roots */ + if (roots!=NB_ORDER) + { + /*If we can't find all LSP's, do some damage control and use previous filter*/ + for (i=0;iold_lsp[i]; + } + } + } + + + + + /* Whole frame analysis (open-loop estimation of pitch and excitation gain) */ + { + int diff = NB_WINDOW_SIZE-NB_FRAME_SIZE; + if (st->first) + for (i=0;iold_lsp, lsp, interp_lsp, NB_ORDER, NB_NB_SUBFRAMES, NB_NB_SUBFRAMES<<1, LSP_MARGIN); + + /* Compute interpolated LPCs (unquantized) for whole frame*/ + lsp_to_lpc(interp_lsp, interp_lpc, NB_ORDER,stack); + + + /*Open-loop pitch*/ + if (!st->submodes[st->submodeID] || (st->complexity>2 && SUBMODE(have_subframe_gain)<3) || SUBMODE(forced_pitch_gain) || SUBMODE(lbr_pitch) != -1 +#ifndef DISABLE_VBR + || st->vbr_enabled || st->vad_enabled +#endif + ) + { + int nol_pitch[6]; + spx_word16_t nol_pitch_coef[6]; + + bw_lpc(0.9, interp_lpc, bw_lpc1, NB_ORDER); + bw_lpc(0.55, interp_lpc, bw_lpc2, NB_ORDER); + + SPEEX_COPY(st->sw, st->winBuf, diff); + SPEEX_COPY(st->sw+diff, in, NB_FRAME_SIZE-diff); + filter10(st->sw, bw_lpc1, bw_lpc2, st->sw, NB_FRAME_SIZE, st->mem_sw_whole, stack); + + open_loop_nbest_pitch(st->sw, NB_PITCH_START, NB_PITCH_END, NB_FRAME_SIZE, + nol_pitch, nol_pitch_coef, 6, stack); + ol_pitch=nol_pitch[0]; + ol_pitch_coef = nol_pitch_coef[0]; + /*Try to remove pitch multiples*/ + for (i=1;i<6;i++) + { +#ifdef FIXED_POINT + if ((nol_pitch_coef[i]>MULT16_16_Q15(nol_pitch_coef[0],27853)) && +#else + if ((nol_pitch_coef[i]>.85*nol_pitch_coef[0]) && +#endif + (ABS(2*nol_pitch[i]-ol_pitch)<=2 || ABS(3*nol_pitch[i]-ol_pitch)<=3 || + ABS(4*nol_pitch[i]-ol_pitch)<=4 || ABS(5*nol_pitch[i]-ol_pitch)<=5)) + { + /*ol_pitch_coef=nol_pitch_coef[i];*/ + ol_pitch = nol_pitch[i]; + } + } + /*if (ol_pitch>50) + ol_pitch/=2;*/ + /*ol_pitch_coef = sqrt(ol_pitch_coef);*/ + + } else { + ol_pitch=0; + ol_pitch_coef=0; + } + + /*Compute "real" excitation*/ + /*SPEEX_COPY(st->exc, st->winBuf, diff); + SPEEX_COPY(st->exc+diff, in, NB_FRAME_SIZE-diff);*/ + fir_mem16(st->winBuf, interp_lpc, st->exc, diff, NB_ORDER, st->mem_exc, stack); + fir_mem16(in, interp_lpc, st->exc+diff, NB_FRAME_SIZE-diff, NB_ORDER, st->mem_exc, stack); + + /* Compute open-loop excitation gain */ + { + spx_word16_t g = compute_rms16(st->exc, NB_FRAME_SIZE); + if (st->submodeID!=1 && ol_pitch>0) + ol_gain = MULT16_16(g, MULT16_16_Q14(QCONST16(1.1,14), + spx_sqrt(QCONST32(1.,28)-MULT16_32_Q15(QCONST16(.8,15),SHL32(MULT16_16(ol_pitch_coef,ol_pitch_coef),16))))); + else + ol_gain = SHL32(EXTEND32(g),SIG_SHIFT); + } + } + +#ifdef VORBIS_PSYCHO + SPEEX_MOVE(st->psy_window, st->psy_window+NB_FRAME_SIZE, 256-NB_FRAME_SIZE); + SPEEX_COPY(&st->psy_window[256-NB_FRAME_SIZE], in, NB_FRAME_SIZE); + compute_curve(st->psy, st->psy_window, st->curve); + /*print_vec(st->curve, 128, "curve");*/ + if (st->first) + SPEEX_COPY(st->old_curve, st->curve, 128); +#endif + + /*VBR stuff*/ +#ifndef DISABLE_VBR + if (st->vbr_enabled||st->vad_enabled) + { + float lsp_dist=0; + for (i=0;iold_lsp[i] - lsp[i])*(st->old_lsp[i] - lsp[i]); + lsp_dist /= LSP_SCALING*LSP_SCALING; + + if (st->abr_enabled) + { + float qual_change=0; + if (st->abr_drift2 * st->abr_drift > 0) + { + /* Only adapt if long-term and short-term drift are the same sign */ + qual_change = -.00001*st->abr_drift/(1+st->abr_count); + if (qual_change>.05) + qual_change=.05; + if (qual_change<-.05) + qual_change=-.05; + } + st->vbr_quality += qual_change; + if (st->vbr_quality>10) + st->vbr_quality=10; + if (st->vbr_quality<0) + st->vbr_quality=0; + } + + st->relative_quality = vbr_analysis(&st->vbr, in, NB_FRAME_SIZE, ol_pitch, GAIN_SCALING_1*ol_pitch_coef); + /*if (delta_qual<0)*/ + /* delta_qual*=.1*(3+st->vbr_quality);*/ + if (st->vbr_enabled) + { + spx_int32_t mode; + int choice=0; + float min_diff=100; + mode = 8; + while (mode) + { + int v1; + float thresh; + v1=(int)floor(st->vbr_quality); + if (v1==10) + thresh = vbr_nb_thresh[mode][v1]; + else + thresh = (st->vbr_quality-v1)*vbr_nb_thresh[mode][v1+1] + (1+v1-st->vbr_quality)*vbr_nb_thresh[mode][v1]; + if (st->relative_quality > thresh && + st->relative_quality-threshrelative_quality-thresh; + } + mode--; + } + mode=choice; + if (mode==0) + { + if (st->dtx_count==0 || lsp_dist>.05 || !st->dtx_enabled || st->dtx_count>20) + { + mode=1; + st->dtx_count=1; + } else { + mode=0; + st->dtx_count++; + } + } else { + st->dtx_count=0; + } + + speex_encoder_ctl(state, SPEEX_SET_MODE, &mode); + if (st->vbr_max>0) + { + spx_int32_t rate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &rate); + if (rate > st->vbr_max) + { + rate = st->vbr_max; + speex_encoder_ctl(state, SPEEX_SET_BITRATE, &rate); + } + } + + if (st->abr_enabled) + { + spx_int32_t bitrate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate); + st->abr_drift+=(bitrate-st->abr_enabled); + st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled); + st->abr_count += 1.0; + } + + } else { + /*VAD only case*/ + int mode; + if (st->relative_quality<2) + { + if (st->dtx_count==0 || lsp_dist>.05 || !st->dtx_enabled || st->dtx_count>20) + { + st->dtx_count=1; + mode=1; + } else { + mode=0; + st->dtx_count++; + } + } else { + st->dtx_count = 0; + mode=st->submodeSelect; + } + /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/ + st->submodeID=mode; + } + } else { + st->relative_quality = -1; + } +#endif /* #ifndef DISABLE_VBR */ + + if (st->encode_submode) + { + /* First, transmit a zero for narrowband */ + speex_bits_pack(bits, 0, 1); + + /* Transmit the sub-mode we use for this frame */ + speex_bits_pack(bits, st->submodeID, NB_SUBMODE_BITS); + + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + for (i=0;iexc[i]=st->sw[i]=VERY_SMALL; + + for (i=0;imem_sw[i]=0; + st->first=1; + st->bounded_pitch = 1; + + SPEEX_COPY(st->winBuf, in+2*NB_FRAME_SIZE-NB_WINDOW_SIZE, NB_WINDOW_SIZE-NB_FRAME_SIZE); + + /* Clear memory (no need to really compute it) */ + for (i=0;imem_sp[i] = 0; + return 0; + + } + + /* LSP Quantization */ + if (st->first) + { + for (i=0;iold_lsp[i] = lsp[i]; + } + + + /*Quantize LSPs*/ +#if 1 /*0 for unquantized*/ + SUBMODE(lsp_quant)(lsp, qlsp, NB_ORDER, bits); +#else + for (i=0;i15) + quant=15; + if (quant<0) + quant=0; + speex_bits_pack(bits, quant, 4); + ol_pitch_coef=MULT16_16_P15(QCONST16(0.066667,15),SHL16(quant,GAIN_SHIFT)); + } + + + /*Quantize and transmit open-loop excitation gain*/ +#ifdef FIXED_POINT + { + int qe = scal_quant32(ol_gain, ol_gain_table, 32); + /*ol_gain = exp(qe/3.5)*SIG_SCALING;*/ + ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]); + speex_bits_pack(bits, qe, 5); + } +#else + { + int qe = (int)(floor(.5+3.5*log(ol_gain*1.0/SIG_SCALING))); + if (qe<0) + qe=0; + if (qe>31) + qe=31; + ol_gain = exp(qe/3.5)*SIG_SCALING; + speex_bits_pack(bits, qe, 5); + } +#endif + + + + /* Special case for first frame */ + if (st->first) + { + for (i=0;iold_qlsp[i] = qlsp[i]; + } + + /* Target signal */ + ALLOC(target, NB_SUBFRAME_SIZE, spx_word16_t); + ALLOC(innov, NB_SUBFRAME_SIZE, spx_sig_t); + ALLOC(exc32, NB_SUBFRAME_SIZE, spx_word32_t); + ALLOC(syn_resp, NB_SUBFRAME_SIZE, spx_word16_t); + ALLOC(mem, NB_ORDER, spx_mem_t); + + /* Loop on sub-frames */ + for (sub=0;subexc+offset; + /* Weighted signal */ + sw=st->sw+offset; + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_lsp, lsp, interp_lsp, NB_ORDER, sub, NB_NB_SUBFRAMES, LSP_MARGIN); + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, NB_ORDER, sub, NB_NB_SUBFRAMES, LSP_MARGIN); + + /* Compute interpolated LPCs (quantized and unquantized) */ + lsp_to_lpc(interp_lsp, interp_lpc, NB_ORDER,stack); + + lsp_to_lpc(interp_qlsp, interp_qlpc, NB_ORDER, stack); + + /* Compute analysis filter gain at w=pi (for use in SB-CELP) */ + { + spx_word32_t pi_g=LPC_SCALING; + for (i=0;iinterp_qlpc[i] + st->interp_qlpc[i+1];*/ + pi_g = ADD32(pi_g, SUB32(EXTEND32(interp_qlpc[i+1]),EXTEND32(interp_qlpc[i]))); + } + st->pi_gain[sub] = pi_g; + } + +#ifdef VORBIS_PSYCHO + { + float curr_curve[128]; + float fact = ((float)sub+1.0f)/NB_NB_SUBFRAMES; + for (i=0;i<128;i++) + curr_curve[i] = (1.0f-fact)*st->old_curve[i] + fact*st->curve[i]; + curve_to_lpc(st->psy, curr_curve, bw_lpc1, bw_lpc2, 10); + } +#else + /* Compute bandwidth-expanded (unquantized) LPCs for perceptual weighting */ + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, NB_ORDER); + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, NB_ORDER); + /*print_vec(st->bw_lpc1, 10, "bw_lpc");*/ +#endif + + /*FIXME: This will break if we change the window size */ + speex_assert(NB_WINDOW_SIZE-NB_FRAME_SIZE == NB_SUBFRAME_SIZE); + if (sub==0) + inBuf = st->winBuf; + else + inBuf = &in[((sub-1)*NB_SUBFRAME_SIZE)]; + for (i=0;icomplexity==0) + response_bound >>= 1; + compute_impulse_response(interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, response_bound, NB_ORDER, stack); + for (i=response_bound;imem_sp[i],1); + for (i=0;imem_sw[i],1); + filter10(exc, st->bw_lpc1, st->bw_lpc2, exc, response_bound, mem, stack); + SPEEX_MEMSET(&exc[response_bound], 0, NB_SUBFRAME_SIZE-response_bound); +#else + iir_mem16(exc, interp_qlpc, exc, NB_SUBFRAME_SIZE, NB_ORDER, mem, stack); + for (i=0;imem_sw[i],1); + filter10(exc, bw_lpc1, bw_lpc2, exc, NB_SUBFRAME_SIZE, mem, stack); +#endif + + /* Compute weighted signal */ + for (i=0;imem_sw[i]; + filter10(sw, bw_lpc1, bw_lpc2, sw, NB_SUBFRAME_SIZE, mem, stack); + + if (st->complexity==0) + for (i=0;imem_sw[i]=mem[i]; + + /* Compute target signal (saturation prevents overflows on clipped input speech) */ + for (i=0;imem_exc2, stack); + /* If we have a long-term predictor (otherwise, something's wrong) */ + speex_assert (SUBMODE(ltp_quant)); + { + int pit_min, pit_max; + /* Long-term prediction */ + if (SUBMODE(lbr_pitch) != -1) + { + /* Low bit-rate pitch handling */ + int margin; + margin = SUBMODE(lbr_pitch); + if (margin) + { + if (ol_pitch < NB_PITCH_START+margin-1) + ol_pitch=NB_PITCH_START+margin-1; + if (ol_pitch > NB_PITCH_END-margin) + ol_pitch=NB_PITCH_END-margin; + pit_min = ol_pitch-margin+1; + pit_max = ol_pitch+margin; + } else { + pit_min=pit_max=ol_pitch; + } + } else { + pit_min = NB_PITCH_START; + pit_max = NB_PITCH_END; + } + + /* Force pitch to use only the current frame if needed */ + if (st->bounded_pitch && pit_max>offset) + pit_max=offset; + + /* Perform pitch search */ + pitch = SUBMODE(ltp_quant)(target, sw, interp_qlpc, bw_lpc1, bw_lpc2, + exc32, SUBMODE(ltp_params), pit_min, pit_max, ol_pitch_coef, + NB_ORDER, NB_SUBFRAME_SIZE, bits, stack, + exc, syn_resp, st->complexity, 0, st->plc_tuning, &st->cumul_gain); + + st->pitch[sub]=pitch; + } + /* Quantization of innovation */ + SPEEX_MEMSET(innov, 0, NB_SUBFRAME_SIZE); + + /* FIXME: Make sure this is safe from overflows (so far so good) */ + for (i=0;icomplexity, SUBMODE(double_codebook)); + + /* De-normalize innovation and update excitation */ + signal_mul(innov, innov, ener, NB_SUBFRAME_SIZE); + + /* In some (rare) modes, we do a second search (more bits) to reduce noise even more */ + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, NB_SUBFRAME_SIZE, spx_sig_t); + SPEEX_MEMSET(innov2, 0, NB_SUBFRAME_SIZE); + for (i=0;icomplexity, 0); + signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), NB_SUBFRAME_SIZE); + for (i=0;iinnov_rms_save) + st->innov_rms_save[sub] = compute_rms(innov, NB_SUBFRAME_SIZE); + } + + /* Final signal synthesis from excitation */ + iir_mem16(exc, interp_qlpc, sw, NB_SUBFRAME_SIZE, NB_ORDER, st->mem_sp, stack); + + /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ + if (st->complexity!=0) + filter10(sw, bw_lpc1, bw_lpc2, sw, NB_SUBFRAME_SIZE, st->mem_sw, stack); + + } + + /* Store the LSPs for interpolation in the next frame */ + if (st->submodeID>=1) + { + for (i=0;iold_lsp[i] = lsp[i]; + for (i=0;iold_qlsp[i] = qlsp[i]; + } + +#ifdef VORBIS_PSYCHO + if (st->submodeID>=1) + SPEEX_COPY(st->old_curve, st->curve, 128); +#endif + + if (st->submodeID==1) + { +#ifndef DISABLE_VBR + if (st->dtx_count) + speex_bits_pack(bits, 15, 4); + else +#endif + speex_bits_pack(bits, 0, 4); + } + + /* The next frame will not be the first (Duh!) */ + st->first = 0; + SPEEX_COPY(st->winBuf, in+2*NB_FRAME_SIZE-NB_WINDOW_SIZE, NB_WINDOW_SIZE-NB_FRAME_SIZE); + + if (SUBMODE(innovation_quant) == noise_codebook_quant || st->submodeID==0) + st->bounded_pitch = 1; + else + st->bounded_pitch = 0; + + return 1; +} +#endif /* DISABLE_ENCODER */ + + +#ifndef DISABLE_DECODER +void *nb_decoder_init(const SpeexMode *m) +{ + DecState *st; + const SpeexNBMode *mode; + int i; + + mode=(const SpeexNBMode*)m->mode; + st = (DecState *)speex_alloc(sizeof(DecState)); + if (!st) + return NULL; +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + st->stack = (char*)speex_alloc_scratch(NB_DEC_STACK); +#endif + + st->mode=m; + + + st->encode_submode = 1; + + st->first=1; + /* Codec parameters, should eventually have several "modes"*/ + + st->submodes=mode->submodes; + st->submodeID=mode->defaultSubmode; + + st->lpc_enh_enabled=1; + + SPEEX_MEMSET(st->excBuf, 0, NB_FRAME_SIZE + NB_PITCH_END); + + st->last_pitch = 40; + st->count_lost=0; + st->pitch_gain_buf[0] = st->pitch_gain_buf[1] = st->pitch_gain_buf[2] = 0; + st->pitch_gain_buf_idx = 0; + st->seed = 1000; + + st->sampling_rate=8000; + st->last_ol_gain = 0; + + st->user_callback.func = &speex_default_user_handler; + st->user_callback.data = NULL; + for (i=0;i<16;i++) + st->speex_callbacks[i].func = NULL; + + st->voc_m1=st->voc_m2=st->voc_mean=0; + st->voc_offset=0; + st->dtx_enabled=0; + st->isWideband = 0; + st->highpass_enabled = 1; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, NB_DEC_STACK); +#endif + return st; +} + +void nb_decoder_destroy(void *state) +{ +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + DecState *st; + st=(DecState*)state; + + speex_free_scratch(st->stack); +#endif + + speex_free(state); +} + +int nb_decoder_ctl(void *state, int request, void *ptr) +{ + DecState *st; + st=(DecState*)state; + switch(request) + { + case SPEEX_SET_LOW_MODE: + case SPEEX_SET_MODE: + st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_LOW_MODE: + case SPEEX_GET_MODE: + (*(spx_int32_t*)ptr) = st->submodeID; + break; + case SPEEX_SET_ENH: + st->lpc_enh_enabled = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_ENH: + *((spx_int32_t*)ptr) = st->lpc_enh_enabled; + break; + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = NB_FRAME_SIZE; + break; + case SPEEX_GET_BITRATE: + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/NB_FRAME_SIZE; + else + (*(spx_int32_t*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/NB_FRAME_SIZE; + break; + case SPEEX_SET_SAMPLING_RATE: + st->sampling_rate = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_SET_HANDLER: + { + SpeexCallback *c = (SpeexCallback*)ptr; + st->speex_callbacks[c->callback_id].func=c->func; + st->speex_callbacks[c->callback_id].data=c->data; + st->speex_callbacks[c->callback_id].callback_id=c->callback_id; + } + break; + case SPEEX_SET_USER_HANDLER: + { + SpeexCallback *c = (SpeexCallback*)ptr; + st->user_callback.func=c->func; + st->user_callback.data=c->data; + st->user_callback.callback_id=c->callback_id; + } + break; + case SPEEX_RESET_STATE: + { + int i; + for (i=0;imem_sp[i]=0; + for (i=0;iexcBuf[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + (*(spx_int32_t*)ptr)=NB_SUBFRAME_SIZE; + break; + case SPEEX_SET_HIGHPASS: + st->highpass_enabled = (*(spx_int32_t*)ptr); + break; + case SPEEX_GET_HIGHPASS: + (*(spx_int32_t*)ptr) = st->highpass_enabled; + break; + /* FIXME: Convert to fixed-point and re-enable even when float API is disabled */ +#ifndef DISABLE_FLOAT_API + case SPEEX_GET_ACTIVITY: + { + float ret; + ret = log(st->level/st->min_level)/log(st->max_level/st->min_level); + if (ret>1) + ret = 1; + /* Done in a strange way to catch NaNs as well */ + if (!(ret > 0)) + ret = 0; + /*printf ("%f %f %f %f\n", st->level, st->min_level, st->max_level, ret);*/ + (*(spx_int32_t*)ptr) = (int)(100*ret); + } + break; +#endif + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;ipi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;iexc+i*NB_SUBFRAME_SIZE, NB_SUBFRAME_SIZE); + } + break; + case SPEEX_GET_DTX_STATUS: + *((spx_int32_t*)ptr) = st->dtx_enabled; + break; + case SPEEX_SET_INNOVATION_SAVE: + st->innov_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + st->isWideband = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + + +#define median3(a, b, c) ((a) < (b) ? ((b) < (c) ? (b) : ((a) < (c) ? (c) : (a))) : ((c) < (b) ? (b) : ((c) < (a) ? (c) : (a)))) + +#ifdef FIXED_POINT +const spx_word16_t attenuation[10] = {32767, 31483, 27923, 22861, 17278, 12055, 7764, 4616, 2533, 1283}; +#else +const spx_word16_t attenuation[10] = {1., 0.961, 0.852, 0.698, 0.527, 0.368, 0.237, 0.141, 0.077, 0.039}; + +#endif + +static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack) +{ + int i; + int pitch_val; + spx_word16_t pitch_gain; + spx_word16_t fact; + spx_word16_t gain_med; + spx_word16_t innov_gain; + spx_word16_t noise_gain; + + st->exc = st->excBuf + 2*NB_PITCH_END + NB_SUBFRAME_SIZE + 6; + + if (st->count_lost<10) + fact = attenuation[st->count_lost]; + else + fact = 0; + + gain_med = median3(st->pitch_gain_buf[0], st->pitch_gain_buf[1], st->pitch_gain_buf[2]); + if (gain_med < st->last_pitch_gain) + st->last_pitch_gain = gain_med; + +#ifdef FIXED_POINT + pitch_gain = st->last_pitch_gain; + if (pitch_gain>54) + pitch_gain = 54; + pitch_gain = SHL16(pitch_gain, 9); +#else + pitch_gain = GAIN_SCALING_1*st->last_pitch_gain; + if (pitch_gain>.85) + pitch_gain=.85; +#endif + pitch_gain = MULT16_16_Q15(fact,pitch_gain) + VERY_SMALL; + /* FIXME: This was rms of innovation (not exc) */ + innov_gain = compute_rms16(st->exc, NB_FRAME_SIZE); + noise_gain = MULT16_16_Q15(innov_gain, MULT16_16_Q15(fact, SUB16(Q15ONE,MULT16_16_Q15(pitch_gain,pitch_gain)))); + /* Shift all buffers by one frame */ + SPEEX_MOVE(st->excBuf, st->excBuf+NB_FRAME_SIZE, 2*NB_PITCH_END + NB_SUBFRAME_SIZE + 12); + + + pitch_val = st->last_pitch + SHR32((spx_int32_t)speex_rand(1+st->count_lost, &st->seed),SIG_SHIFT); + if (pitch_val > NB_PITCH_END) + pitch_val = NB_PITCH_END; + if (pitch_val < NB_PITCH_START) + pitch_val = NB_PITCH_START; + for (i=0;iexc[i]= MULT16_16_Q15(pitch_gain, (st->exc[i-pitch_val]+VERY_SMALL)) + + speex_rand(noise_gain, &st->seed); + } + + bw_lpc(QCONST16(.98,15), st->interp_qlpc, st->interp_qlpc, NB_ORDER); + iir_mem16(&st->exc[-NB_SUBFRAME_SIZE], st->interp_qlpc, out, NB_FRAME_SIZE, + NB_ORDER, st->mem_sp, stack); + highpass(out, out, NB_FRAME_SIZE, HIGHPASS_NARROWBAND|HIGHPASS_OUTPUT, st->mem_hp); + + st->first = 0; + st->count_lost++; + st->pitch_gain_buf[st->pitch_gain_buf_idx++] = PSHR16(pitch_gain,9); + if (st->pitch_gain_buf_idx > 2) /* rollover */ + st->pitch_gain_buf_idx = 0; +} + +/* Just so we don't need to carry the complete wideband mode information */ +static const int wb_skip_table[8] = {0, 36, 112, 192, 352, 0, 0, 0}; + +int nb_decode(void *state, SpeexBits *bits, void *vout) +{ + DecState *st; + int i, sub; + int pitch; + spx_word16_t pitch_gain[3]; + spx_word32_t ol_gain=0; + int ol_pitch=0; + spx_word16_t ol_pitch_coef=0; + int best_pitch=40; + spx_word16_t best_pitch_gain=0; + int wideband; + int m; + char *stack; + VARDECL(spx_sig_t *innov); + VARDECL(spx_word32_t *exc32); + VARDECL(spx_coef_t *ak); + VARDECL(spx_lsp_t *qlsp); + spx_word16_t pitch_average=0; + + spx_word16_t *out = (spx_word16_t*)vout; + VARDECL(spx_lsp_t *interp_qlsp); + + st=(DecState*)state; + stack=st->stack; + + st->exc = st->excBuf + 2*NB_PITCH_END + NB_SUBFRAME_SIZE + 6; + + /* Check if we're in DTX mode*/ + if (!bits && st->dtx_enabled) + { + st->submodeID=0; + } else + { + /* If bits is NULL, consider the packet to be lost (what could we do anyway) */ + if (!bits) + { + nb_decode_lost(st, out, stack); + return 0; + } + + if (st->encode_submode) + { + + /* Search for next narrowband block (handle requests, skip wideband blocks) */ + do { + if (speex_bits_remaining(bits)<5) + return -1; + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) /* Skip wideband block (for compatibility) */ + { + int submode; + int advance; + advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + /*speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);*/ + advance = wb_skip_table[submode]; + if (advance < 0) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + advance -= (SB_SUBMODE_BITS+1); + speex_bits_advance(bits, advance); + + if (speex_bits_remaining(bits)<5) + return -1; + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) + { + advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + /*speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);*/ + advance = wb_skip_table[submode]; + if (advance < 0) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + advance -= (SB_SUBMODE_BITS+1); + speex_bits_advance(bits, advance); + wideband = speex_bits_unpack_unsigned(bits, 1); + if (wideband) + { + speex_notify("More than two wideband layers found. The stream is corrupted."); + return -2; + } + + } + } + if (speex_bits_remaining(bits)<4) + return -1; + /* FIXME: Check for overflow */ + m = speex_bits_unpack_unsigned(bits, 4); + if (m==15) /* We found a terminator */ + { + return -1; + } else if (m==14) /* Speex in-band request */ + { + int ret = speex_inband_handler(bits, st->speex_callbacks, state); + if (ret) + return ret; + } else if (m==13) /* User in-band request */ + { + int ret = st->user_callback.func(bits, state, st->user_callback.data); + if (ret) + return ret; + } else if (m>8) /* Invalid mode */ + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + + } while (m>8); + + /* Get the sub-mode that was used */ + st->submodeID = m; + } + + } + + /* Shift all buffers by one frame */ + SPEEX_MOVE(st->excBuf, st->excBuf+NB_FRAME_SIZE, 2*NB_PITCH_END + NB_SUBFRAME_SIZE + 12); + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + VARDECL(spx_coef_t *lpc); + ALLOC(lpc, NB_ORDER, spx_coef_t); + bw_lpc(QCONST16(0.93f,15), st->interp_qlpc, lpc, NB_ORDER); + { + spx_word16_t innov_gain=0; + /* FIXME: This was innov, not exc */ + innov_gain = compute_rms16(st->exc, NB_FRAME_SIZE); + for (i=0;iexc[i]=speex_rand(innov_gain, &st->seed); + } + + + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(st->exc, lpc, out, NB_FRAME_SIZE, NB_ORDER, st->mem_sp, stack); + + st->count_lost=0; + return 0; + } + + ALLOC(qlsp, NB_ORDER, spx_lsp_t); + + /* Unquantize LSPs */ + SUBMODE(lsp_unquant)(qlsp, NB_ORDER, bits); + + /*Damp memory if a frame was lost and the LSP changed too much*/ + if (st->count_lost) + { + spx_word16_t fact; + spx_word32_t lsp_dist=0; + for (i=0;iold_qlsp[i] - qlsp[i]))); +#ifdef FIXED_POINT + fact = SHR16(19661,SHR32(lsp_dist,LSP_SHIFT+2)); +#else + fact = .6*exp(-.2*lsp_dist); +#endif + for (i=0;imem_sp[i] = MULT16_32_Q15(fact,st->mem_sp[i]); + } + + + /* Handle first frame and lost-packet case */ + if (st->first || st->count_lost) + { + for (i=0;iold_qlsp[i] = qlsp[i]; + } + + /* Get open-loop pitch estimation for low bit-rate pitch coding */ + if (SUBMODE(lbr_pitch)!=-1) + { + ol_pitch = NB_PITCH_START+speex_bits_unpack_unsigned(bits, 7); + } + + if (SUBMODE(forced_pitch_gain)) + { + int quant; + quant = speex_bits_unpack_unsigned(bits, 4); + ol_pitch_coef=MULT16_16_P15(QCONST16(0.066667,15),SHL16(quant,GAIN_SHIFT)); + } + + /* Get global excitation gain */ + { + int qe; + qe = speex_bits_unpack_unsigned(bits, 5); +#ifdef FIXED_POINT + /* FIXME: Perhaps we could slightly lower the gain here when the output is going to saturate? */ + ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]); +#else + ol_gain = SIG_SCALING*exp(qe/3.5); +#endif + } + + ALLOC(ak, NB_ORDER, spx_coef_t); + ALLOC(innov, NB_SUBFRAME_SIZE, spx_sig_t); + ALLOC(exc32, NB_SUBFRAME_SIZE, spx_word32_t); + + if (st->submodeID==1) + { + int extra; + extra = speex_bits_unpack_unsigned(bits, 4); + + if (extra==15) + st->dtx_enabled=1; + else + st->dtx_enabled=0; + } + if (st->submodeID>1) + st->dtx_enabled=0; + + /*Loop on subframes */ + for (sub=0;subexc+offset; + /* Original signal */ + if (st->innov_save) + innov_save = st->innov_save+offset; + + + /* Reset excitation */ + SPEEX_MEMSET(exc, 0, NB_SUBFRAME_SIZE); + + /*Adaptive codebook contribution*/ + speex_assert (SUBMODE(ltp_unquant)); + { + int pit_min, pit_max; + /* Handle pitch constraints if any */ + if (SUBMODE(lbr_pitch) != -1) + { + int margin; + margin = SUBMODE(lbr_pitch); + if (margin) + { +/* GT - need optimization? + if (ol_pitch < NB_PITCH_START+margin-1) + ol_pitch=NB_PITCH_START+margin-1; + if (ol_pitch > NB_PITCH_END-margin) + ol_pitch=NB_PITCH_END-margin; + pit_min = ol_pitch-margin+1; + pit_max = ol_pitch+margin; +*/ + pit_min = ol_pitch-margin+1; + if (pit_min < NB_PITCH_START) + pit_min = NB_PITCH_START; + pit_max = ol_pitch+margin; + if (pit_max > NB_PITCH_END) + pit_max = NB_PITCH_END; + } else { + pit_min = pit_max = ol_pitch; + } + } else { + pit_min = NB_PITCH_START; + pit_max = NB_PITCH_END; + } + + + + SUBMODE(ltp_unquant)(exc, exc32, pit_min, pit_max, ol_pitch_coef, SUBMODE(ltp_params), + NB_SUBFRAME_SIZE, &pitch, &pitch_gain[0], bits, stack, + st->count_lost, offset, st->last_pitch_gain, 0); + + /* Ensuring that things aren't blowing up as would happen if e.g. an encoder is + crafting packets to make us produce NaNs and slow down the decoder (vague DoS threat). + We can probably be even more aggressive and limit to 15000 or so. */ + sanitize_values32(exc32, NEG32(QCONST32(32000,SIG_SHIFT-1)), QCONST32(32000,SIG_SHIFT-1), NB_SUBFRAME_SIZE); + + tmp = gain_3tap_to_1tap(pitch_gain); + + pitch_average += tmp; + if ((tmp>best_pitch_gain&&ABS(2*best_pitch-pitch)>=3&&ABS(3*best_pitch-pitch)>=4&&ABS(4*best_pitch-pitch)>=5) + || (tmp>MULT16_16_Q15(QCONST16(.6,15),best_pitch_gain)&&(ABS(best_pitch-2*pitch)<3||ABS(best_pitch-3*pitch)<4||ABS(best_pitch-4*pitch)<5)) + || (MULT16_16_Q15(QCONST16(.67,15),tmp)>best_pitch_gain&&(ABS(2*best_pitch-pitch)<3||ABS(3*best_pitch-pitch)<4||ABS(4*best_pitch-pitch)<5)) ) + { + best_pitch = pitch; + if (tmp > best_pitch_gain) + best_pitch_gain = tmp; + } + } + + /* Unquantize the innovation */ + { + int q_energy; + spx_word32_t ener; + + SPEEX_MEMSET(innov, 0, NB_SUBFRAME_SIZE); + + /* Decode sub-frame gain correction */ + if (SUBMODE(have_subframe_gain)==3) + { + q_energy = speex_bits_unpack_unsigned(bits, 3); + ener = MULT16_32_Q14(exc_gain_quant_scal3[q_energy],ol_gain); + } else if (SUBMODE(have_subframe_gain)==1) + { + q_energy = speex_bits_unpack_unsigned(bits, 1); + ener = MULT16_32_Q14(exc_gain_quant_scal1[q_energy],ol_gain); + } else { + ener = ol_gain; + } + + speex_assert (SUBMODE(innovation_unquant)); + { + /*Fixed codebook contribution*/ + SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), NB_SUBFRAME_SIZE, bits, stack, &st->seed); + /* De-normalize innovation and update excitation */ + + signal_mul(innov, innov, ener, NB_SUBFRAME_SIZE); + + /* Decode second codebook (only for some modes) */ + if (SUBMODE(double_codebook)) + { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, NB_SUBFRAME_SIZE, spx_sig_t); + SPEEX_MEMSET(innov2, 0, NB_SUBFRAME_SIZE); + SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), NB_SUBFRAME_SIZE, bits, stack, &st->seed); + signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), NB_SUBFRAME_SIZE); + for (i=0;isubmodeID==1) + { + spx_word16_t g=ol_pitch_coef; + g=MULT16_16_P14(QCONST16(1.5f,14),(g-QCONST16(.2f,6))); + if (g<0) + g=0; + if (g>GAIN_SCALING) + g=GAIN_SCALING; + + SPEEX_MEMSET(exc, 0, NB_SUBFRAME_SIZE); + while (st->voc_offsetvoc_offset]= g*sqrt(2*ol_pitch)*ol_gain; + Not quite sure why we need the factor of two in the sqrt */ + if (st->voc_offset>=0) + exc[st->voc_offset]=MULT16_16(spx_sqrt(MULT16_16_16(2,ol_pitch)),EXTRACT16(PSHR32(MULT16_16(g,PSHR32(ol_gain,SIG_SHIFT)),6))); + st->voc_offset+=ol_pitch; + } + st->voc_offset -= NB_SUBFRAME_SIZE; + + for (i=0;ivoc_m1)), + SUB16(MULT16_16_Q15(Q15_ONE-MULT16_16_16(QCONST16(.85f,9),g),EXTRACT16(PSHR32(innov[i],SIG_SHIFT))), + MULT16_16_Q15(MULT16_16_16(QCONST16(.15f,9),g),EXTRACT16(PSHR32(st->voc_m2,SIG_SHIFT))) + )); + st->voc_m1 = exci; + st->voc_m2=innov[i]; + st->voc_mean = EXTRACT16(PSHR32(ADD32(MULT16_16(QCONST16(.8f,15),st->voc_mean), MULT16_16(QCONST16(.2f,15),exc[i])), 15)); + exc[i]-=st->voc_mean; + } + } + + } + } + + ALLOC(interp_qlsp, NB_ORDER, spx_lsp_t); + + if (st->lpc_enh_enabled && SUBMODE(comb_gain)>0 && !st->count_lost) + { + multicomb(st->exc-NB_SUBFRAME_SIZE, out, st->interp_qlpc, NB_ORDER, 2*NB_SUBFRAME_SIZE, best_pitch, 40, SUBMODE(comb_gain), stack); + multicomb(st->exc+NB_SUBFRAME_SIZE, out+2*NB_SUBFRAME_SIZE, st->interp_qlpc, NB_ORDER, 2*NB_SUBFRAME_SIZE, best_pitch, 40, SUBMODE(comb_gain), stack); + } else { + SPEEX_COPY(out, &st->exc[-NB_SUBFRAME_SIZE], NB_FRAME_SIZE); + } + + /* If the last packet was lost, re-scale the excitation to obtain the same energy as encoded in ol_gain */ + if (st->count_lost) + { + spx_word16_t exc_ener; + spx_word32_t gain32; + spx_word16_t gain; + exc_ener = compute_rms16 (st->exc, NB_FRAME_SIZE); + gain32 = PDIV32(ol_gain, ADD16(exc_ener,1)); +#ifdef FIXED_POINT + if (gain32 > 32767) + gain32 = 32767; + gain = EXTRACT16(gain32); +#else + if (gain32 > 2) + gain32=2; + gain = gain32; +#endif + for (i=0;iexc[i] = MULT16_16_Q14(gain, st->exc[i]); + out[i]=st->exc[i-NB_SUBFRAME_SIZE]; + } + } + + /*Loop on subframes */ + for (sub=0;subold_qlsp, qlsp, interp_qlsp, NB_ORDER, sub, NB_NB_SUBFRAMES, LSP_MARGIN); + + /* Compute interpolated LPCs (unquantized) */ + lsp_to_lpc(interp_qlsp, ak, NB_ORDER, stack); + + /* Compute analysis filter at w=pi */ + { + spx_word32_t pi_g=LPC_SCALING; + for (i=0;iinterp_qlpc[i] + st->interp_qlpc[i+1];*/ + pi_g = ADD32(pi_g, SUB32(EXTEND32(ak[i+1]),EXTEND32(ak[i]))); + } + st->pi_gain[sub] = pi_g; + } + + iir_mem16(sp, st->interp_qlpc, sp, NB_SUBFRAME_SIZE, NB_ORDER, + st->mem_sp, stack); + + for (i=0;iinterp_qlpc[i] = ak[i]; + + } + + if (st->highpass_enabled) + highpass(out, out, NB_FRAME_SIZE, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_OUTPUT, st->mem_hp); + /*for (i=0;iframe[i]);*/ + + /* Tracking output level */ + st->level = 1+PSHR32(ol_gain,SIG_SHIFT); + st->max_level = MAX16(MULT16_16_Q15(QCONST16(.99f,15), st->max_level), st->level); + st->min_level = MIN16(ADD16(1,MULT16_16_Q14(QCONST16(1.01f,14), st->min_level)), st->level); + if (st->max_level < st->min_level+1) + st->max_level = st->min_level+1; + /*printf ("%f %f %f %d\n", og, st->min_level, st->max_level, update);*/ + + /* Store the LSPs for interpolation in the next frame */ + for (i=0;iold_qlsp[i] = qlsp[i]; + + /* The next frame will not be the first (Duh!) */ + st->first = 0; + st->count_lost=0; + st->last_pitch = best_pitch; +#ifdef FIXED_POINT + st->last_pitch_gain = PSHR16(pitch_average,2); +#else + st->last_pitch_gain = .25*pitch_average; +#endif + st->pitch_gain_buf[st->pitch_gain_buf_idx++] = st->last_pitch_gain; + if (st->pitch_gain_buf_idx > 2) /* rollover */ + st->pitch_gain_buf_idx = 0; + + st->last_ol_gain = ol_gain; + + return 0; +} +#endif /* DISABLE_DECODER */ + diff --git a/native/codec/libraries/speex/libspeex/nb_celp.h b/native/codec/libraries/speex/libspeex/nb_celp.h new file mode 100644 index 0000000..a8d3088 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/nb_celp.h @@ -0,0 +1,199 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file nb_celp.h + @brief Narrowband CELP encoder/decoder +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef NB_CELP_H +#define NB_CELP_H + +#include "modes.h" +#include "speex/speex_callbacks.h" +#include "vbr.h" +#include "filters.h" + +#ifdef VORBIS_PSYCHO +#include "vorbis_psy.h" +#endif + +#define NB_ORDER 10 +#define NB_FRAME_SIZE 160 +#define NB_SUBFRAME_SIZE 40 +#define NB_NB_SUBFRAMES 4 +#define NB_PITCH_START 17 +#define NB_PITCH_END 144 + +#define NB_WINDOW_SIZE (NB_FRAME_SIZE+NB_SUBFRAME_SIZE) +#define NB_EXCBUF (NB_FRAME_SIZE+NB_PITCH_END+2) +#define NB_DEC_BUFFER (NB_FRAME_SIZE+2*NB_PITCH_END+NB_SUBFRAME_SIZE+12) +/**Structure representing the full state of the narrowband encoder*/ +typedef struct EncState { + const SpeexMode *mode; /**< Mode corresponding to the state */ + int first; /**< Is this the first frame? */ + + spx_word32_t cumul_gain; /**< Product of previously used pitch gains (Q10) */ + int bounded_pitch; /**< Next frame should not rely on previous frames for pitch */ + int ol_pitch; /**< Open-loop pitch */ + int ol_voiced; /**< Open-loop voiced/non-voiced decision */ + int pitch[NB_NB_SUBFRAMES]; + +#ifdef VORBIS_PSYCHO + VorbisPsy *psy; + float *psy_window; + float *curve; + float *old_curve; +#endif + + spx_word16_t gamma1; /**< Perceptual filter: A(z/gamma1) */ + spx_word16_t gamma2; /**< Perceptual filter: A(z/gamma2) */ + spx_word16_t lpc_floor; /**< Noise floor multiplier for A[0] in LPC analysis*/ + char *stack; /**< Pseudo-stack allocation for temporary memory */ + spx_word16_t winBuf[NB_WINDOW_SIZE-NB_FRAME_SIZE]; /**< Input buffer (original signal) */ + spx_word16_t excBuf[NB_EXCBUF]; /**< Excitation buffer */ + spx_word16_t *exc; /**< Start of excitation frame */ + spx_word16_t swBuf[NB_EXCBUF]; /**< Weighted signal buffer */ + spx_word16_t *sw; /**< Start of weighted signal frame */ + const spx_word16_t *window; /**< Temporary (Hanning) window */ + const spx_word16_t *lagWindow; /**< Window applied to auto-correlation */ + spx_lsp_t old_lsp[NB_ORDER]; /**< LSPs for previous frame */ + spx_lsp_t old_qlsp[NB_ORDER]; /**< Quantized LSPs for previous frame */ + spx_mem_t mem_sp[NB_ORDER]; /**< Filter memory for signal synthesis */ + spx_mem_t mem_sw[NB_ORDER]; /**< Filter memory for perceptually-weighted signal */ + spx_mem_t mem_sw_whole[NB_ORDER]; /**< Filter memory for perceptually-weighted signal (whole frame)*/ + spx_mem_t mem_exc[NB_ORDER]; /**< Filter memory for excitation (whole frame) */ + spx_mem_t mem_exc2[NB_ORDER]; /**< Filter memory for excitation (whole frame) */ + spx_mem_t mem_hp[2]; /**< High-pass filter memory */ + spx_word32_t pi_gain[NB_NB_SUBFRAMES]; /**< Gain of LPC filter at theta=pi (fe/2) */ + spx_word16_t *innov_rms_save; /**< If non-NULL, innovation RMS is copied here */ + +#ifndef DISABLE_VBR + VBRState vbr; /**< State of the VBR data */ + float vbr_quality; /**< Quality setting for VBR encoding */ + float relative_quality; /**< Relative quality that will be needed by VBR */ + spx_int32_t vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ + spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode */ + int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */ + int dtx_enabled; /**< 1 for enabling DTX, 0 otherwise */ + int dtx_count; /**< Number of consecutive DTX frames */ + spx_int32_t abr_enabled; /**< ABR setting (in bps), 0 if off */ + float abr_drift; + float abr_drift2; + float abr_count; +#endif /* #ifndef DISABLE_VBR */ + + int complexity; /**< Complexity setting (0-10 from least complex to most complex) */ + spx_int32_t sampling_rate; + int plc_tuning; + int encode_submode; + const SpeexSubmode * const *submodes; /**< Sub-mode data */ + int submodeID; /**< Activated sub-mode */ + int submodeSelect; /**< Mode chosen by the user (may differ from submodeID if VAD is on) */ + int isWideband; /**< Is this used as part of the embedded wideband codec */ + int highpass_enabled; /**< Is the input filter enabled */ +} EncState; + +/**Structure representing the full state of the narrowband decoder*/ +typedef struct DecState { + const SpeexMode *mode; /**< Mode corresponding to the state */ + int first; /**< Is this the first frame? */ + int count_lost; /**< Was the last frame lost? */ + spx_int32_t sampling_rate; + + spx_word16_t last_ol_gain; /**< Open-loop gain for previous frame */ + + char *stack; /**< Pseudo-stack allocation for temporary memory */ + spx_word16_t excBuf[NB_DEC_BUFFER]; /**< Excitation buffer */ + spx_word16_t *exc; /**< Start of excitation frame */ + spx_lsp_t old_qlsp[NB_ORDER]; /**< Quantized LSPs for previous frame */ + spx_coef_t interp_qlpc[NB_ORDER]; /**< Interpolated quantized LPCs */ + spx_mem_t mem_sp[NB_ORDER]; /**< Filter memory for synthesis signal */ + spx_mem_t mem_hp[2]; /**< High-pass filter memory */ + spx_word32_t pi_gain[NB_NB_SUBFRAMES]; /**< Gain of LPC filter at theta=pi (fe/2) */ + spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ + + spx_word16_t level; + spx_word16_t max_level; + spx_word16_t min_level; + + /* This is used in packet loss concealment */ + int last_pitch; /**< Pitch of last correctly decoded frame */ + spx_word16_t last_pitch_gain; /**< Pitch gain of last correctly decoded frame */ + spx_word16_t pitch_gain_buf[3]; /**< Pitch gain of last decoded frames */ + int pitch_gain_buf_idx; /**< Tail of the buffer */ + spx_int32_t seed; /** Seed used for random number generation */ + + int encode_submode; + const SpeexSubmode * const *submodes; /**< Sub-mode data */ + int submodeID; /**< Activated sub-mode */ + int lpc_enh_enabled; /**< 1 when LPC enhancer is on, 0 otherwise */ + SpeexCallback speex_callbacks[SPEEX_MAX_CALLBACKS]; + + SpeexCallback user_callback; + + /*Vocoder data*/ + spx_word16_t voc_m1; + spx_word32_t voc_m2; + spx_word16_t voc_mean; + int voc_offset; + + int dtx_enabled; + int isWideband; /**< Is this used as part of the embedded wideband codec */ + int highpass_enabled; /**< Is the input filter enabled */ +} DecState; + +/** Initializes encoder state*/ +void *nb_encoder_init(const SpeexMode *m); + +/** De-allocates encoder state resources*/ +void nb_encoder_destroy(void *state); + +/** Encodes one frame*/ +int nb_encode(void *state, void *in, SpeexBits *bits); + + +/** Initializes decoder state*/ +void *nb_decoder_init(const SpeexMode *m); + +/** De-allocates decoder state resources*/ +void nb_decoder_destroy(void *state); + +/** Decodes one frame*/ +int nb_decode(void *state, SpeexBits *bits, void *out); + +/** ioctl-like function for controlling a narrowband encoder */ +int nb_encoder_ctl(void *state, int request, void *ptr); + +/** ioctl-like function for controlling a narrowband decoder */ +int nb_decoder_ctl(void *state, int request, void *ptr); + + +#endif diff --git a/native/codec/libraries/speex/libspeex/os_support.h b/native/codec/libraries/speex/libspeex/os_support.h new file mode 100644 index 0000000..2e23a5e --- /dev/null +++ b/native/codec/libraries/speex/libspeex/os_support.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef OS_SUPPORT_CUSTOM +#include "os_support_custom.h" +#endif + +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free + NOTE: speex_alloc needs to CLEAR THE MEMORY */ +#ifndef OVERRIDE_SPEEX_ALLOC +static inline void *speex_alloc (int size) +{ + /* WARNING: this is not equivalent to malloc(). If you want to use malloc() + or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise + you will experience strange bugs */ + return calloc(size,1); +} +#endif + +/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ +#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH +static inline void *speex_alloc_scratch (int size) +{ + /* Scratch space doesn't need to be cleared */ + return calloc(size,1); +} +#endif + +/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */ +#ifndef OVERRIDE_SPEEX_REALLOC +static inline void *speex_realloc (void *ptr, int size) +{ + return realloc(ptr, size); +} +#endif + +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */ +#ifndef OVERRIDE_SPEEX_FREE +static inline void speex_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ +#ifndef OVERRIDE_SPEEX_FREE_SCRATCH +static inline void speex_free_scratch (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n elements from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_SPEEX_COPY +#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n elements from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_SPEEX_MOVE +#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** For n elements worth of memory, set every byte to the value of c, starting at address dst */ +#ifndef OVERRIDE_SPEEX_MEMSET +#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst)))) +#endif + + +#ifndef OVERRIDE_SPEEX_FATAL +static inline void _speex_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + exit(1); +} +#endif + +#ifndef OVERRIDE_SPEEX_WARNING +static inline void speex_warning(const char *str) +{ +#ifndef DISABLE_WARNINGS + fprintf (stderr, "warning: %s\n", str); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_WARNING_INT +static inline void speex_warning_int(const char *str, int val) +{ +#ifndef DISABLE_WARNINGS + fprintf (stderr, "warning: %s %d\n", str, val); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_NOTIFY +static inline void speex_notify(const char *str) +{ +#ifndef DISABLE_NOTIFICATIONS + fprintf (stderr, "notification: %s\n", str); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_PUTC +/** Speex wrapper for putc */ +static inline void _speex_putc(int ch, void *file) +{ + FILE *f = (FILE *)file; + fprintf(f, "%c", ch); +} +#endif + +#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__); +#define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}} + +#ifndef RELEASE +static inline void print_vec(float *vec, int len, char *name) +{ + int i; + printf ("%s ", name); + for (i=0;i +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include "arch.h" + +#ifdef BFIN_ASM +#include "quant_lsp_bfin.h" +#endif + +#ifdef FIXED_POINT + +#define LSP_LINEAR(i) (SHL16(i+1,11)) +#define LSP_LINEAR_HIGH(i) (ADD16(MULT16_16_16(i,2560),6144)) +#define LSP_DIV_256(x) (SHL16((spx_word16_t)x, 5)) +#define LSP_DIV_512(x) (SHL16((spx_word16_t)x, 4)) +#define LSP_DIV_1024(x) (SHL16((spx_word16_t)x, 3)) +#define LSP_PI 25736 + +#else + +#define LSP_LINEAR(i) (.25*(i)+.25) +#define LSP_LINEAR_HIGH(i) (.3125*(i)+.75) +#define LSP_SCALE 256. +#define LSP_DIV_256(x) (0.0039062*(x)) +#define LSP_DIV_512(x) (0.0019531*(x)) +#define LSP_DIV_1024(x) (0.00097656*(x)) +#define LSP_PI M_PI + +#endif + +#ifndef DISABLE_ENCODER +static void compute_quant_weights(spx_lsp_t *qlsp, spx_word16_t *quant_weight, int order) +{ + int i; + spx_word16_t tmp1, tmp2; + for (i=0;i tmp2 ? tmp1 : tmp2; + }*/ + + for (i=0;i>> 16;\n\t" +" R1 = (A1 += R2.L*R0.H) (IS);\n\t" +"4: R3 = R3 + R1;\n\t" + +" cc =R3<%0;\n\t" +" if cc %0=R3;\n\t" +" if cc %1=R5;\n\t" +"2: R5 += 1;\n\t" +" L0 = 0;\n\t" +" L1 = 0;\n\t" + : "=&d" (best_dist), "=&d" (best_id) + : "a" (x), "a" (weight), "b" (cdbk), "a" (nbVec), "a" (nbDim) + : "I0", "I1", "P2", "R0", "R1", "R2", "R3", "R5", "A1", + "L0", "L1", "B0", "B1", "CC", "ASTAT" BFIN_HWLOOP0_REGS BFIN_HWLOOP1_REGS + ); + + for (j=0;j +#include "sb_celp.h" +#include "filters.h" +#include "lpc.h" +#include "lsp.h" +#include "stack_alloc.h" +#include "cb_search.h" +#include "quant_lsp.h" +#include "vq.h" +#include "ltp.h" +#include "arch.h" +#include "math_approx.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +/* Default size for the encoder and decoder stack (can be changed at compile time). + This does not apply when using variable-size arrays or alloca. */ +#ifndef SB_ENC_STACK +#define SB_ENC_STACK (10000*sizeof(spx_sig_t)) +#endif + +#ifndef SB_DEC_STACK +#define SB_DEC_STACK (6000*sizeof(spx_sig_t)) +#endif + + +#ifndef DISABLE_WIDEBAND + + +#define sqr(x) ((x)*(x)) + +#define SUBMODE(x) st->submodes[st->submodeID]->x + +#ifdef FIXED_POINT +static const spx_word16_t gc_quant_bound[16] = {125, 164, 215, 282, 370, 484, 635, 832, 1090, 1428, 1871, 2452, 3213, 4210, 5516, 7228}; +static const spx_word16_t fold_quant_bound[32] = { + 39, 44, 50, 57, 64, 73, 83, 94, + 106, 120, 136, 154, 175, 198, 225, 255, + 288, 327, 370, 420, 476, 539, 611, 692, + 784, 889, 1007, 1141, 1293, 1465, 1660, 1881}; +#define LSP_MARGIN 410 +#define LSP_DELTA1 6553 +#define LSP_DELTA2 1638 + +#else + +static const spx_word16_t gc_quant_bound[16] = { + 0.97979, 1.28384, 1.68223, 2.20426, 2.88829, 3.78458, 4.95900, 6.49787, + 8.51428, 11.15642, 14.61846, 19.15484, 25.09895, 32.88761, 43.09325, 56.46588}; +static const spx_word16_t fold_quant_bound[32] = { + 0.30498, 0.34559, 0.39161, 0.44375, 0.50283, 0.56979, 0.64565, 0.73162, + 0.82903, 0.93942, 1.06450, 1.20624, 1.36685, 1.54884, 1.75506, 1.98875, + 2.25355, 2.55360, 2.89361, 3.27889, 3.71547, 4.21018, 4.77076, 5.40598, + 6.12577, 6.94141, 7.86565, 8.91295, 10.09969, 11.44445, 12.96826, 14.69497}; + +#define LSP_MARGIN .05 +#define LSP_DELTA1 .2 +#define LSP_DELTA2 .05 + +#endif + +#define QMF_ORDER 64 + +#ifdef FIXED_POINT +static const spx_word16_t h0[64] = {2, -7, -7, 18, 15, -39, -25, 75, 35, -130, -41, 212, 38, -327, -17, 483, -32, -689, 124, 956, -283, -1307, 543, 1780, -973, -2467, 1733, 3633, -3339, -6409, 9059, 30153, 30153, 9059, -6409, -3339, 3633, 1733, -2467, -973, 1780, 543, -1307, -283, 956, 124, -689, -32, 483, -17, -327, 38, 212, -41, -130, 35, 75, -25, -39, 15, 18, -7, -7, 2}; + +#else +static const float h0[64] = { + 3.596189e-05f, -0.0001123515f, + -0.0001104587f, 0.0002790277f, + 0.0002298438f, -0.0005953563f, + -0.0003823631f, 0.00113826f, + 0.0005308539f, -0.001986177f, + -0.0006243724f, 0.003235877f, + 0.0005743159f, -0.004989147f, + -0.0002584767f, 0.007367171f, + -0.0004857935f, -0.01050689f, + 0.001894714f, 0.01459396f, + -0.004313674f, -0.01994365f, + 0.00828756f, 0.02716055f, + -0.01485397f, -0.03764973f, + 0.026447f, 0.05543245f, + -0.05095487f, -0.09779096f, + 0.1382363f, 0.4600981f, + 0.4600981f, 0.1382363f, + -0.09779096f, -0.05095487f, + 0.05543245f, 0.026447f, + -0.03764973f, -0.01485397f, + 0.02716055f, 0.00828756f, + -0.01994365f, -0.004313674f, + 0.01459396f, 0.001894714f, + -0.01050689f, -0.0004857935f, + 0.007367171f, -0.0002584767f, + -0.004989147f, 0.0005743159f, + 0.003235877f, -0.0006243724f, + -0.001986177f, 0.0005308539f, + 0.00113826f, -0.0003823631f, + -0.0005953563f, 0.0002298438f, + 0.0002790277f, -0.0001104587f, + -0.0001123515f, 3.596189e-05f +}; + +#endif + +extern const spx_word16_t lag_window[]; +extern const spx_word16_t lpc_window[]; + +#ifndef DISABLE_ENCODER +void *sb_encoder_init(const SpeexMode *m) +{ + int i; + spx_int32_t tmp; + SBEncState *st; + const SpeexSBMode *mode; + + st = (SBEncState*)speex_alloc(sizeof(SBEncState)); + if (!st) + return NULL; + st->mode = m; + mode = (const SpeexSBMode*)m->mode; + + + st->st_low = speex_encoder_init(mode->nb_mode); +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + /*st->stack = (char*)speex_alloc_scratch(SB_ENC_STACK);*/ + speex_encoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack); +#endif + + st->full_frame_size = 2*mode->frameSize; + st->frame_size = mode->frameSize; + st->subframeSize = mode->subframeSize; + st->nbSubframes = mode->frameSize/mode->subframeSize; + st->windowSize = st->frame_size+st->subframeSize; + st->lpcSize=mode->lpcSize; + + st->encode_submode = 1; + st->submodes=mode->submodes; + st->submodeSelect = st->submodeID=mode->defaultSubmode; + + tmp=9; + speex_encoder_ctl(st->st_low, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp); + + st->lpc_floor = mode->lpc_floor; + st->gamma1=mode->gamma1; + st->gamma2=mode->gamma2; + st->first=1; + + st->high=(spx_word16_t*)speex_alloc((st->windowSize-st->frame_size)*sizeof(spx_word16_t)); + + st->h0_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + + st->window= lpc_window; + + st->lagWindow = lag_window; + + st->old_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); + st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); + st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); + st->innov_rms_save = NULL; + + st->mem_sp = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sp2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + st->mem_sw = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t)); + + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + +#ifndef DISABLE_VBR + st->vbr_quality = 8; + st->vbr_enabled = 0; + st->vbr_max = 0; + st->vbr_max_high = 20000; /* We just need a big value here */ + st->vad_enabled = 0; + st->abr_enabled = 0; + st->relative_quality=0; +#endif /* #ifndef DISABLE_VBR */ + + st->complexity=2; + speex_encoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate); + st->sampling_rate*=2; +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st)); +#endif + return st; +} + +void sb_encoder_destroy(void *state) +{ + SBEncState *st=(SBEncState*)state; + + speex_encoder_destroy(st->st_low); +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + /*speex_free_scratch(st->stack);*/ +#endif + + speex_free(st->high); + + speex_free(st->h0_mem); + + speex_free(st->old_lsp); + speex_free(st->old_qlsp); + speex_free(st->interp_qlpc); + speex_free(st->pi_gain); + speex_free(st->exc_rms); + + speex_free(st->mem_sp); + speex_free(st->mem_sp2); + speex_free(st->mem_sw); + + + speex_free(st); +} + +int sb_encoder_ctl(void *state, int request, void *ptr) +{ + SBEncState *st; + st=(SBEncState*)state; + switch(request) + { + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->full_frame_size; + break; + case SPEEX_SET_HIGH_MODE: + st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_SET_LOW_MODE: + speex_encoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr); + break; + case SPEEX_SET_DTX: + speex_encoder_ctl(st->st_low, SPEEX_SET_DTX, ptr); + break; + case SPEEX_GET_DTX: + speex_encoder_ctl(st->st_low, SPEEX_GET_DTX, ptr); + break; + case SPEEX_GET_LOW_MODE: + speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr); + break; + case SPEEX_SET_MODE: + speex_encoder_ctl(st, SPEEX_SET_QUALITY, ptr); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR: + st->vbr_enabled = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, ptr); + break; + case SPEEX_GET_VBR: + (*(spx_int32_t*)ptr) = st->vbr_enabled; + break; + case SPEEX_SET_VAD: + st->vad_enabled = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_VAD, ptr); + break; + case SPEEX_GET_VAD: + (*(spx_int32_t*)ptr) = st->vad_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ +#if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) + case SPEEX_SET_VBR_QUALITY: + { + spx_int32_t q; + float qual = (*(float*)ptr)+.6; + st->vbr_quality = (*(float*)ptr); + if (qual>10) + qual=10; + q=(int)floor(.5+*(float*)ptr); + if (q>10) + q=10; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_QUALITY, &qual); + speex_encoder_ctl(state, SPEEX_SET_QUALITY, &q); + break; + } + case SPEEX_GET_VBR_QUALITY: + (*(float*)ptr) = st->vbr_quality; + break; +#endif /* #if !defined(DISABLE_VBR) && !defined(DISABLE_FLOAT_API) */ +#ifndef DISABLE_VBR + case SPEEX_SET_ABR: + st->abr_enabled = (*(spx_int32_t*)ptr); + st->vbr_enabled = st->abr_enabled!=0; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, &st->vbr_enabled); + if (st->vbr_enabled) + { + spx_int32_t i=10, rate, target; + float vbr_qual; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + vbr_qual=i; + if (vbr_qual<0) + vbr_qual=0; + speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_qual); + st->abr_count=0; + st->abr_drift=0; + st->abr_drift2=0; + } + + break; + case SPEEX_GET_ABR: + (*(spx_int32_t*)ptr) = st->abr_enabled; + break; +#endif /* #ifndef DISABLE_VBR */ + + case SPEEX_SET_QUALITY: + { + spx_int32_t nb_qual; + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeSelect = st->submodeID = ((const SpeexSBMode*)(st->mode->mode))->quality_map[quality]; + nb_qual = ((const SpeexSBMode*)(st->mode->mode))->low_quality_map[quality]; + speex_encoder_ctl(st->st_low, SPEEX_SET_MODE, &nb_qual); + } + break; + case SPEEX_SET_COMPLEXITY: + speex_encoder_ctl(st->st_low, SPEEX_SET_COMPLEXITY, ptr); + st->complexity = (*(spx_int32_t*)ptr); + if (st->complexity<1) + st->complexity=1; + break; + case SPEEX_GET_COMPLEXITY: + (*(spx_int32_t*)ptr) = st->complexity; + break; + case SPEEX_SET_BITRATE: + { + spx_int32_t i=10; + spx_int32_t rate, target; + target = (*(spx_int32_t*)ptr); + while (i>=0) + { + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i); + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate); + if (rate <= target) + break; + i--; + } + } + break; + case SPEEX_GET_BITRATE: + speex_encoder_ctl(st->st_low, request, ptr); + /*fprintf (stderr, "before: %d\n", (*(int*)ptr));*/ + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) += st->sampling_rate*SUBMODE(bits_per_frame)/st->full_frame_size; + else + (*(spx_int32_t*)ptr) += st->sampling_rate*(SB_SUBMODE_BITS+1)/st->full_frame_size; + /*fprintf (stderr, "after: %d\n", (*(int*)ptr));*/ + break; + case SPEEX_SET_SAMPLING_RATE: + { + spx_int32_t tmp=(*(spx_int32_t*)ptr); + st->sampling_rate = tmp; + tmp>>=1; + speex_encoder_ctl(st->st_low, SPEEX_SET_SAMPLING_RATE, &tmp); + } + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_RESET_STATE: + { + int i; + st->first = 1; + for (i=0;ilpcSize;i++) + st->old_lsp[i]= DIV32(MULT16_16(QCONST16(3.1415927f, LSP_SHIFT), i+1), st->lpcSize+1); + for (i=0;ilpcSize;i++) + st->mem_sw[i]=st->mem_sp[i]=st->mem_sp2[i]=0; + for (i=0;ih0_mem[i]=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + speex_encoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + speex_encoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr); + (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr) + QMF_ORDER - 1; + break; + case SPEEX_SET_PLC_TUNING: + speex_encoder_ctl(st->st_low, SPEEX_SET_PLC_TUNING, ptr); + break; + case SPEEX_GET_PLC_TUNING: + speex_encoder_ctl(st->st_low, SPEEX_GET_PLC_TUNING, ptr); + break; +#ifndef DISABLE_VBR + case SPEEX_SET_VBR_MAX_BITRATE: + { + st->vbr_max = (*(spx_int32_t*)ptr); + if (SPEEX_SET_VBR_MAX_BITRATE<1) + { + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_MAX_BITRATE, &st->vbr_max); + st->vbr_max_high = 17600; + } else { + spx_int32_t low_rate; + if (st->vbr_max >= 42200) + { + st->vbr_max_high = 17600; + } else if (st->vbr_max >= 27800) + { + st->vbr_max_high = 9600; + } else if (st->vbr_max > 20600) + { + st->vbr_max_high = 5600; + } else { + st->vbr_max_high = 1800; + } + if (st->subframeSize==80) + st->vbr_max_high = 1800; + low_rate = st->vbr_max - st->vbr_max_high; + speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_MAX_BITRATE, &low_rate); + } + } + break; + case SPEEX_GET_VBR_MAX_BITRATE: + (*(spx_int32_t*)ptr) = st->vbr_max; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_HIGHPASS: + speex_encoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr); + break; + case SPEEX_GET_HIGHPASS: + speex_encoder_ctl(st->st_low, SPEEX_GET_HIGHPASS, ptr); + break; + + + /* This is all internal stuff past this point */ + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = st->exc_rms[i]; + } + break; +#ifndef DISABLE_VBR + case SPEEX_GET_RELATIVE_QUALITY: + (*(float*)ptr)=st->relative_quality; + break; +#endif /* #ifndef DISABLE_VBR */ + case SPEEX_SET_INNOVATION_SAVE: + st->innov_rms_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + + +int sb_encode(void *state, void *vin, SpeexBits *bits) +{ + SBEncState *st; + int i, roots, sub; + char *stack; + VARDECL(spx_mem_t *mem); + VARDECL(spx_sig_t *innov); + VARDECL(spx_word16_t *target); + VARDECL(spx_word16_t *syn_resp); + VARDECL(spx_word32_t *low_pi_gain); + spx_word16_t *low; + spx_word16_t *high; + VARDECL(spx_word16_t *low_exc_rms); + VARDECL(spx_word16_t *low_innov_rms); + const SpeexSBMode *mode; + spx_int32_t dtx; + spx_word16_t *in = (spx_word16_t*)vin; + spx_word16_t e_low=0, e_high=0; + VARDECL(spx_coef_t *lpc); + VARDECL(spx_coef_t *interp_lpc); + VARDECL(spx_coef_t *bw_lpc1); + VARDECL(spx_coef_t *bw_lpc2); + VARDECL(spx_lsp_t *lsp); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_lsp); + VARDECL(spx_lsp_t *interp_qlsp); + + st = (SBEncState*)state; + stack=st->stack; + mode = (const SpeexSBMode*)(st->mode->mode); + low = in; + high = in+st->frame_size; + + /* High-band buffering / sync with low band */ + /* Compute the two sub-bands by filtering with QMF h0*/ + qmf_decomp(in, h0, low, high, st->full_frame_size, QMF_ORDER, st->h0_mem, stack); + +#ifndef DISABLE_VBR + if (st->vbr_enabled || st->vad_enabled) + { + /* Need to compute things here before the signal is trashed by the encoder */ + /*FIXME: Are the two signals (low, high) in sync? */ + e_low = compute_rms16(low, st->frame_size); + e_high = compute_rms16(high, st->frame_size); + } +#endif /* #ifndef DISABLE_VBR */ + + ALLOC(low_innov_rms, st->nbSubframes, spx_word16_t); + speex_encoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_rms); + /* Encode the narrowband part*/ + speex_encode_native(st->st_low, low, bits); + + high = high - (st->windowSize-st->frame_size); + SPEEX_COPY(high, st->high, st->windowSize-st->frame_size); + SPEEX_COPY(st->high, &high[st->frame_size], st->windowSize-st->frame_size); + + + ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); + ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); + speex_encoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); + speex_encoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); + + speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, &dtx); + + if (dtx==0) + dtx=1; + else + dtx=0; + + ALLOC(lpc, st->lpcSize, spx_coef_t); + ALLOC(interp_lpc, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc1, st->lpcSize, spx_coef_t); + ALLOC(bw_lpc2, st->lpcSize, spx_coef_t); + + ALLOC(lsp, st->lpcSize, spx_lsp_t); + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_lsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + + { + VARDECL(spx_word16_t *autocorr); + VARDECL(spx_word16_t *w_sig); + ALLOC(autocorr, st->lpcSize+1, spx_word16_t); + ALLOC(w_sig, st->windowSize, spx_word16_t); + /* Window for analysis */ + /* FIXME: This is a kludge */ + if (st->subframeSize==80) + { + for (i=0;iwindowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i>>1]),SIG_SHIFT)); + } else { + for (i=0;iwindowSize;i++) + w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i]),SIG_SHIFT)); + } + /* Compute auto-correlation */ + _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize); + autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ + + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i=0;ilpcSize+1;i++) + autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]); + + /* Levinson-Durbin */ + _spx_lpc(lpc, autocorr, st->lpcSize); + } + + /* LPC to LSPs (x-domain) transform */ + roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack); + if (roots!=st->lpcSize) + { + roots = lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA2, stack); + if (roots!=st->lpcSize) { + /*If we can't find all LSP's, do some damage control and use a flat filter*/ + for (i=0;ilpcSize;i++) + { + lsp[i]=st->old_lsp[i]; + } + } + } + +#ifndef DISABLE_VBR + /* VBR code */ + if ((st->vbr_enabled || st->vad_enabled) && !dtx) + { + float ratio; + if (st->abr_enabled) + { + float qual_change=0; + if (st->abr_drift2 * st->abr_drift > 0) + { + /* Only adapt if long-term and short-term drift are the same sign */ + qual_change = -.00001*st->abr_drift/(1+st->abr_count); + if (qual_change>.1) + qual_change=.1; + if (qual_change<-.1) + qual_change=-.1; + } + st->vbr_quality += qual_change; + if (st->vbr_quality>10) + st->vbr_quality=10; + if (st->vbr_quality<0) + st->vbr_quality=0; + } + + + ratio = 2*log((1.f+e_high)/(1.f+e_low)); + + speex_encoder_ctl(st->st_low, SPEEX_GET_RELATIVE_QUALITY, &st->relative_quality); + if (ratio<-4) + ratio=-4; + if (ratio>2) + ratio=2; + /*if (ratio>-2)*/ + if (st->vbr_enabled) + { + spx_int32_t modeid; + modeid = mode->nb_modes-1; + st->relative_quality+=1.0*(ratio+2); + if (st->relative_quality<-1) + st->relative_quality=-1; + while (modeid) + { + int v1; + float thresh; + v1=(int)floor(st->vbr_quality); + if (v1==10) + thresh = mode->vbr_thresh[modeid][v1]; + else + thresh = (st->vbr_quality-v1) * mode->vbr_thresh[modeid][v1+1] + + (1+v1-st->vbr_quality) * mode->vbr_thresh[modeid][v1]; + if (st->relative_quality >= thresh && st->sampling_rate*st->submodes[modeid]->bits_per_frame/st->full_frame_size <= st->vbr_max_high) + break; + modeid--; + } + speex_encoder_ctl(state, SPEEX_SET_HIGH_MODE, &modeid); + if (st->abr_enabled) + { + spx_int32_t bitrate; + speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate); + st->abr_drift+=(bitrate-st->abr_enabled); + st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled); + st->abr_count += 1.0; + } + + } else { + /* VAD only */ + int modeid; + if (st->relative_quality<2.0) + modeid=1; + else + modeid=st->submodeSelect; + /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/ + st->submodeID=modeid; + + } + /*fprintf (stderr, "%f %f\n", ratio, low_qual);*/ + } +#endif /* #ifndef DISABLE_VBR */ + + if (st->encode_submode) + { + speex_bits_pack(bits, 1, 1); + if (dtx) + speex_bits_pack(bits, 0, SB_SUBMODE_BITS); + else + speex_bits_pack(bits, st->submodeID, SB_SUBMODE_BITS); + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (dtx || st->submodes[st->submodeID] == NULL) + { + for (i=0;iframe_size;i++) + high[i]=VERY_SMALL; + + for (i=0;ilpcSize;i++) + st->mem_sw[i]=0; + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(high, st->interp_qlpc, high, st->frame_size, st->lpcSize, st->mem_sp, stack); + + if (dtx) + return 0; + else + return 1; + } + + + /* LSP quantization */ + SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits); + + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + ALLOC(mem, st->lpcSize, spx_mem_t); + ALLOC(syn_resp, st->subframeSize, spx_word16_t); + ALLOC(innov, st->subframeSize, spx_sig_t); + ALLOC(target, st->subframeSize, spx_word16_t); + + for (sub=0;subnbSubframes;sub++) + { + VARDECL(spx_word16_t *exc); + VARDECL(spx_word16_t *res); + VARDECL(spx_word16_t *sw); + spx_word16_t *sp; + spx_word16_t filter_ratio; /*Q7*/ + int offset; + spx_word32_t rl, rh; /*Q13*/ + spx_word16_t eh=0; + + offset = st->subframeSize*sub; + sp=high+offset; + ALLOC(exc, st->subframeSize, spx_word16_t); + ALLOC(res, st->subframeSize, spx_word16_t); + ALLOC(sw, st->subframeSize, spx_word16_t); + + /* LSP interpolation (quantized and unquantized) */ + lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes, LSP_MARGIN); + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes, LSP_MARGIN); + + lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack); + lsp_to_lpc(interp_qlsp, st->interp_qlpc, st->lpcSize, stack); + + bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize); + bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize); + + /* Compute mid-band (4000 Hz for wideband) response of low-band and high-band + filters */ + st->pi_gain[sub]=LPC_SCALING; + rh = LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + rh += st->interp_qlpc[i+1] - st->interp_qlpc[i]; + st->pi_gain[sub] += st->interp_qlpc[i] + st->interp_qlpc[i+1]; + } + + rl = low_pi_gain[sub]; +#ifdef FIXED_POINT + filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767)); +#else + filter_ratio=(rl+.01)/(rh+.01); +#endif + + /* Compute "real excitation" */ + fir_mem16(sp, st->interp_qlpc, exc, st->subframeSize, st->lpcSize, st->mem_sp2, stack); + /* Compute energy of low-band and high-band excitation */ + + eh = compute_rms16(exc, st->subframeSize); + + if (!SUBMODE(innovation_quant)) {/* 1 for spectral folding excitation, 0 for stochastic */ + spx_word32_t g; /*Q7*/ + spx_word16_t el; /*Q0*/ + el = low_innov_rms[sub]; + + /* Gain to use if we want to use the low-band excitation for high-band */ + g=PDIV32(MULT16_16(filter_ratio,eh),EXTEND32(ADD16(1,el))); + +#if 0 + { + char *tmp_stack=stack; + float *tmp_sig; + float g2; + ALLOC(tmp_sig, st->subframeSize, spx_sig_t); + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + iir_mem2(st->low_innov+offset, st->interp_qlpc, tmp_sig, st->subframeSize, st->lpcSize, mem); + g2 = compute_rms(sp, st->subframeSize)/(.01+compute_rms(tmp_sig, st->subframeSize)); + /*fprintf (stderr, "gains: %f %f\n", g, g2);*/ + g = g2; + stack = tmp_stack; + } +#endif + + /*print_vec(&g, 1, "gain factor");*/ + /* Gain quantization */ + { + int quant = scal_quant(g, fold_quant_bound, 32); + /*speex_warning_int("tata", quant);*/ + if (quant<0) + quant=0; + if (quant>31) + quant=31; + speex_bits_pack(bits, quant, 5); + } + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = eh; + } + st->exc_rms[sub] = eh; + } else { + spx_word16_t gc; /*Q7*/ + spx_word32_t scale; /*Q14*/ + spx_word16_t el; /*Q0*/ + el = low_exc_rms[sub]; /*Q0*/ + + gc = PDIV32_16(MULT16_16(filter_ratio,1+eh),1+el); + + /* This is a kludge that cleans up a historical bug */ + if (st->subframeSize==80) + gc = MULT16_16_P15(QCONST16(0.70711f,15),gc); + /*printf ("%f %f %f %f\n", el, eh, filter_ratio, gc);*/ + { + int qgc = scal_quant(gc, gc_quant_bound, 16); + speex_bits_pack(bits, qgc, 4); + gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]); + } + if (st->subframeSize==80) + gc = MULT16_16_P14(QCONST16(1.4142f,14), gc); + + scale = SHL32(MULT16_16(PDIV32_16(SHL32(EXTEND32(gc),SIG_SHIFT-6),filter_ratio),(1+el)),6); + + compute_impulse_response(st->interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, st->subframeSize, st->lpcSize, stack); + + + /* Reset excitation */ + for (i=0;isubframeSize;i++) + res[i]=VERY_SMALL; + + /* Compute zero response (ringing) of A(z/g1) / ( A(z/g2) * Aq(z) ) */ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + iir_mem16(res, st->interp_qlpc, res, st->subframeSize, st->lpcSize, mem, stack); + + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sw[i]; + filter_mem16(res, bw_lpc1, bw_lpc2, res, st->subframeSize, st->lpcSize, mem, stack); + + /* Compute weighted signal */ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sw[i]; + filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack); + + /* Compute target signal */ + for (i=0;isubframeSize;i++) + target[i]=SUB16(sw[i],res[i]); + + signal_div(target, target, scale, st->subframeSize); + + /* Reset excitation */ + SPEEX_MEMSET(innov, 0, st->subframeSize); + + /*print_vec(target, st->subframeSize, "\ntarget");*/ + SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); + /*print_vec(target, st->subframeSize, "after");*/ + + signal_mul(innov, innov, scale, st->subframeSize); + + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + for (i=0;isubframeSize;i++) + target[i]=MULT16_16_P13(QCONST16(2.5f,13), target[i]); + + SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, + SUBMODE(innovation_params), st->lpcSize, st->subframeSize, + innov2, syn_resp, bits, stack, st->complexity, 0); + signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); + + for (i=0;isubframeSize;i++) + innov[i] = ADD32(innov[i],innov2[i]); + stack = tmp_stack; + } + for (i=0;isubframeSize;i++) + exc[i] = PSHR32(innov[i],SIG_SHIFT); + + if (st->innov_rms_save) + { + st->innov_rms_save[sub] = MULT16_16_Q15(QCONST16(.70711f, 15), compute_rms(innov, st->subframeSize)); + } + st->exc_rms[sub] = compute_rms16(exc, st->subframeSize); + + + } + + + /*Keep the previous memory*/ + for (i=0;ilpcSize;i++) + mem[i]=st->mem_sp[i]; + /* Final signal synthesis from excitation */ + iir_mem16(exc, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, st->mem_sp, stack); + + /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ + filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack); + } + + for (i=0;ilpcSize;i++) + st->old_lsp[i] = lsp[i]; + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + + st->first=0; + + return 1; +} + +#endif /* DISABLE_ENCODER */ + + +#ifndef DISABLE_DECODER +void *sb_decoder_init(const SpeexMode *m) +{ + spx_int32_t tmp; + SBDecState *st; + const SpeexSBMode *mode; + st = (SBDecState*)speex_alloc(sizeof(SBDecState)); + if (!st) + return NULL; + st->mode = m; + mode=(const SpeexSBMode*)m->mode; + st->encode_submode = 1; + + st->st_low = speex_decoder_init(mode->nb_mode); +#if defined(VAR_ARRAYS) || defined (USE_ALLOCA) + st->stack = NULL; +#else + /*st->stack = (char*)speex_alloc_scratch(SB_DEC_STACK);*/ + speex_decoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack); +#endif + + st->full_frame_size = 2*mode->frameSize; + st->frame_size = mode->frameSize; + st->subframeSize = mode->subframeSize; + st->nbSubframes = mode->frameSize/mode->subframeSize; + st->lpcSize=mode->lpcSize; + speex_decoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate); + st->sampling_rate*=2; + tmp=1; + speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp); + + st->submodes=mode->submodes; + st->submodeID=mode->defaultSubmode; + + st->first=1; + + st->g0_mem = (spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + st->g1_mem = (spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t)); + + st->excBuf = (spx_word16_t*)speex_alloc((st->subframeSize)*sizeof(spx_word16_t)); + + st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); + st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); + + st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); + st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); + st->mem_sp = (spx_mem_t*)speex_alloc((2*st->lpcSize)*sizeof(spx_mem_t)); + + st->innov_save = NULL; + + + st->lpc_enh_enabled=0; + st->seed = 1000; + +#ifdef ENABLE_VALGRIND + VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st)); +#endif + return st; +} + +void sb_decoder_destroy(void *state) +{ + SBDecState *st; + st = (SBDecState*)state; + speex_decoder_destroy(st->st_low); +#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA)) + /*speex_free_scratch(st->stack);*/ +#endif + + speex_free(st->g0_mem); + speex_free(st->g1_mem); + speex_free(st->excBuf); + speex_free(st->old_qlsp); + speex_free(st->interp_qlpc); + speex_free(st->pi_gain); + speex_free(st->exc_rms); + speex_free(st->mem_sp); + + speex_free(state); +} + + + +int sb_decoder_ctl(void *state, int request, void *ptr) +{ + SBDecState *st; + st=(SBDecState*)state; + switch(request) + { + case SPEEX_SET_HIGH_MODE: + st->submodeID = (*(spx_int32_t*)ptr); + break; + case SPEEX_SET_LOW_MODE: + speex_decoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr); + break; + case SPEEX_GET_LOW_MODE: + speex_decoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr); + break; + case SPEEX_GET_FRAME_SIZE: + (*(spx_int32_t*)ptr) = st->full_frame_size; + break; + case SPEEX_SET_ENH: + speex_decoder_ctl(st->st_low, request, ptr); + st->lpc_enh_enabled = *((spx_int32_t*)ptr); + break; + case SPEEX_GET_ENH: + *((spx_int32_t*)ptr) = st->lpc_enh_enabled; + break; + case SPEEX_SET_MODE: + case SPEEX_SET_QUALITY: + { + spx_int32_t nb_qual; + int quality = (*(spx_int32_t*)ptr); + if (quality < 0) + quality = 0; + if (quality > 10) + quality = 10; + st->submodeID = ((const SpeexSBMode*)(st->mode->mode))->quality_map[quality]; + nb_qual = ((const SpeexSBMode*)(st->mode->mode))->low_quality_map[quality]; + speex_decoder_ctl(st->st_low, SPEEX_SET_MODE, &nb_qual); + } + break; + case SPEEX_GET_BITRATE: + speex_decoder_ctl(st->st_low, request, ptr); + if (st->submodes[st->submodeID]) + (*(spx_int32_t*)ptr) += st->sampling_rate*SUBMODE(bits_per_frame)/st->full_frame_size; + else + (*(spx_int32_t*)ptr) += st->sampling_rate*(SB_SUBMODE_BITS+1)/st->full_frame_size; + break; + case SPEEX_SET_SAMPLING_RATE: + { + spx_int32_t tmp=(*(spx_int32_t*)ptr); + st->sampling_rate = tmp; + tmp>>=1; + speex_decoder_ctl(st->st_low, SPEEX_SET_SAMPLING_RATE, &tmp); + } + break; + case SPEEX_GET_SAMPLING_RATE: + (*(spx_int32_t*)ptr)=st->sampling_rate; + break; + case SPEEX_SET_HANDLER: + speex_decoder_ctl(st->st_low, SPEEX_SET_HANDLER, ptr); + break; + case SPEEX_SET_USER_HANDLER: + speex_decoder_ctl(st->st_low, SPEEX_SET_USER_HANDLER, ptr); + break; + case SPEEX_RESET_STATE: + { + int i; + for (i=0;i<2*st->lpcSize;i++) + st->mem_sp[i]=0; + for (i=0;ig0_mem[i]=st->g1_mem[i]=0; + st->last_ener=0; + } + break; + case SPEEX_SET_SUBMODE_ENCODING: + st->encode_submode = (*(spx_int32_t*)ptr); + speex_decoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr); + break; + case SPEEX_GET_SUBMODE_ENCODING: + (*(spx_int32_t*)ptr) = st->encode_submode; + break; + case SPEEX_GET_LOOKAHEAD: + speex_decoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr); + (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr); + break; + case SPEEX_SET_HIGHPASS: + speex_decoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr); + break; + case SPEEX_GET_HIGHPASS: + speex_decoder_ctl(st->st_low, SPEEX_GET_HIGHPASS, ptr); + break; + case SPEEX_GET_ACTIVITY: + speex_decoder_ctl(st->st_low, SPEEX_GET_ACTIVITY, ptr); + break; + case SPEEX_GET_PI_GAIN: + { + int i; + spx_word32_t *g = (spx_word32_t*)ptr; + for (i=0;inbSubframes;i++) + g[i]=st->pi_gain[i]; + } + break; + case SPEEX_GET_EXC: + { + int i; + for (i=0;inbSubframes;i++) + ((spx_word16_t*)ptr)[i] = st->exc_rms[i]; + } + break; + case SPEEX_GET_DTX_STATUS: + speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, ptr); + break; + case SPEEX_SET_INNOVATION_SAVE: + st->innov_save = (spx_word16_t*)ptr; + break; + case SPEEX_SET_WIDEBAND: + speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr); + break; + case SPEEX_GET_STACK: + *((char**)ptr) = st->stack; + break; + default: + speex_warning_int("Unknown nb_ctl request: ", request); + return -1; + } + return 0; +} + + +static void sb_decode_lost(SBDecState *st, spx_word16_t *out, int dtx, char *stack) +{ + int i; + int saved_modeid=0; + + if (dtx) + { + saved_modeid=st->submodeID; + st->submodeID=1; + } else { + bw_lpc(QCONST16(0.99f,15), st->interp_qlpc, st->interp_qlpc, st->lpcSize); + } + + st->first=1; + + + /* Final signal synthesis from excitation */ + if (!dtx) + { + st->last_ener = MULT16_16_Q15(QCONST16(.9f,15),st->last_ener); + } + for (i=0;iframe_size;i++) + out[i+st->frame_size] = speex_rand(st->last_ener, &st->seed); + + iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, + st->mem_sp, stack); + + + /* Reconstruct the original */ + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + if (dtx) + { + st->submodeID=saved_modeid; + } + + return; +} + +int sb_decode(void *state, SpeexBits *bits, void *vout) +{ + int i, sub; + SBDecState *st; + int wideband; + int ret; + char *stack; + VARDECL(spx_word32_t *low_pi_gain); + VARDECL(spx_word16_t *low_exc_rms); + VARDECL(spx_coef_t *ak); + VARDECL(spx_lsp_t *qlsp); + VARDECL(spx_lsp_t *interp_qlsp); + spx_int32_t dtx; + const SpeexSBMode *mode; + spx_word16_t *out = (spx_word16_t*)vout; + spx_word16_t *low_innov_alias; + spx_word32_t exc_ener_sum = 0; + + st = (SBDecState*)state; + stack=st->stack; + mode = (const SpeexSBMode*)(st->mode->mode); + + low_innov_alias = out+st->frame_size; + speex_decoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_alias); + /* Decode the low-band */ + ret = speex_decode_native(st->st_low, bits, out); + + speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, &dtx); + + /* If error decoding the narrowband part, propagate error */ + if (ret!=0) + { + return ret; + } + + if (!bits) + { + sb_decode_lost(st, out, dtx, stack); + return 0; + } + + if (st->encode_submode) + { + + /*Check "wideband bit"*/ + if (speex_bits_remaining(bits)>0) + wideband = speex_bits_peek(bits); + else + wideband = 0; + if (wideband) + { + /*Regular wideband frame, read the submode*/ + wideband = speex_bits_unpack_unsigned(bits, 1); + st->submodeID = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS); + } else + { + /*Was a narrowband frame, set "null submode"*/ + st->submodeID = 0; + } + if (st->submodeID != 0 && st->submodes[st->submodeID] == NULL) + { + speex_notify("Invalid mode encountered. The stream is corrupted."); + return -2; + } + } + + /* If null mode (no transmission), just set a couple things to zero*/ + if (st->submodes[st->submodeID] == NULL) + { + if (dtx) + { + sb_decode_lost(st, out, 1, stack); + return 0; + } + + for (i=0;iframe_size;i++) + out[st->frame_size+i]=VERY_SMALL; + + st->first=1; + + /* Final signal synthesis from excitation */ + iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, st->mem_sp, stack); + + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + + return 0; + + } + + ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); + ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); + speex_decoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); + speex_decoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); + + ALLOC(qlsp, st->lpcSize, spx_lsp_t); + ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); + SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits); + + if (st->first) + { + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + } + + ALLOC(ak, st->lpcSize, spx_coef_t); + + for (sub=0;subnbSubframes;sub++) + { + VARDECL(spx_word32_t *exc); + spx_word16_t *innov_save=NULL; + spx_word16_t *sp; + spx_word16_t filter_ratio; + spx_word16_t el=0; + int offset; + spx_word32_t rl=0,rh=0; + + offset = st->subframeSize*sub; + sp=out+st->frame_size+offset; + ALLOC(exc, st->subframeSize, spx_word32_t); + /* Pointer for saving innovation */ + if (st->innov_save) + { + innov_save = st->innov_save+2*offset; + SPEEX_MEMSET(innov_save, 0, 2*st->subframeSize); + } + + /* LSP interpolation */ + lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes, LSP_MARGIN); + + /* LSP to LPC */ + lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack); + + /* Calculate reponse ratio between the low and high filter in the middle + of the band (4000 Hz) */ + + st->pi_gain[sub]=LPC_SCALING; + rh = LPC_SCALING; + for (i=0;ilpcSize;i+=2) + { + rh += ak[i+1] - ak[i]; + st->pi_gain[sub] += ak[i] + ak[i+1]; + } + + rl = low_pi_gain[sub]; +#ifdef FIXED_POINT + filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767)); +#else + filter_ratio=(rl+.01)/(rh+.01); +#endif + + SPEEX_MEMSET(exc, 0, st->subframeSize); + if (!SUBMODE(innovation_unquant)) + { + spx_word32_t g; + int quant; + + quant = speex_bits_unpack_unsigned(bits, 5); + g= spx_exp(MULT16_16(QCONST16(.125f,11),(quant-10))); + + g = PDIV32(g, filter_ratio); + + for (i=0;isubframeSize;i+=2) + { + exc[i]=SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i]),SHL32(g,6)),SIG_SHIFT); + exc[i+1]=NEG32(SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i+1]),SHL32(g,6)),SIG_SHIFT)); + } + + } else { + spx_word16_t gc; + spx_word32_t scale; + int qgc = speex_bits_unpack_unsigned(bits, 4); + + el = low_exc_rms[sub]; + gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]); + + if (st->subframeSize==80) + gc = MULT16_16_P14(QCONST16(1.4142f,14),gc); + + scale = SHL32(PDIV32(SHL32(MULT16_16(gc, el),3), filter_ratio),SIG_SHIFT-3); + SUBMODE(innovation_unquant)(exc, SUBMODE(innovation_params), st->subframeSize, + bits, stack, &st->seed); + + signal_mul(exc,exc,scale,st->subframeSize); + + if (SUBMODE(double_codebook)) { + char *tmp_stack=stack; + VARDECL(spx_sig_t *innov2); + ALLOC(innov2, st->subframeSize, spx_sig_t); + SPEEX_MEMSET(innov2, 0, st->subframeSize); + SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, + bits, stack, &st->seed); + signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); + for (i=0;isubframeSize;i++) + exc[i] = ADD32(exc[i],innov2[i]); + stack = tmp_stack; + } + + } + + if (st->innov_save) + { + for (i=0;isubframeSize;i++) + innov_save[2*i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT)); + } + + iir_mem16(st->excBuf, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, + st->mem_sp, stack); + for (i=0;isubframeSize;i++) + st->excBuf[i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT)); + for (i=0;ilpcSize;i++) + st->interp_qlpc[i] = ak[i]; + st->exc_rms[sub] = compute_rms16(st->excBuf, st->subframeSize); + exc_ener_sum = ADD32(exc_ener_sum, DIV32(MULT16_16(st->exc_rms[sub],st->exc_rms[sub]), st->nbSubframes)); + } + st->last_ener = spx_sqrt(exc_ener_sum); + + qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); + for (i=0;ilpcSize;i++) + st->old_qlsp[i] = qlsp[i]; + + st->first=0; + + return 0; +} +#endif /* DISABLE_DECODER */ + + + +#endif + diff --git a/native/codec/libraries/speex/libspeex/sb_celp.h b/native/codec/libraries/speex/libspeex/sb_celp.h new file mode 100644 index 0000000..141d0c2 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/sb_celp.h @@ -0,0 +1,154 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin */ +/** + @file sb_celp.h + @brief Sub-band CELP mode used for wideband encoding +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SB_CELP_H +#define SB_CELP_H + +#include "modes.h" +#include "nb_celp.h" + +/**Structure representing the full state of the sub-band encoder*/ +typedef struct SBEncState { + const SpeexMode *mode; /**< Pointer to the mode (containing for vtable info) */ + void *st_low; /**< State of the low-band (narrowband) encoder */ + int full_frame_size; /**< Length of full-band frames*/ + int frame_size; /**< Length of high-band frames*/ + int subframeSize; /**< Length of high-band sub-frames*/ + int nbSubframes; /**< Number of high-band sub-frames*/ + int windowSize; /**< Length of high-band LPC window*/ + int lpcSize; /**< Order of high-band LPC analysis */ + int first; /**< First frame? */ + spx_word16_t lpc_floor; /**< Controls LPC analysis noise floor */ + spx_word16_t gamma1; /**< Perceptual weighting coef 1 */ + spx_word16_t gamma2; /**< Perceptual weighting coef 2 */ + + char *stack; /**< Temporary allocation stack */ + spx_word16_t *high; /**< High-band signal (buffer) */ + spx_word16_t *h0_mem; + + const spx_word16_t *window; /**< LPC analysis window */ + const spx_word16_t *lagWindow; /**< Auto-correlation window */ + spx_lsp_t *old_lsp; /**< LSPs of previous frame */ + spx_lsp_t *old_qlsp; /**< Quantized LSPs of previous frame */ + spx_coef_t *interp_qlpc; /**< Interpolated quantized LPCs for current sub-frame */ + + spx_mem_t *mem_sp; /**< Synthesis signal memory */ + spx_mem_t *mem_sp2; + spx_mem_t *mem_sw; /**< Perceptual signal memory */ + spx_word32_t *pi_gain; + spx_word16_t *exc_rms; + spx_word16_t *innov_rms_save; /**< If non-NULL, innovation is copied here */ + +#ifndef DISABLE_VBR + float vbr_quality; /**< Quality setting for VBR encoding */ + int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */ + spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode (total) */ + spx_int32_t vbr_max_high; /**< Max bit-rate allowed in VBR mode for the high-band */ + spx_int32_t abr_enabled; /**< ABR setting (in bps), 0 if off */ + float abr_drift; + float abr_drift2; + float abr_count; + int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */ + float relative_quality; +#endif /* #ifndef DISABLE_VBR */ + + int encode_submode; + const SpeexSubmode * const *submodes; + int submodeID; + int submodeSelect; + int complexity; + spx_int32_t sampling_rate; + +} SBEncState; + + +/**Structure representing the full state of the sub-band decoder*/ +typedef struct SBDecState { + const SpeexMode *mode; /**< Pointer to the mode (containing for vtable info) */ + void *st_low; /**< State of the low-band (narrowband) encoder */ + int full_frame_size; + int frame_size; + int subframeSize; + int nbSubframes; + int lpcSize; + int first; + spx_int32_t sampling_rate; + int lpc_enh_enabled; + + char *stack; + spx_word16_t *g0_mem, *g1_mem; + + spx_word16_t *excBuf; + spx_lsp_t *old_qlsp; + spx_coef_t *interp_qlpc; + + spx_mem_t *mem_sp; + spx_word32_t *pi_gain; + spx_word16_t *exc_rms; + spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ + + spx_word16_t last_ener; + spx_int32_t seed; + + int encode_submode; + const SpeexSubmode * const *submodes; + int submodeID; +} SBDecState; + + +/**Initializes encoder state*/ +void *sb_encoder_init(const SpeexMode *m); + +/**De-allocates encoder state resources*/ +void sb_encoder_destroy(void *state); + +/**Encodes one frame*/ +int sb_encode(void *state, void *in, SpeexBits *bits); + + +/**Initializes decoder state*/ +void *sb_decoder_init(const SpeexMode *m); + +/**De-allocates decoder state resources*/ +void sb_decoder_destroy(void *state); + +/**Decodes one frame*/ +int sb_decode(void *state, SpeexBits *bits, void *out); + +int sb_encoder_ctl(void *state, int request, void *ptr); + +int sb_decoder_ctl(void *state, int request, void *ptr); + +#endif diff --git a/native/codec/libraries/speex/libspeex/smallft.c b/native/codec/libraries/speex/libspeex/smallft.c new file mode 100644 index 0000000..82c3b0a --- /dev/null +++ b/native/codec/libraries/speex/libspeex/smallft.c @@ -0,0 +1,1261 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: *unnormalized* fft transform + last mod: $Id: smallft.c,v 1.19 2003/10/08 05:12:37 jm Exp $ + + ********************************************************************/ + +/* FFT implementation from OggSquish, minus cosine transforms, + * minus all but radix 2/4 case. In Vorbis we only need this + * cut-down version. + * + * To do more than just power-of-two sized vectors, see the full + * version I wrote for NetLib. + * + * Note that the packing is a little strange; rather than the FFT r/i + * packing following R_0, I_n, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, + * it follows R_0, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, I_n like the + * FORTRAN version + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "smallft.h" +#include "arch.h" +#include "os_support.h" + +static void drfti1(int n, float *wa, int *ifac){ + static int ntryh[4] = { 4,2,3,5 }; + static float tpi = 6.28318530717958648f; + float arg,argh,argld,fi; + int ntry=0,i,j=-1; + int k1, l1, l2, ib; + int ld, ii, ip, is, nq, nr; + int ido, ipm, nfm1; + int nl=n; + int nf=0; + + L101: + j++; + if (j < 4) + ntry=ntryh[j]; + else + ntry+=2; + + L104: + nq=nl/ntry; + nr=nl-ntry*nq; + if (nr!=0) goto L101; + + nf++; + ifac[nf+1]=ntry; + nl=nq; + if(ntry!=2)goto L107; + if(nf==1)goto L107; + + for (i=1;i>1; + ipp2=ip; + idp2=ido; + nbd=(ido-1)>>1; + t0=l1*ido; + t10=ip*ido; + + if(ido==1)goto L119; + for(ik=0;ikl1){ + for(j=1;j>1; + ipp2=ip; + ipph=(ip+1)>>1; + if(idol1)goto L139; + + is= -ido-1; + t1=0; + for(j=1;jn==1)return; + drftf1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); +} + +void spx_drft_backward(struct drft_lookup *l,float *data){ + if (l->n==1)return; + drftb1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); +} + +void spx_drft_init(struct drft_lookup *l,int n) +{ + l->n=n; + l->trigcache=(float*)speex_alloc(3*n*sizeof(*l->trigcache)); + l->splitcache=(int*)speex_alloc(32*sizeof(*l->splitcache)); + fdrffti(n, l->trigcache, l->splitcache); +} + +void spx_drft_clear(struct drft_lookup *l) +{ + if(l) + { + if(l->trigcache) + speex_free(l->trigcache); + if(l->splitcache) + speex_free(l->splitcache); + } +} diff --git a/native/codec/libraries/speex/libspeex/smallft.h b/native/codec/libraries/speex/libspeex/smallft.h new file mode 100644 index 0000000..446e2f6 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/smallft.h @@ -0,0 +1,46 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: fft transform + last mod: $Id: smallft.h,v 1.3 2003/09/16 18:35:45 jm Exp $ + + ********************************************************************/ +/** + @file smallft.h + @brief Discrete Rotational Fourier Transform (DRFT) +*/ + +#ifndef _V_SMFT_H_ +#define _V_SMFT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** Discrete Rotational Fourier Transform lookup */ +struct drft_lookup{ + int n; + float *trigcache; + int *splitcache; +}; + +extern void spx_drft_forward(struct drft_lookup *l,float *data); +extern void spx_drft_backward(struct drft_lookup *l,float *data); +extern void spx_drft_init(struct drft_lookup *l,int n); +extern void spx_drft_clear(struct drft_lookup *l); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/speex/libspeex/speex.c b/native/codec/libraries/speex/libspeex/speex.c new file mode 100644 index 0000000..33701ba --- /dev/null +++ b/native/codec/libraries/speex/libspeex/speex.c @@ -0,0 +1,253 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex.c + + Basic Speex functions + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "modes.h" +#include +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +#define MAX_IN_SAMPLES 640 + + + +EXPORT void *speex_encoder_init(const SpeexMode *mode) +{ + return mode->enc_init(mode); +} + +EXPORT void *speex_decoder_init(const SpeexMode *mode) +{ + return mode->dec_init(mode); +} + +EXPORT void speex_encoder_destroy(void *state) +{ + (*((SpeexMode**)state))->enc_destroy(state); +} + +EXPORT void speex_decoder_destroy(void *state) +{ + (*((SpeexMode**)state))->dec_destroy(state); +} + + + +int speex_encode_native(void *state, spx_word16_t *in, SpeexBits *bits) +{ + return (*((SpeexMode**)state))->enc(state, in, bits); +} + +int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out) +{ + return (*((SpeexMode**)state))->dec(state, bits, out); +} + + + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) +{ + int i; + spx_int32_t N; + spx_int16_t short_in[MAX_IN_SAMPLES]; + speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + for (i=0;i32767.f) + short_in[i] = 32767; + else if (in[i]<-32768.f) + short_in[i] = -32768; + else + short_in[i] = (spx_int16_t)floor(.5+in[i]); + } + return (*((SpeexMode**)state))->enc(state, short_in, bits); +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) +{ + SpeexMode *mode; + mode = *(SpeexMode**)state; + return (mode)->enc(state, in, bits); +} + +#ifndef DISABLE_FLOAT_API +EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) +{ + int i, ret; + spx_int32_t N; + spx_int16_t short_out[MAX_IN_SAMPLES]; + speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + ret = (*((SpeexMode**)state))->dec(state, bits, short_out); + for (i=0;idec(state, bits, out); +} + +#else + +EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) +{ + return (*((SpeexMode**)state))->enc(state, in, bits); +} + +EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) +{ + int i; + spx_int32_t N; + float float_in[MAX_IN_SAMPLES]; + speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + for (i=0;ienc(state, float_in, bits); +} + +EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) +{ + return (*((SpeexMode**)state))->dec(state, bits, out); +} + +EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) +{ + int i; + spx_int32_t N; + float float_out[MAX_IN_SAMPLES]; + int ret; + speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N); + ret = (*((SpeexMode**)state))->dec(state, bits, float_out); + if (ret == 0) + { + for (i=0;i32767.f) + out[i] = 32767; + else if (float_out[i]<-32768.f) + out[i] = -32768; + else + out[i] = (spx_int16_t)floor(.5+float_out[i]); + } + } + return ret; +} +#endif + + + +EXPORT int speex_encoder_ctl(void *state, int request, void *ptr) +{ + return (*((SpeexMode**)state))->enc_ctl(state, request, ptr); +} + +EXPORT int speex_decoder_ctl(void *state, int request, void *ptr) +{ + return (*((SpeexMode**)state))->dec_ctl(state, request, ptr); +} + + + +int nb_mode_query(const void *mode, int request, void *ptr) +{ + const SpeexNBMode *m = (const SpeexNBMode*)mode; + + switch (request) + { + case SPEEX_MODE_FRAME_SIZE: + *((int*)ptr)=m->frameSize; + break; + case SPEEX_SUBMODE_BITS_PER_FRAME: + if (*((int*)ptr)==0) + *((int*)ptr) = NB_SUBMODE_BITS+1; + else if (m->submodes[*((int*)ptr)]==NULL) + *((int*)ptr) = -1; + else + *((int*)ptr) = m->submodes[*((int*)ptr)]->bits_per_frame; + break; + default: + speex_warning_int("Unknown nb_mode_query request: ", request); + return -1; + } + return 0; +} + + + +EXPORT int speex_lib_ctl(int request, void *ptr) +{ + switch (request) + { + case SPEEX_LIB_GET_MAJOR_VERSION: + *((int*)ptr) = SPEEX_MAJOR_VERSION; + break; + case SPEEX_LIB_GET_MINOR_VERSION: + *((int*)ptr) = SPEEX_MINOR_VERSION; + break; + case SPEEX_LIB_GET_MICRO_VERSION: + *((int*)ptr) = SPEEX_MICRO_VERSION; + break; + case SPEEX_LIB_GET_EXTRA_VERSION: + *((const char**)ptr) = SPEEX_EXTRA_VERSION; + break; + case SPEEX_LIB_GET_VERSION_STRING: + *((const char**)ptr) = SPEEX_VERSION; + break; + /*case SPEEX_LIB_SET_ALLOC_FUNC: + break; + case SPEEX_LIB_GET_ALLOC_FUNC: + break; + case SPEEX_LIB_SET_FREE_FUNC: + break; + case SPEEX_LIB_GET_FREE_FUNC: + break;*/ + default: + speex_warning_int("Unknown wb_mode_query request: ", request); + return -1; + } + return 0; +} diff --git a/native/codec/libraries/speex/libspeex/speex_callbacks.c b/native/codec/libraries/speex/libspeex/speex_callbacks.c new file mode 100644 index 0000000..8be9e38 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/speex_callbacks.c @@ -0,0 +1,144 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File speex_callbacks.c + Callback handling and in-band signalling + + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_callbacks.h" +#include "arch.h" +#include "os_support.h" + +EXPORT int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state) +{ + int id; + SpeexCallback *callback; + /*speex_bits_advance(bits, 5);*/ + id=speex_bits_unpack_unsigned(bits, 4); + callback = callback_list+id; + + if (callback->func) + { + return callback->func(bits, state, callback->data); + } else + /*If callback is not registered, skip the right number of bits*/ + { + int adv; + if (id<2) + adv = 1; + else if (id<8) + adv = 4; + else if (id<10) + adv = 8; + else if (id<12) + adv = 16; + else if (id<14) + adv = 32; + else + adv = 64; + speex_bits_advance(bits, adv); + } + return 0; +} + +EXPORT int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_MODE, &m); + return 0; +} + +EXPORT int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_LOW_MODE, &m); + return 0; +} + +EXPORT int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t m; + m = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_HIGH_MODE, &m); + return 0; +} + +#ifndef DISABLE_VBR +EXPORT int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t vbr; + vbr = speex_bits_unpack_unsigned(bits, 1); + speex_encoder_ctl(data, SPEEX_SET_VBR, &vbr); + return 0; +} +#endif /* #ifndef DISABLE_VBR */ + +EXPORT int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) +{ + spx_int32_t enh; + enh = speex_bits_unpack_unsigned(bits, 1); + speex_decoder_ctl(data, SPEEX_SET_ENH, &enh); + return 0; +} + +#ifndef DISABLE_VBR +EXPORT int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) +{ + float qual; + qual = speex_bits_unpack_unsigned(bits, 4); + speex_encoder_ctl(data, SPEEX_SET_VBR_QUALITY, &qual); + return 0; +} +#endif /* #ifndef DISABLE_VBR */ + +EXPORT int speex_std_char_handler(SpeexBits *bits, void *state, void *data) +{ + unsigned char ch; + ch = speex_bits_unpack_unsigned(bits, 8); + _speex_putc(ch, data); + /*printf("speex_std_char_handler ch=%x\n", ch);*/ + return 0; +} + + + +/* Default handler for user callbacks: skip it */ +EXPORT int speex_default_user_handler(SpeexBits *bits, void *state, void *data) +{ + int req_size = speex_bits_unpack_unsigned(bits, 4); + speex_bits_advance(bits, 5+8*req_size); + return 0; +} diff --git a/native/codec/libraries/speex/libspeex/speex_header.c b/native/codec/libraries/speex/libspeex/speex_header.c new file mode 100644 index 0000000..5900d36 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/speex_header.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: speex_header.c + Describes the Speex header + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include "speex/speex_header.h" +#include "speex/speex.h" +#include "os_support.h" + +#ifndef NULL +#define NULL 0 +#endif + +/** Convert little endian */ +static inline spx_int32_t le_int(spx_int32_t i) +{ +#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) + spx_uint32_t ui, ret; + ui = i; + ret = ui>>24; + ret |= (ui>>8)&0x0000ff00; + ret |= (ui<<8)&0x00ff0000; + ret |= (ui<<24); + return ret; +#else + return i; +#endif +} + +#define ENDIAN_SWITCH(x) {x=le_int(x);} + + +/* +typedef struct SpeexHeader { + char speex_string[8]; + char speex_version[SPEEX_HEADER_VERSION_LENGTH]; + int speex_version_id; + int header_size; + int rate; + int mode; + int mode_bitstream_version; + int nb_channels; + int bitrate; + int frame_size; + int vbr; + int frames_per_packet; + int extra_headers; + int reserved1; + int reserved2; +} SpeexHeader; +*/ + +EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m) +{ + int i; + const char *h="Speex "; + /* + strncpy(header->speex_string, "Speex ", 8); + strncpy(header->speex_version, SPEEX_VERSION, SPEEX_HEADER_VERSION_LENGTH-1); + header->speex_version[SPEEX_HEADER_VERSION_LENGTH-1]=0; + */ + for (i=0;i<8;i++) + header->speex_string[i]=h[i]; + for (i=0;ispeex_version[i]=SPEEX_VERSION[i]; + for (;ispeex_version[i]=0; + + header->speex_version_id = 1; + header->header_size = sizeof(SpeexHeader); + + header->rate = rate; + header->mode = m->modeID; + header->mode_bitstream_version = m->bitstream_version; + if (m->modeID<0) + speex_warning("This mode is meant to be used alone"); + header->nb_channels = nb_channels; + header->bitrate = -1; + speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size); + header->vbr = 0; + + header->frames_per_packet = 0; + header->extra_headers = 0; + header->reserved1 = 0; + header->reserved2 = 0; +} + +EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size) +{ + SpeexHeader *le_header; + le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); + + SPEEX_COPY(le_header, header, 1); + + /*Make sure everything is now little-endian*/ + ENDIAN_SWITCH(le_header->speex_version_id); + ENDIAN_SWITCH(le_header->header_size); + ENDIAN_SWITCH(le_header->rate); + ENDIAN_SWITCH(le_header->mode); + ENDIAN_SWITCH(le_header->mode_bitstream_version); + ENDIAN_SWITCH(le_header->nb_channels); + ENDIAN_SWITCH(le_header->bitrate); + ENDIAN_SWITCH(le_header->frame_size); + ENDIAN_SWITCH(le_header->vbr); + ENDIAN_SWITCH(le_header->frames_per_packet); + ENDIAN_SWITCH(le_header->extra_headers); + + *size = sizeof(SpeexHeader); + return (char *)le_header; +} + +EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size) +{ + int i; + SpeexHeader *le_header; + const char *h = "Speex "; + + /*FIXME: Do we allow larger headers?*/ + if (size < (int)sizeof(SpeexHeader)) + { + speex_notify("Speex header too small"); + return NULL; + } + + + for (i=0;i<8;i++) + if (packet[i]!=h[i]) + { + /* This doesn't look like a Speex file */ + return NULL; + } + + le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); + + SPEEX_COPY(le_header, (SpeexHeader*)packet, 1); + + /*Make sure everything is converted correctly from little-endian*/ + ENDIAN_SWITCH(le_header->speex_version_id); + ENDIAN_SWITCH(le_header->header_size); + ENDIAN_SWITCH(le_header->rate); + ENDIAN_SWITCH(le_header->mode); + ENDIAN_SWITCH(le_header->mode_bitstream_version); + ENDIAN_SWITCH(le_header->nb_channels); + ENDIAN_SWITCH(le_header->bitrate); + ENDIAN_SWITCH(le_header->frame_size); + ENDIAN_SWITCH(le_header->vbr); + ENDIAN_SWITCH(le_header->frames_per_packet); + ENDIAN_SWITCH(le_header->extra_headers); + + if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0) + { + speex_notify("Invalid mode specified in Speex header"); + speex_free (le_header); + return NULL; + } + + if (le_header->nb_channels>2) + le_header->nb_channels = 2; + if (le_header->nb_channels<1) + le_header->nb_channels = 1; + + return le_header; + +} + +EXPORT void speex_header_free(void *ptr) +{ + speex_free(ptr); +} diff --git a/native/codec/libraries/speex/libspeex/stack_alloc.h b/native/codec/libraries/speex/libspeex/stack_alloc.h new file mode 100644 index 0000000..f6eb3f6 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/stack_alloc.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#ifdef USE_ALLOCA +# ifdef _WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#ifdef ENABLE_VALGRIND + +#include + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) + +#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) + +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) + +#endif + +#if defined(VAR_ARRAYS) +#define VARDECL(var) +#define ALLOC(var, size, type) type var[size] +#elif defined(USE_ALLOCA) +#define VARDECL(var) var +#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size)) +#else +#define VARDECL(var) var +#define ALLOC(var, size, type) var = PUSH(stack, size, type) +#endif + + +#endif diff --git a/native/codec/libraries/speex/libspeex/stereo.c b/native/codec/libraries/speex/libspeex/stereo.c new file mode 100644 index 0000000..83642cb --- /dev/null +++ b/native/codec/libraries/speex/libspeex/stereo.c @@ -0,0 +1,303 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: stereo.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_stereo.h" +#include "speex/speex_callbacks.h" +#include "math_approx.h" +#include "vq.h" +#include +#include "os_support.h" + +typedef struct RealSpeexStereoState { + spx_word32_t balance; /**< Left/right balance info */ + spx_word32_t e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)] */ + spx_word32_t smooth_left; /**< Smoothed left channel gain */ + spx_word32_t smooth_right; /**< Smoothed right channel gain */ + spx_uint32_t reserved1; /**< Reserved for future use */ + spx_int32_t reserved2; /**< Reserved for future use */ +} RealSpeexStereoState; + + +/*float e_ratio_quant[4] = {1, 1.26, 1.587, 2};*/ +#ifndef FIXED_POINT +static const float e_ratio_quant[4] = {.25f, .315f, .397f, .5f}; +static const float e_ratio_quant_bounds[3] = {0.2825f, 0.356f, 0.4485f}; +#else +static const spx_word16_t e_ratio_quant[4] = {8192, 10332, 13009, 16384}; +static const spx_word16_t e_ratio_quant_bounds[3] = {9257, 11665, 14696}; +static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104, + 134, 172, 221, 284, 364, 468, 600, 771, + 990, 1271, 1632, 2096, 2691, 3455, 4436, 5696, + 7314, 9392, 12059, 15484, 19882, 25529, 32766}; +#endif + +/* This is an ugly compatibility hack that properly resets the stereo state + In case it it compiled in fixed-point, but initialised with the deprecated + floating point static initialiser */ +#ifdef FIXED_POINT +#define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0); +#else +#define COMPATIBILITY_HACK(s) +#endif + +EXPORT SpeexStereoState *speex_stereo_state_init() +{ + SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); + speex_stereo_state_reset(stereo); + return stereo; +} + +EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo) +{ + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; +#ifdef FIXED_POINT + stereo->balance = 65536; + stereo->e_ratio = 16384; + stereo->smooth_left = 16384; + stereo->smooth_right = 16384; + stereo->reserved1 = 0xdeadbeef; + stereo->reserved2 = 0; +#else + stereo->balance = 1.0f; + stereo->e_ratio = .5f; + stereo->smooth_left = 1.f; + stereo->smooth_right = 1.f; + stereo->reserved1 = 0; + stereo->reserved2 = 0; +#endif +} + +EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo) +{ + speex_free(stereo); +} + +#ifndef DISABLE_ENCODER +#ifndef DISABLE_FLOAT_API +EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) +{ + int i, tmp; + float e_left=0, e_right=0, e_tot=0; + float balance, e_ratio; + for (i=0;i0) + speex_bits_pack(bits, 0, 1); + else + speex_bits_pack(bits, 1, 1); + balance=floor(.5+fabs(balance)); + if (balance>30) + balance=31; + + speex_bits_pack(bits, (int)balance, 5); + + /* FIXME: this is a hack */ + tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4); + speex_bits_pack(bits, tmp, 2); +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) +{ + int i, tmp; + spx_word32_t e_left=0, e_right=0, e_tot=0; + spx_word32_t balance, e_ratio; + spx_word32_t largest, smallest; + int balance_id; +#ifdef FIXED_POINT + int shift; +#endif + + /* In band marker */ + speex_bits_pack(bits, 14, 5); + /* Stereo marker */ + speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4); + + for (i=0;i e_right) + { + speex_bits_pack(bits, 0, 1); + largest = e_left; + smallest = e_right; + } else { + speex_bits_pack(bits, 1, 1); + largest = e_right; + smallest = e_left; + } + + /* Balance quantization */ +#ifdef FIXED_POINT + shift = spx_ilog2(largest)-15; + largest = VSHR32(largest, shift-4); + smallest = VSHR32(smallest, shift); + balance = DIV32(largest, ADD32(smallest, 1)); + if (balance > 32767) + balance = 32767; + balance_id = scal_quant(EXTRACT16(balance), balance_bounds, 32); +#else + balance=(largest+1.)/(smallest+1.); + balance=4*log(balance); + balance_id=floor(.5+fabs(balance)); + if (balance_id>30) + balance_id=31; +#endif + + speex_bits_pack(bits, balance_id, 5); + + /* "coherence" quantisation */ +#ifdef FIXED_POINT + shift = spx_ilog2(e_tot); + e_tot = VSHR32(e_tot, shift-25); + e_left = VSHR32(e_left, shift-10); + e_right = VSHR32(e_right, shift-10); + e_ratio = DIV32(e_tot, e_left+e_right+1); +#else + e_ratio = e_tot/(1.+e_left+e_right); +#endif + + tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4); + /*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/ + speex_bits_pack(bits, tmp, 2); +} +#else /* DISABLE_ENCODER */ +EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) +{ +} +#endif /* DISABLE_ENCODER */ + + +#ifndef DISABLE_FLOAT_API +EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) +{ + int i; + spx_word32_t balance; + spx_word16_t e_left, e_right, e_ratio; + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; + + COMPATIBILITY_HACK(stereo); + + balance=stereo->balance; + e_ratio=stereo->e_ratio; + + /* These two are Q14, with max value just below 2. */ + e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); + e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); + + for (i=frame_size-1;i>=0;i--) + { + spx_word16_t tmp=data[i]; + stereo->smooth_left = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_left, QCONST16(0.98, 15)), e_left, QCONST16(0.02, 15)), 15)); + stereo->smooth_right = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_right, QCONST16(0.98, 15)), e_right, QCONST16(0.02, 15)), 15)); + data[2*i] = (float)MULT16_16_P14(stereo->smooth_left, tmp); + data[2*i+1] = (float)MULT16_16_P14(stereo->smooth_right, tmp); + } +} +#endif /* #ifndef DISABLE_FLOAT_API */ + +EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) +{ + int i; + spx_word32_t balance; + spx_word16_t e_left, e_right, e_ratio; + RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; + + COMPATIBILITY_HACK(stereo); + + balance=stereo->balance; + e_ratio=stereo->e_ratio; + + /* These two are Q14, with max value just below 2. */ + e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); + e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); + + for (i=frame_size-1;i>=0;i--) + { + spx_int16_t tmp=data[i]; + stereo->smooth_left = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_left, QCONST16(0.98, 15)), e_left, QCONST16(0.02, 15)), 15)); + stereo->smooth_right = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_right, QCONST16(0.98, 15)), e_right, QCONST16(0.02, 15)), 15)); + data[2*i] = (spx_int16_t)MULT16_16_P14(stereo->smooth_left, tmp); + data[2*i+1] = (spx_int16_t)MULT16_16_P14(stereo->smooth_right, tmp); + } +} + +EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) +{ + RealSpeexStereoState *stereo; + spx_word16_t sign=1, dexp; + int tmp; + + stereo = (RealSpeexStereoState*)data; + + COMPATIBILITY_HACK(stereo); + + if (speex_bits_unpack_unsigned(bits, 1)) + sign=-1; + dexp = speex_bits_unpack_unsigned(bits, 5); +#ifndef FIXED_POINT + stereo->balance = exp(sign*.25*dexp); +#else + stereo->balance = spx_exp(MULT16_16(sign, SHL16(dexp, 9))); +#endif + tmp = speex_bits_unpack_unsigned(bits, 2); + stereo->e_ratio = e_ratio_quant[tmp]; + + return 0; +} diff --git a/native/codec/libraries/speex/libspeex/testenc.c b/native/codec/libraries/speex/libspeex/testenc.c new file mode 100644 index 0000000..1f634ed --- /dev/null +++ b/native/codec/libraries/speex/libspeex/testenc.c @@ -0,0 +1,145 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_callbacks.h" +#include +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 160 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); + + /* BEGIN: You probably don't need the following in a real application */ + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + /* END of unnecessary stuff */ + + tmp=1; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=8; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + + /* Turn this off if you want to measure SNR (on by default) */ + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_HIGHPASS, &tmp); + speex_decoder_ctl(dec, SPEEX_SET_HIGHPASS, &tmp); + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + if (argc==4) + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; + } + fprintf (stderr, "Total encoded size: %d bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + speex_bits_destroy(&bits); + +#ifndef DISABLE_FLOAT_API + { + float sigpow,errpow,snr, seg_snr=0; + sigpow = 0; + errpow = 0; + + /* This code just computes SNR, so you don't need it either */ + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 640 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + float sigpow,errpow,snr, seg_snr=0; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + sigpow = 0; + errpow = 0; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB)); + + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + tmp=0; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=7; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + if (argc==4) + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; + } + fprintf (stderr, "Total encoded size: %d bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 320 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + float sigpow,errpow,snr, seg_snr=0; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + sigpow = 0; + errpow = 0; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_WB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_WB)); + + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + tmp=1; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=8; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=3; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + /*tmp=3; + speex_encoder_ctl(st, SPEEX_SET_HIGH_MODE, &tmp); + tmp=6; + speex_encoder_ctl(st, SPEEX_SET_LOW_MODE, &tmp); +*/ + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + if (argc==4) + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; + } + fprintf (stderr, "Total encoded size: %d bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + speex_bits_destroy(&bits); + + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i + + +#define sqr(x) ((x)*(x)) + +#define MIN_ENERGY 6000 +#define NOISE_POW .3 + +#ifndef DISABLE_VBR + +const float vbr_nb_thresh[9][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* CNG */ + { 4.0f, 2.5f, 2.0f, 1.2f, 0.5f,-0.25f, -0.5f, -0.7f, -0.8f, -0.9f, -1.0f}, /* 2 kbps */ + {10.0f, 6.5f, 5.2f, 4.5f, 3.9f, 3.7f, 3.0f, 2.5f, 2.3f, 1.8f, 1.0f}, /* 6 kbps */ + {11.0f, 8.8f, 7.5f, 6.5f, 5.0f, 4.2f, 3.9f, 3.9f, 3.5f, 3.0f, 1.0f}, /* 8 kbps */ + {11.0f, 11.0f, 9.9f, 8.5f, 7.0f, 5.25f, 4.5f, 4.0f, 4.0f, 4.0f, 2.0f}, /* 11 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 9.25f, 8.0f, 7.0f, 5.0f, 4.0f, 3.0f}, /* 15 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.5f, 6.2f, 5.2f, 5.0f}, /* 18 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 10.0f, 9.8f, 7.5f}, /* 24 kbps */ + { 7.0f, 4.5f, 3.7f, 3.0f, 2.5f, 1.0f, 1.8f, 1.5f, 1.0f, 0.0f, 0.0f} /* 4 kbps */ +}; + + +const float vbr_hb_thresh[5][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* 2 kbps */ + {11.0f, 11.0f, 9.5f, 8.5f, 7.5f, 6.0f, 5.0f, 3.9f, 3.0f, 2.0f, 1.0f}, /* 6 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.5f, 8.7f, 7.8f, 7.0f, 6.5f, 4.0f}, /* 10 kbps */ + {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 9.8f, 7.5f, 5.5f} /* 18 kbps */ +}; + +const float vbr_uhb_thresh[2][11]={ + {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */ + { 3.9f, 2.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f} /* 2 kbps */ +}; + +void vbr_init(VBRState *vbr) +{ + int i; + + vbr->average_energy=1600000; + vbr->last_energy=1; + vbr->accum_sum=0; + vbr->soft_pitch=0; + vbr->last_pitch_coef=0; + vbr->last_quality=0; + + vbr->noise_accum = .05*pow(MIN_ENERGY, NOISE_POW); + vbr->noise_accum_count=.05; + vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count; + vbr->consec_noise=0; + + + for (i=0;ilast_log_energy[i] = log(MIN_ENERGY); +} + + +/* + This function should analyse the signal and decide how critical the + coding error will be perceptually. The following factors should be + taken into account: + + -Attacks (positive energy derivative) should be coded with more bits + + -Stationary voiced segments should receive more bits + + -Segments with (very) low absolute energy should receive less bits (maybe + only shaped noise?) + + -DTX for near-zero energy? + + -Stationary fricative segments should have less bits + + -Temporal masking: when energy slope is decreasing, decrease the bit-rate + + -Decrease bit-rate for males (low pitch)? + + -(wideband only) less bits in the high-band when signal is very + non-stationary (harder to notice high-frequency noise)??? + +*/ + +float vbr_analysis(VBRState *vbr, spx_word16_t *sig, int len, int pitch, float pitch_coef) +{ + int i; + float ener=0, ener1=0, ener2=0; + float qual=7; + float log_energy; + float non_st=0; + float voicing; + float pow_ener; + + for (i=0;i>1;i++) + ener1 += ((float)sig[i])*sig[i]; + + for (i=len>>1;ilast_log_energy[i]); + non_st = non_st/(30*VBR_MEMORY_SIZE); + if (non_st>1) + non_st=1; + + voicing = 3*(pitch_coef-.4)*fabs(pitch_coef-.4); + vbr->average_energy = 0.9*vbr->average_energy + .1*ener; + vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count; + pow_ener = pow(ener,NOISE_POW); + if (vbr->noise_accum_count<.06 && ener>MIN_ENERGY) + vbr->noise_accum = .05*pow_ener; + + if ((voicing<.3 && non_st < .2 && pow_ener < 1.2*vbr->noise_level) + || (voicing<.3 && non_st < .05 && pow_ener < 1.5*vbr->noise_level) + || (voicing<.4 && non_st < .05 && pow_ener < 1.2*vbr->noise_level) + || (voicing<0 && non_st < .05)) + { + float tmp; + + vbr->consec_noise++; + if (pow_ener > 3*vbr->noise_level) + tmp = 3*vbr->noise_level; + else + tmp = pow_ener; + if (vbr->consec_noise>=4) + { + vbr->noise_accum = .95*vbr->noise_accum + .05*tmp; + vbr->noise_accum_count = .95*vbr->noise_accum_count + .05; + } + } else { + vbr->consec_noise=0; + } + + if (pow_ener < vbr->noise_level && ener>MIN_ENERGY) + { + vbr->noise_accum = .95*vbr->noise_accum + .05*pow_ener; + vbr->noise_accum_count = .95*vbr->noise_accum_count + .05; + } + + /* Checking for very low absolute energy */ + if (ener < 30000) + { + qual -= .7; + if (ener < 10000) + qual-=.7; + if (ener < 3000) + qual-=.7; + } else { + float short_diff, long_diff; + short_diff = log((ener+1)/(1+vbr->last_energy)); + long_diff = log((ener+1)/(1+vbr->average_energy)); + /*fprintf (stderr, "%f %f\n", short_diff, long_diff);*/ + + if (long_diff<-5) + long_diff=-5; + if (long_diff>2) + long_diff=2; + + if (long_diff>0) + qual += .6*long_diff; + if (long_diff<0) + qual += .5*long_diff; + if (short_diff>0) + { + if (short_diff>5) + short_diff=5; + qual += 1*short_diff; + } + /* Checking for energy increases */ + if (ener2 > 1.6*ener1) + qual += .5; + } + vbr->last_energy = ener; + vbr->soft_pitch = .8*vbr->soft_pitch + .2*pitch_coef; + qual += 2.2*((pitch_coef-.4) + (vbr->soft_pitch-.4)); + + if (qual < vbr->last_quality) + qual = .5*qual + .5*vbr->last_quality; + if (qual<4) + qual=4; + if (qual>10) + qual=10; + + /* + if (vbr->consec_noise>=2) + qual-=1.3; + if (vbr->consec_noise>=5) + qual-=1.3; + if (vbr->consec_noise>=12) + qual-=1.3; + */ + if (vbr->consec_noise>=3) + qual=4; + + if (vbr->consec_noise) + qual -= 1.0 * (log(3.0 + vbr->consec_noise)-log(3)); + if (qual<0) + qual=0; + + if (ener<1600000) + { + if (vbr->consec_noise>2) + qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3)); + if (ener<10000&&vbr->consec_noise>2) + qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3)); + if (qual<0) + qual=0; + qual += .3*log(.0001+ener/1600000.0); + } + if (qual<-1) + qual=-1; + + /*printf ("%f %f %f %f\n", qual, voicing, non_st, pow_ener/(.01+vbr->noise_level));*/ + + vbr->last_pitch_coef = pitch_coef; + vbr->last_quality = qual; + + for (i=VBR_MEMORY_SIZE-1;i>0;i--) + vbr->last_log_energy[i] = vbr->last_log_energy[i-1]; + vbr->last_log_energy[0] = log_energy; + + /*printf ("VBR: %f %f %f %f\n", (float)(log_energy-log(vbr->average_energy+MIN_ENERGY)), non_st, voicing, vbr->noise_level);*/ + + return qual; +} + +void vbr_destroy(VBRState *vbr) +{ +} + +#endif /* #ifndef DISABLE_VBR */ diff --git a/native/codec/libraries/speex/libspeex/vbr.h b/native/codec/libraries/speex/libspeex/vbr.h new file mode 100644 index 0000000..8163440 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/vbr.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file vbr.h + @brief Variable Bit-Rate (VBR) related routines +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + + +#ifndef VBR_H +#define VBR_H + +#include "arch.h" + +#define VBR_MEMORY_SIZE 5 + +extern const float vbr_nb_thresh[9][11]; +extern const float vbr_hb_thresh[5][11]; +extern const float vbr_uhb_thresh[2][11]; + +/** VBR state. */ +typedef struct VBRState { + float average_energy; + float last_energy; + float last_log_energy[VBR_MEMORY_SIZE]; + float accum_sum; + float last_pitch_coef; + float soft_pitch; + float last_quality; + float noise_level; + float noise_accum; + float noise_accum_count; + int consec_noise; +} VBRState; + +void vbr_init(VBRState *vbr); + +float vbr_analysis(VBRState *vbr, spx_word16_t *sig, int len, int pitch, float pitch_coef); + +void vbr_destroy(VBRState *vbr); + +#endif diff --git a/native/codec/libraries/speex/libspeex/vorbis_psy.c b/native/codec/libraries/speex/libspeex/vorbis_psy.c new file mode 100644 index 0000000..cb385b7 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/vorbis_psy.c @@ -0,0 +1,509 @@ +/* Copyright (C) 2005 Jean-Marc Valin, CSIRO, Christopher Montgomery + File: vorbis_psy.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef VORBIS_PSYCHO + +#include "arch.h" +#include "smallft.h" +#include "lpc.h" +#include "vorbis_psy.h" +#include "os_support.h" + +#include +#include +#include + +/* psychoacoustic setup ********************************************/ + +static VorbisPsyInfo example_tuning = { + + .5,.5, + 3,3,25, + + /*63 125 250 500 1k 2k 4k 8k 16k*/ + // vorbis mode 4 style + //{-32,-32,-32,-32,-28,-24,-22,-20,-20, -20, -20, -8, -6, -6, -6, -6, -6}, + { -4, -6, -6, -6, -6, -6, -6, -6, -8, -8,-10,-10, -8, -6, -4, -4, -2}, + + { + 0, 1, 2, 3, 4, 5, 5, 5, /* 7dB */ + 6, 6, 6, 5, 4, 4, 4, 4, /* 15dB */ + 4, 4, 5, 5, 5, 6, 6, 6, /* 23dB */ + 7, 7, 7, 8, 8, 8, 9, 10, /* 31dB */ + 11,12,13,14,15,16,17, 18, /* 39dB */ + } + +}; + + + +/* there was no great place to put this.... */ +#include +static void _analysis_output(char *base,int i,float *v,int n,int bark,int dB){ + int j; + FILE *of; + char buffer[80]; + + sprintf(buffer,"%s_%d.m",base,i); + of=fopen(buffer,"w"); + + if(!of)perror("failed to open data dump file"); + + for(j=0;j> 16; + if( lo>=0 ) break; + hi = b[i] & 0xffff; + + tN = N[hi] + N[-lo]; + tX = X[hi] - X[-lo]; + tXX = XX[hi] + XX[-lo]; + tY = Y[hi] + Y[-lo]; + tXY = XY[hi] - XY[-lo]; + + A = tY * tXX - tX * tXY; + B = tN * tXY - tX * tY; + D = tN * tXX - tX * tX; + R = (A + x * B) / D; + if (R < 0.f) + R = 0.f; + + noise[i] = R - offset; + } + + for ( ;; i++, x += 1.f) { + + lo = b[i] >> 16; + hi = b[i] & 0xffff; + if(hi>=n)break; + + tN = N[hi] - N[lo]; + tX = X[hi] - X[lo]; + tXX = XX[hi] - XX[lo]; + tY = Y[hi] - Y[lo]; + tXY = XY[hi] - XY[lo]; + + A = tY * tXX - tX * tXY; + B = tN * tXY - tX * tY; + D = tN * tXX - tX * tX; + R = (A + x * B) / D; + if (R < 0.f) R = 0.f; + + noise[i] = R - offset; + } + for ( ; i < n; i++, x += 1.f) { + + R = (A + x * B) / D; + if (R < 0.f) R = 0.f; + + noise[i] = R - offset; + } + + if (fixed <= 0) return; + + for (i = 0, x = 0.f;; i++, x += 1.f) { + hi = i + fixed / 2; + lo = hi - fixed; + if(lo>=0)break; + + tN = N[hi] + N[-lo]; + tX = X[hi] - X[-lo]; + tXX = XX[hi] + XX[-lo]; + tY = Y[hi] + Y[-lo]; + tXY = XY[hi] - XY[-lo]; + + + A = tY * tXX - tX * tXY; + B = tN * tXY - tX * tY; + D = tN * tXX - tX * tX; + R = (A + x * B) / D; + + if (R - offset < noise[i]) noise[i] = R - offset; + } + for ( ;; i++, x += 1.f) { + + hi = i + fixed / 2; + lo = hi - fixed; + if(hi>=n)break; + + tN = N[hi] - N[lo]; + tX = X[hi] - X[lo]; + tXX = XX[hi] - XX[lo]; + tY = Y[hi] - Y[lo]; + tXY = XY[hi] - XY[lo]; + + A = tY * tXX - tX * tXY; + B = tN * tXY - tX * tY; + D = tN * tXX - tX * tX; + R = (A + x * B) / D; + + if (R - offset < noise[i]) noise[i] = R - offset; + } + for ( ; i < n; i++, x += 1.f) { + R = (A + x * B) / D; + if (R - offset < noise[i]) noise[i] = R - offset; + } +} + +static void _vp_noisemask(VorbisPsy *p, + float *logfreq, + float *logmask){ + + int i,n=p->n/2; + float *work=alloca(n*sizeof(*work)); + + bark_noise_hybridmp(n,p->bark,logfreq,logmask, + 140.,-1); + + for(i=0;ibark,work,logmask,0., + p->vi->noisewindowfixed); + + for(i=0;i=NOISE_COMPAND_LEVELS)dB=NOISE_COMPAND_LEVELS-1; + if(dB<0)dB=0; + logmask[i]= work[i]+p->vi->noisecompand[dB]+p->noiseoffset[i]; + } + +} + +VorbisPsy *vorbis_psy_init(int rate, int n) +{ + long i,j,lo=-99,hi=1; + VorbisPsy *p = speex_alloc(sizeof(VorbisPsy)); + memset(p,0,sizeof(*p)); + + p->n = n; + spx_drft_init(&p->lookup, n); + p->bark = speex_alloc(n*sizeof(*p->bark)); + p->rate=rate; + p->vi = &example_tuning; + + /* BH4 window */ + p->window = speex_alloc(sizeof(*p->window)*n); + float a0 = .35875f; + float a1 = .48829f; + float a2 = .14128f; + float a3 = .01168f; + for(i=0;iwindow[i] = //a0 - a1*cos(2.*M_PI/n*(i+.5)) + a2*cos(4.*M_PI/n*(i+.5)) - a3*cos(6.*M_PI/n*(i+.5)); + sin((i+.5)/n * M_PI)*sin((i+.5)/n * M_PI); + /* bark scale lookups */ + for(i=0;ivi->noisewindowlominvi->noisewindowlo);lo++); + + for(;hi<=n && (hivi->noisewindowhimin || + toBARK(rate/(2*n)*hi)<(bark+p->vi->noisewindowhi));hi++); + + p->bark[i]=((lo-1)<<16)+(hi-1); + + } + + /* set up rolling noise median */ + p->noiseoffset=speex_alloc(n*sizeof(*p->noiseoffset)); + + for(i=0;i=P_BANDS-1)halfoc=P_BANDS-1; + inthalfoc=(int)halfoc; + del=halfoc-inthalfoc; + + p->noiseoffset[i]= + p->vi->noiseoff[inthalfoc]*(1.-del) + + p->vi->noiseoff[inthalfoc+1]*del; + + } +#if 0 + _analysis_output_always("noiseoff0",ls,p->noiseoffset,n,1,0,0); +#endif + + return p; +} + +void vorbis_psy_destroy(VorbisPsy *p) +{ + if(p){ + spx_drft_clear(&p->lookup); + if(p->bark) + speex_free(p->bark); + if(p->noiseoffset) + speex_free(p->noiseoffset); + if(p->window) + speex_free(p->window); + memset(p,0,sizeof(*p)); + speex_free(p); + } +} + +void compute_curve(VorbisPsy *psy, float *audio, float *curve) +{ + int i; + float work[psy->n]; + + float scale=4.f/psy->n; + float scale_dB; + + scale_dB=todB(scale); + + /* window the PCM data; use a BH4 window, not vorbis */ + for(i=0;in;i++) + work[i]=audio[i] * psy->window[i]; + + { + static int seq=0; + + //_analysis_output("win",seq,work,psy->n,0,0); + + seq++; + } + + /* FFT yields more accurate tonal estimation (not phase sensitive) */ + spx_drft_forward(&psy->lookup,work); + + /* magnitudes */ + work[0]=scale_dB+todB(work[0]); + for(i=1;in-1;i+=2){ + float temp = work[i]*work[i] + work[i+1]*work[i+1]; + work[(i+1)>>1] = scale_dB+.5f * todB(temp); + } + + /* derive a noise curve */ + _vp_noisemask(psy,work,curve); +#define SIDEL 12 + for (i=0;in>>1)-i-1]=curve[(psy->n>>1)-SIDEH]; + } + for(i=0;i<((psy->n)>>1);i++) + curve[i] = fromdB(1.2*curve[i]+.2*i); + //curve[i] = fromdB(0.8*curve[i]+.35*i); + //curve[i] = fromdB(0.9*curve[i])*pow(1.0*i+45,1.3); +} + +/* Transform a masking curve (power spectrum) into a pole-zero filter */ +void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord) +{ + int i; + float ac[psy->n]; + float tmp; + int len = psy->n >> 1; + for (i=0;i<2*len;i++) + ac[i] = 0; + for (i=1;ilookup, ac); + _spx_lpc(awk1, ac, ord); + tmp = 1.; + for (i=0;ilookup, ac); + /* Compute (power) response of awk1 (all zero) */ + ac[0] *= ac[0]; + for (i=1;ilookup, ac); + _spx_lpc(awk2, ac, ord); + tmp = 1; + for (i=0;i +#include + +#define ORDER 10 +#define CURVE_SIZE 24 + +int main() +{ + int i; + float curve[CURVE_SIZE]; + float awk1[ORDER], awk2[ORDER]; + for (i=0;i1e-13?log((x)*(x))*4.34294480f:-30) +#define fromdB(x) (exp((x)*.11512925f)) + +/* The bark scale equations are approximations, since the original + table was somewhat hand rolled. The below are chosen to have the + best possible fit to the rolled tables, thus their somewhat odd + appearance (these are more accurate and over a longer range than + the oft-quoted bark equations found in the texts I have). The + approximations are valid from 0 - 30kHz (nyquist) or so. + + all f in Hz, z in Bark */ + +#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) +#define fromBARK(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f) + +/* Frequency to octave. We arbitrarily declare 63.5 Hz to be octave + 0.0 */ + +#define toOC(n) (log(n)*1.442695f-5.965784f) +#define fromOC(o) (exp(((o)+5.965784f)*.693147f)) + + +typedef struct { + + float noisewindowlo; + float noisewindowhi; + int noisewindowlomin; + int noisewindowhimin; + int noisewindowfixed; + float noiseoff[P_BANDS]; + float noisecompand[NOISE_COMPAND_LEVELS]; + +} VorbisPsyInfo; + + + +typedef struct { + int n; + int rate; + struct drft_lookup lookup; + VorbisPsyInfo *vi; + + float *window; + float *noiseoffset; + long *bark; + +} VorbisPsy; + + +VorbisPsy *vorbis_psy_init(int rate, int size); +void vorbis_psy_destroy(VorbisPsy *psy); +void compute_curve(VorbisPsy *psy, float *audio, float *curve); +void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord); + +#endif +#endif diff --git a/native/codec/libraries/speex/libspeex/vq.c b/native/codec/libraries/speex/libspeex/vq.c new file mode 100644 index 0000000..c7f1396 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/vq.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: vq.c + Vector quantization + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vq.h" +#include "stack_alloc.h" +#include "arch.h" + +#ifdef _USE_SSE +#include +#include "vq_sse.h" +#elif defined(SHORTCUTS) && (defined(ARM4_ASM) || defined(ARM5E_ASM)) +#include "vq_arm4.h" +#elif defined(BFIN_ASM) +#include "vq_bfin.h" +#endif + +#ifndef DISABLE_ENCODER +int scal_quant(spx_word16_t in, const spx_word16_t *boundary, int entries) +{ + int i=0; + while (iboundary[0]) + { + boundary++; + i++; + } + return i; +} + +int scal_quant32(spx_word32_t in, const spx_word32_t *boundary, int entries) +{ + int i=0; + while (iboundary[0]) + { + boundary++; + i++; + } + return i; +} +#endif /* DISABLE_ENCODER */ + +#if !defined(OVERRIDE_VQ_NBEST) && !defined(DISABLE_ENCODER) +/*Finds the indices of the n-best entries in a codebook*/ +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + used = 0; + for (i=0;i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + } + } +} +#endif /* !defined(OVERRIDE_VQ_NBEST) && !defined(DISABLE_ENCODER) */ + + + + +#if !defined(OVERRIDE_VQ_NBEST_SIGN) && !defined(DISABLE_WIDEBAND) && !defined(DISABLE_ENCODER) +/*Finds the indices of the n-best entries in a codebook with sign*/ +void vq_nbest_sign(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k, sign, used; + used=0; + for (i=0;i0) + { + sign=0; + dist=-dist; + } else + { + sign=1; + } +#ifdef FIXED_POINT + dist = ADD32(dist,SHR32(E[i],1)); +#else + dist = ADD32(dist,.5f*E[i]); +#endif + if (i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + if (sign) + nbest[k]+=entries; + } + } +} +#endif /* !defined(OVERRIDE_VQ_NBEST_SIGN) && !defined(DISABLE_WIDEBAND) && !defined(DISABLE_ENCODER) */ diff --git a/native/codec/libraries/speex/libspeex/vq.h b/native/codec/libraries/speex/libspeex/vq.h new file mode 100644 index 0000000..5a4ced2 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/vq.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file vq.h + @brief Vector quantization +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef VQ_H +#define VQ_H + +#include "arch.h" + +int scal_quant(spx_word16_t in, const spx_word16_t *boundary, int entries); +int scal_quant32(spx_word32_t in, const spx_word32_t *boundary, int entries); + +#ifdef _USE_SSE +#include +void vq_nbest(spx_word16_t *in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); + +void vq_nbest_sign(spx_word16_t *in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); +#else +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); + +void vq_nbest_sign(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack); +#endif + +#endif diff --git a/native/codec/libraries/speex/libspeex/vq_arm4.h b/native/codec/libraries/speex/libspeex/vq_arm4.h new file mode 100644 index 0000000..585b861 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/vq_arm4.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file vq_arm4.h + @brief ARM4-optimized vq routine +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_VQ_NBEST +void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j; + for (i=0;i>= 1;\n\t" + "A0 = %0;\n\t" + "R0.L = W[%1++%7] || R1.L = W[I0++];\n\t" + "LOOP vq_loop%= LC1 = %5;\n\t" + "LOOP_BEGIN vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS) || R0.L = W[%1++%7] || R1.L = W[I0++];\n\t" + "LOOP_END vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS);\n\t" + "cc = %0 < %2;\n\t" + "if cc %2 = %0;\n\t" + "if cc %3 = R2;\n\t" + "R2 += 1;\n\t" + "LOOP_END entries_loop%=;\n\t" + : "=&D" (dist), "=&a" (codebook), "=&d" (best_dist[0]), "=&d" (nbest[0]), "=&a" (E) + : "a" (len-1), "a" (in), "a" (2), "d" (entries), "d" (len<<1), "1" (codebook), "4" (E), "2" (best_dist[0]), "3" (nbest[0]) + : "R0", "R1", "R2", "I0", "L0", "B0", "A0", "cc", "memory", + "ASTAT" BFIN_HWLOOP0_REGS BFIN_HWLOOP1_REGS + ); + } + } else { + int i,k,used; + used = 0; + for (i=0;i>= 1;\n\t" + "A0 = %0;\n\t" + "I0 = %3;\n\t" + "L0 = 0;\n\t" + "R0.L = W[%1++%4] || R1.L = W[I0++];\n\t" + "LOOP vq_loop%= LC0 = %2;\n\t" + "LOOP_BEGIN vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS) || R0.L = W[%1++%4] || R1.L = W[I0++];\n\t" + "LOOP_END vq_loop%=;\n\t" + "%0 = (A0 -= R0.L*R1.L) (IS);\n\t" + : "=D" (dist), "=a" (codebook) + : "a" (len-1), "a" (in), "a" (2), "1" (codebook), "0" (E[i]) + : "R0", "R1", "I0", "L0", "A0", "ASTAT" BFIN_HWLOOP0_REGS + ); + if (i= 1) && (k > used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist; + nbest[k]=i; + used++; + } + } + } +} diff --git a/native/codec/libraries/speex/libspeex/vq_sse.h b/native/codec/libraries/speex/libspeex/vq_sse.h new file mode 100644 index 0000000..2abe880 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/vq_sse.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2004 Jean-Marc Valin */ +/** + @file vq_sse.h + @brief SSE-optimized vq routine +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define OVERRIDE_VQ_NBEST +void vq_nbest(spx_word16_t *_in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + VARDECL(float *dist); + VARDECL(__m128 *in); + __m128 half; + used = 0; + ALLOC(dist, entries, float); + half = _mm_set_ps1(.5f); + ALLOC(in, len, __m128); + for (i=0;i>2;i++) + { + __m128 d = _mm_mul_ps(E[i], half); + for (j=0;j= 1) && (k > used || dist[i] < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist[i]; + nbest[k]=i; + used++; + } + } +} + + + + +#define OVERRIDE_VQ_NBEST_SIGN +void vq_nbest_sign(spx_word16_t *_in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack) +{ + int i,j,k,used; + VARDECL(float *dist); + VARDECL(__m128 *in); + + used = 0; + ALLOC(dist, entries, float); + + ALLOC(in, len, __m128); + for (i=0;i>2;i++) + { + __m128 d = _mm_setzero_ps(); + for (j=0;j0) + { + sign=0; + dist[i]=-dist[i]; + } else + { + sign=1; + } + dist[i] += .5f*((float*)E)[i]; + if (i= 1) && (k > used || dist[i] < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + best_dist[k]=dist[i]; + nbest[k]=i; + used++; + if (sign) + nbest[k]+=entries; + } + } +} diff --git a/native/codec/libraries/speex/libspeex/window.c b/native/codec/libraries/speex/libspeex/window.c new file mode 100644 index 0000000..a89d4d7 --- /dev/null +++ b/native/codec/libraries/speex/libspeex/window.c @@ -0,0 +1,102 @@ +/* Copyright (C) 2006 Jean-Marc Valin + File: window.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" + +#ifdef FIXED_POINT +const spx_word16_t lag_window[11] = { + 32767, 32675, 32397, 31940, 31311, 30520, 29581, 28508, 27318, 26029, 24661 +}; + +const spx_word16_t lpc_window[200] = { +2621, 2627, 2642, 2668, 2704, 2750, 2807, 2874, +2951, 3038, 3135, 3242, 3359, 3486, 3623, 3769, +3925, 4090, 4264, 4448, 4641, 4843, 5053, 5272, +5500, 5736, 5981, 6233, 6493, 6761, 7036, 7319, +7609, 7905, 8209, 8519, 8835, 9157, 9485, 9819, +10158, 10502, 10852, 11206, 11564, 11926, 12293, 12663, +13037, 13414, 13793, 14176, 14561, 14948, 15337, 15727, +16119, 16512, 16906, 17300, 17695, 18089, 18484, 18877, +19270, 19662, 20053, 20442, 20829, 21214, 21596, 21976, +22353, 22726, 23096, 23463, 23826, 24184, 24538, 24887, +25231, 25570, 25904, 26232, 26555, 26871, 27181, 27484, +27781, 28070, 28353, 28628, 28896, 29157, 29409, 29653, +29889, 30117, 30336, 30547, 30749, 30941, 31125, 31300, +31465, 31621, 31767, 31903, 32030, 32147, 32254, 32352, +32439, 32516, 32582, 32639, 32685, 32722, 32747, 32763, +32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, +32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, +32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, +32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, +32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, +32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, +32767, 32767, 32767, 32723, 32590, 32368, 32058, 31661, +31177, 30610, 29959, 29227, 28416, 27528, 26566, 25532, +24430, 23263, 22034, 20747, 19406, 18015, 16579, 15104, +13594, 12058, 10503, 8941, 7391, 5887, 4498, 3392 +}; +#else +const spx_word16_t lag_window[11] = { + 1.00000f, 0.99716f, 0.98869f, 0.97474f, 0.95554f, 0.93140f, 0.90273f, 0.86998f, 0.83367f, 0.79434f, 0.75258f +}; + +const spx_word16_t lpc_window[200] = { + 0.080000f, 0.080158f, 0.080630f, 0.081418f, 0.082520f, 0.083935f, 0.085663f, 0.087703f, + 0.090052f, 0.092710f, 0.095674f, 0.098943f, 0.102514f, 0.106385f, 0.110553f, 0.115015f, + 0.119769f, 0.124811f, 0.130137f, 0.135744f, 0.141628f, 0.147786f, 0.154212f, 0.160902f, + 0.167852f, 0.175057f, 0.182513f, 0.190213f, 0.198153f, 0.206328f, 0.214731f, 0.223357f, + 0.232200f, 0.241254f, 0.250513f, 0.259970f, 0.269619f, 0.279453f, 0.289466f, 0.299651f, + 0.310000f, 0.320507f, 0.331164f, 0.341965f, 0.352901f, 0.363966f, 0.375151f, 0.386449f, + 0.397852f, 0.409353f, 0.420943f, 0.432615f, 0.444361f, 0.456172f, 0.468040f, 0.479958f, + 0.491917f, 0.503909f, 0.515925f, 0.527959f, 0.540000f, 0.552041f, 0.564075f, 0.576091f, + 0.588083f, 0.600042f, 0.611960f, 0.623828f, 0.635639f, 0.647385f, 0.659057f, 0.670647f, + 0.682148f, 0.693551f, 0.704849f, 0.716034f, 0.727099f, 0.738035f, 0.748836f, 0.759493f, + 0.770000f, 0.780349f, 0.790534f, 0.800547f, 0.810381f, 0.820030f, 0.829487f, 0.838746f, + 0.847800f, 0.856643f, 0.865269f, 0.873672f, 0.881847f, 0.889787f, 0.897487f, 0.904943f, + 0.912148f, 0.919098f, 0.925788f, 0.932214f, 0.938372f, 0.944256f, 0.949863f, 0.955189f, + 0.960231f, 0.964985f, 0.969447f, 0.973615f, 0.977486f, 0.981057f, 0.984326f, 0.987290f, + 0.989948f, 0.992297f, 0.994337f, 0.996065f, 0.997480f, 0.998582f, 0.999370f, 0.999842f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 0.998640f, 0.994566f, 0.987787f, 0.978324f, 0.966203f, + 0.951458f, 0.934131f, 0.914270f, 0.891931f, 0.867179f, 0.840084f, 0.810723f, 0.779182f, + 0.745551f, 0.709930f, 0.672424f, 0.633148f, 0.592223f, 0.549781f, 0.505964f, 0.460932f, + 0.414863f, 0.367968f, 0.320511f, 0.272858f, 0.225569f, 0.179655f, 0.137254f, 0.103524f +}; +#endif diff --git a/native/codec/libraries/speex/m4/add_cflags.m4 b/native/codec/libraries/speex/m4/add_cflags.m4 new file mode 100644 index 0000000..08f4a40 --- /dev/null +++ b/native/codec/libraries/speex/m4/add_cflags.m4 @@ -0,0 +1,18 @@ +dnl @synopsis XIPH_ADD_CFLAGS +dnl +dnl Add the given option to CFLAGS, if it doesn't break the compiler + +AC_DEFUN([XIPH_ADD_CFLAGS], +[AC_MSG_CHECKING([if $CC accepts $1]) + ac_add_cflags__old_cflags="$CFLAGS" + CFLAGS="$1" + AC_TRY_LINK([ + #include + ], + [puts("Hello, World!"); return 0;], + AC_MSG_RESULT([yes]) + CFLAGS="$ac_add_cflags__old_cflags $1", + AC_MSG_RESULT([no]) + CFLAGS="$ac_add_cflags__old_cflags" + ) +])# XIPH_ADD_CFLAGS diff --git a/native/codec/libraries/speex/m4/pkg.m4 b/native/codec/libraries/speex/m4/pkg.m4 new file mode 100644 index 0000000..4b77f9f --- /dev/null +++ b/native/codec/libraries/speex/m4/pkg.m4 @@ -0,0 +1,272 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES + +# PKG_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable pkgconfigdir as the location where a module +# should install pkg-config .pc files. By default the directory is +# $libdir/pkgconfig, but the default can be changed by passing +# DIRECTORY. The user can override through the --with-pkgconfigdir +# parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_INSTALLDIR + + +# PKG_NOARCH_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable noarch_pkgconfigdir as the location where a +# module should install arch-independent pkg-config .pc files. By +# default the directory is $datadir/pkgconfig, but the default can be +# changed by passing DIRECTORY. The user can override through the +# --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_NOARCH_INSTALLDIR + +# PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, +# [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], +# [DESCRIPTION], [DEFAULT]) +# +# Prepare a "--with-" configure option using the lowercase [VARIABLE-PREFIX] +# name, merging the behaviour of AC_ARG_WITH and PKG_CHECK_MODULES in a single +# macro +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_WITH_MODULES], +[ +m4_pushdef([with_arg], m4_tolower([$1])) + +m4_pushdef([description], + [m4_default([$5], [build with ]with_arg[ support])]) + +m4_pushdef([def_arg], [m4_default([$6], [auto])]) +m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) +m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) + +m4_case(def_arg, + [yes],[m4_pushdef([with_without], [--without-]with_arg)], + [m4_pushdef([with_without],[--with-]with_arg)]) + +AC_ARG_WITH(with_arg, + AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, + [AS_TR_SH([with_]with_arg)=def_arg]) + +AS_CASE([$AS_TR_SH([with_]with_arg)], + [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], + [auto],[PKG_CHECK_MODULES([$1],[$2], + [m4_n([def_action_if_found]) $3], + [m4_n([def_action_if_not_found]) $4])]) + +m4_popdef([with_arg]) +m4_popdef([description]) +m4_popdef([def_arg]) + +]) dnl PKG_WITH_MODULES + +# PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +# [DESCRIPTION], [DEFAULT]) +# +# Convenience macro to trigger AM_CONDITIONAL after +# PKG_WITH_MODULES check. +# +# HAVE_[VARIABLE-PREFIX] is exported as make variable. +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_HAVE_WITH_MODULES], +[ +PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) + +AM_CONDITIONAL([HAVE_][$1], + [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) +]) + +# PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +# [DESCRIPTION], [DEFAULT]) +# +# Convenience macro to run AM_CONDITIONAL and AC_DEFINE after +# PKG_WITH_MODULES check. +# +# HAVE_[VARIABLE-PREFIX] is exported as make and preprocessor variable. +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], +[ +PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) + +AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], + [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) +]) diff --git a/native/codec/libraries/speex/macosx/English.lproj/InfoPlist.strings b/native/codec/libraries/speex/macosx/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..166513d Binary files /dev/null and b/native/codec/libraries/speex/macosx/English.lproj/InfoPlist.strings differ diff --git a/native/codec/libraries/speex/macosx/Info.plist b/native/codec/libraries/speex/macosx/Info.plist new file mode 100644 index 0000000..1d1c47c --- /dev/null +++ b/native/codec/libraries/speex/macosx/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Speex + CFBundleGetInfoString + Speex framework 1.1.12svn, Copyright © 2002-2006 Xiph.Org Foundation + CFBundleIconFile + + CFBundleIdentifier + org.xiph.speex + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.1.12svn + CFBundleSignature + ???? + CFBundleVersion + 1.1.12d1 + NSHumanReadableCopyright + Speex framework 1.1.12svn, Copyright © 2002-2006 Xiph.Org Foundation + CSResourcesFileMapped + + + diff --git a/native/codec/libraries/speex/macosx/Speex.xcodeproj/project.pbxproj b/native/codec/libraries/speex/macosx/Speex.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6025aad --- /dev/null +++ b/native/codec/libraries/speex/macosx/Speex.xcodeproj/project.pbxproj @@ -0,0 +1,713 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 37CA8DEB0DD73333005C8CB6 /* modes_wb.c in Sources */ = {isa = PBXBuildFile; fileRef = 37CA8DEA0DD73333005C8CB6 /* modes_wb.c */; }; + 37CA8DEC0DD73333005C8CB6 /* modes_wb.c in Sources */ = {isa = PBXBuildFile; fileRef = 37CA8DEA0DD73333005C8CB6 /* modes_wb.c */; }; + 37CA8E000DD7352A005C8CB6 /* os_support.h in Headers */ = {isa = PBXBuildFile; fileRef = 37CA8DFF0DD7352A005C8CB6 /* os_support.h */; }; + 73814B000907FB8200C478FC /* speex_header.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF40907FB8200C478FC /* speex_header.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B030907FB8200C478FC /* speex_stereo.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF70907FB8200C478FC /* speex_stereo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B040907FB8200C478FC /* speex_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF80907FB8200C478FC /* speex_types.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B060907FBAB00C478FC /* speex_callbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF10907FB8200C478FC /* speex_callbacks.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B070907FBAD00C478FC /* speex_bits.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF00907FB8200C478FC /* speex_bits.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B080907FBAE00C478FC /* speex.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AEF0907FB8200C478FC /* speex.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B5A0907FC9900C478FC /* bits.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B0D0907FC9900C478FC /* bits.c */; }; + 73814B5E0907FC9900C478FC /* cb_search.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B110907FC9900C478FC /* cb_search.c */; }; + 73814B600907FC9900C478FC /* exc_5_64_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B130907FC9900C478FC /* exc_5_64_table.c */; }; + 73814B610907FC9900C478FC /* exc_5_256_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B140907FC9900C478FC /* exc_5_256_table.c */; }; + 73814B620907FC9900C478FC /* exc_8_128_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B150907FC9900C478FC /* exc_8_128_table.c */; }; + 73814B630907FC9900C478FC /* exc_10_16_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B160907FC9900C478FC /* exc_10_16_table.c */; }; + 73814B640907FC9900C478FC /* exc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B170907FC9900C478FC /* exc_10_32_table.c */; }; + 73814B650907FC9900C478FC /* exc_20_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B180907FC9900C478FC /* exc_20_32_table.c */; }; + 73814B690907FC9900C478FC /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B1C0907FC9900C478FC /* filters.c */; }; + 73814B700907FC9900C478FC /* gain_table_lbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B230907FC9900C478FC /* gain_table_lbr.c */; }; + 73814B710907FC9900C478FC /* gain_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B240907FC9900C478FC /* gain_table.c */; }; + 73814B720907FC9900C478FC /* hexc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B250907FC9900C478FC /* hexc_10_32_table.c */; }; + 73814B730907FC9900C478FC /* hexc_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B260907FC9900C478FC /* hexc_table.c */; }; + 73814B740907FC9900C478FC /* high_lsp_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B270907FC9900C478FC /* high_lsp_tables.c */; }; + 73814B780907FC9900C478FC /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2B0907FC9900C478FC /* lpc.c */; }; + 73814B7A0907FC9900C478FC /* lsp_tables_nb.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2D0907FC9900C478FC /* lsp_tables_nb.c */; }; + 73814B7B0907FC9900C478FC /* lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2E0907FC9900C478FC /* lsp.c */; }; + 73814B800907FC9900C478FC /* ltp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B330907FC9900C478FC /* ltp.c */; }; + 73814B8A0907FC9900C478FC /* modes.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3D0907FC9900C478FC /* modes.c */; }; + 73814B8C0907FC9900C478FC /* nb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3F0907FC9900C478FC /* nb_celp.c */; }; + 73814B8F0907FC9900C478FC /* quant_lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B420907FC9900C478FC /* quant_lsp.c */; }; + 73814B910907FC9900C478FC /* sb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B440907FC9900C478FC /* sb_celp.c */; }; + 73814B930907FC9900C478FC /* smallft.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B460907FC9900C478FC /* smallft.c */; }; + 73814B950907FC9900C478FC /* speex_callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B480907FC9900C478FC /* speex_callbacks.c */; }; + 73814B960907FC9900C478FC /* speex_header.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B490907FC9900C478FC /* speex_header.c */; }; + 73814B970907FC9900C478FC /* speex.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4A0907FC9900C478FC /* speex.c */; }; + 73814B990907FC9900C478FC /* stereo.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4C0907FC9900C478FC /* stereo.c */; }; + 73814B9F0907FC9900C478FC /* vbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B520907FC9900C478FC /* vbr.c */; }; + 73814BA40907FC9900C478FC /* vq.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B570907FC9900C478FC /* vq.c */; }; + 738837540B193581005C7A69 /* _kiss_fft_guts.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837460B193581005C7A69 /* _kiss_fft_guts.h */; }; + 738837550B193581005C7A69 /* fftwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837470B193581005C7A69 /* fftwrap.c */; }; + 738837560B193581005C7A69 /* fftwrap.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837480B193581005C7A69 /* fftwrap.h */; }; + 738837590B193581005C7A69 /* kiss_fft.c in Sources */ = {isa = PBXBuildFile; fileRef = 7388374B0B193581005C7A69 /* kiss_fft.c */; }; + 7388375A0B193581005C7A69 /* kiss_fft.h in Headers */ = {isa = PBXBuildFile; fileRef = 7388374C0B193581005C7A69 /* kiss_fft.h */; }; + 7388375B0B193581005C7A69 /* kiss_fftr.c in Sources */ = {isa = PBXBuildFile; fileRef = 7388374D0B193581005C7A69 /* kiss_fftr.c */; }; + 7388375C0B193581005C7A69 /* kiss_fftr.h in Headers */ = {isa = PBXBuildFile; fileRef = 7388374E0B193581005C7A69 /* kiss_fftr.h */; }; + 7388375D0B193581005C7A69 /* lsp_bfin.h in Headers */ = {isa = PBXBuildFile; fileRef = 7388374F0B193581005C7A69 /* lsp_bfin.h */; }; + 7388375E0B193581005C7A69 /* pseudofloat.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837500B193581005C7A69 /* pseudofloat.h */; }; + 7388375F0B193581005C7A69 /* quant_lsp_bfin.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837510B193581005C7A69 /* quant_lsp_bfin.h */; }; + 738837600B193581005C7A69 /* vorbis_psy.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837520B193581005C7A69 /* vorbis_psy.c */; }; + 738837610B193581005C7A69 /* vorbis_psy.h in Headers */ = {isa = PBXBuildFile; fileRef = 738837530B193581005C7A69 /* vorbis_psy.h */; }; + 7388377B0B193784005C7A69 /* bits.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B0D0907FC9900C478FC /* bits.c */; }; + 7388377C0B193785005C7A69 /* cb_search.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B110907FC9900C478FC /* cb_search.c */; }; + 7388377D0B193788005C7A69 /* exc_10_16_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B160907FC9900C478FC /* exc_10_16_table.c */; }; + 7388377E0B193789005C7A69 /* exc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B170907FC9900C478FC /* exc_10_32_table.c */; }; + 7388377F0B19378A005C7A69 /* exc_20_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B180907FC9900C478FC /* exc_20_32_table.c */; }; + 738837800B19378A005C7A69 /* exc_5_256_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B140907FC9900C478FC /* exc_5_256_table.c */; }; + 738837810B19378C005C7A69 /* exc_5_64_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B130907FC9900C478FC /* exc_5_64_table.c */; }; + 738837820B19378E005C7A69 /* exc_8_128_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B150907FC9900C478FC /* exc_8_128_table.c */; }; + 738837830B193791005C7A69 /* fftwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837470B193581005C7A69 /* fftwrap.c */; }; + 738837850B193793005C7A69 /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B1C0907FC9900C478FC /* filters.c */; }; + 738837860B193795005C7A69 /* gain_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B240907FC9900C478FC /* gain_table.c */; }; + 738837870B193796005C7A69 /* gain_table_lbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B230907FC9900C478FC /* gain_table_lbr.c */; }; + 738837880B193799005C7A69 /* hexc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B250907FC9900C478FC /* hexc_10_32_table.c */; }; + 738837890B19379B005C7A69 /* hexc_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B260907FC9900C478FC /* hexc_table.c */; }; + 7388378A0B19379E005C7A69 /* high_lsp_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B270907FC9900C478FC /* high_lsp_tables.c */; }; + 7388378C0B1937A4005C7A69 /* kiss_fft.c in Sources */ = {isa = PBXBuildFile; fileRef = 7388374B0B193581005C7A69 /* kiss_fft.c */; }; + 7388378D0B1937A9005C7A69 /* kiss_fftr.c in Sources */ = {isa = PBXBuildFile; fileRef = 7388374D0B193581005C7A69 /* kiss_fftr.c */; }; + 7388378F0B1937B0005C7A69 /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2B0907FC9900C478FC /* lpc.c */; }; + 738837900B1937B0005C7A69 /* lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2E0907FC9900C478FC /* lsp.c */; }; + 738837910B1937B5005C7A69 /* lsp_tables_nb.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2D0907FC9900C478FC /* lsp_tables_nb.c */; }; + 738837920B1937B7005C7A69 /* ltp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B330907FC9900C478FC /* ltp.c */; }; + 738837960B1937BE005C7A69 /* modes.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3D0907FC9900C478FC /* modes.c */; }; + 738837970B1937C0005C7A69 /* nb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3F0907FC9900C478FC /* nb_celp.c */; }; + 738837990B1937C4005C7A69 /* quant_lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B420907FC9900C478FC /* quant_lsp.c */; }; + 7388379A0B1937C6005C7A69 /* sb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B440907FC9900C478FC /* sb_celp.c */; }; + 7388379B0B1937C9005C7A69 /* smallft.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B460907FC9900C478FC /* smallft.c */; }; + 7388379C0B1937CB005C7A69 /* speex.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4A0907FC9900C478FC /* speex.c */; }; + 7388379D0B1937CE005C7A69 /* speex_callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B480907FC9900C478FC /* speex_callbacks.c */; }; + 7388379E0B1937D0005C7A69 /* speex_header.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B490907FC9900C478FC /* speex_header.c */; }; + 7388379F0B1937D1005C7A69 /* stereo.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4C0907FC9900C478FC /* stereo.c */; }; + 738837A00B1937DA005C7A69 /* vbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B520907FC9900C478FC /* vbr.c */; }; + 738837A10B1937DD005C7A69 /* vorbis_psy.c in Sources */ = {isa = PBXBuildFile; fileRef = 738837520B193581005C7A69 /* vorbis_psy.c */; }; + 738837A20B1937DF005C7A69 /* vq.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B570907FC9900C478FC /* vq.c */; }; + 738837A30B1937E1005C7A69 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = BFF73DCF0A78AA170078A4A8 /* window.c */; }; + 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; + BFF73DD00A78AA170078A4A8 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = BFF73DCF0A78AA170078A4A8 /* window.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 32BAE0B70371A74B00C91783 /* Speex_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Speex_Prefix.pch; sourceTree = ""; }; + 37CA8DEA0DD73333005C8CB6 /* modes_wb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = modes_wb.c; path = ../libspeex/modes_wb.c; sourceTree = SOURCE_ROOT; }; + 37CA8DFF0DD7352A005C8CB6 /* os_support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_support.h; path = ../libspeex/os_support.h; sourceTree = SOURCE_ROOT; }; + 73814AEF0907FB8200C478FC /* speex.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex.h; sourceTree = ""; }; + 73814AF00907FB8200C478FC /* speex_bits.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_bits.h; sourceTree = ""; }; + 73814AF10907FB8200C478FC /* speex_callbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_callbacks.h; sourceTree = ""; }; + 73814AF40907FB8200C478FC /* speex_header.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_header.h; sourceTree = ""; }; + 73814AF70907FB8200C478FC /* speex_stereo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_stereo.h; sourceTree = ""; }; + 73814AF80907FB8200C478FC /* speex_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_types.h; sourceTree = ""; }; + 73814B0C0907FC9900C478FC /* arch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = arch.h; path = ../libspeex/arch.h; sourceTree = SOURCE_ROOT; }; + 73814B0D0907FC9900C478FC /* bits.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bits.c; path = ../libspeex/bits.c; sourceTree = SOURCE_ROOT; }; + 73814B0E0907FC9900C478FC /* cb_search_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cb_search_arm4.h; path = ../libspeex/cb_search_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B0F0907FC9900C478FC /* cb_search_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cb_search_bfin.h; path = ../libspeex/cb_search_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B100907FC9900C478FC /* cb_search_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cb_search_sse.h; path = ../libspeex/cb_search_sse.h; sourceTree = SOURCE_ROOT; }; + 73814B110907FC9900C478FC /* cb_search.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = cb_search.c; path = ../libspeex/cb_search.c; sourceTree = SOURCE_ROOT; }; + 73814B120907FC9900C478FC /* cb_search.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cb_search.h; path = ../libspeex/cb_search.h; sourceTree = SOURCE_ROOT; }; + 73814B130907FC9900C478FC /* exc_5_64_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_5_64_table.c; path = ../libspeex/exc_5_64_table.c; sourceTree = SOURCE_ROOT; }; + 73814B140907FC9900C478FC /* exc_5_256_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_5_256_table.c; path = ../libspeex/exc_5_256_table.c; sourceTree = SOURCE_ROOT; }; + 73814B150907FC9900C478FC /* exc_8_128_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_8_128_table.c; path = ../libspeex/exc_8_128_table.c; sourceTree = SOURCE_ROOT; }; + 73814B160907FC9900C478FC /* exc_10_16_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_10_16_table.c; path = ../libspeex/exc_10_16_table.c; sourceTree = SOURCE_ROOT; }; + 73814B170907FC9900C478FC /* exc_10_32_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_10_32_table.c; path = ../libspeex/exc_10_32_table.c; sourceTree = SOURCE_ROOT; }; + 73814B180907FC9900C478FC /* exc_20_32_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_20_32_table.c; path = ../libspeex/exc_20_32_table.c; sourceTree = SOURCE_ROOT; }; + 73814B190907FC9900C478FC /* filters_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filters_arm4.h; path = ../libspeex/filters_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B1A0907FC9900C478FC /* filters_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filters_bfin.h; path = ../libspeex/filters_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B1B0907FC9900C478FC /* filters_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filters_sse.h; path = ../libspeex/filters_sse.h; sourceTree = SOURCE_ROOT; }; + 73814B1C0907FC9900C478FC /* filters.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = filters.c; path = ../libspeex/filters.c; sourceTree = SOURCE_ROOT; }; + 73814B1D0907FC9900C478FC /* filters.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filters.h; path = ../libspeex/filters.h; sourceTree = SOURCE_ROOT; }; + 73814B1E0907FC9900C478FC /* fixed_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_arm4.h; path = ../libspeex/fixed_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B1F0907FC9900C478FC /* fixed_arm5e.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_arm5e.h; path = ../libspeex/fixed_arm5e.h; sourceTree = SOURCE_ROOT; }; + 73814B200907FC9900C478FC /* fixed_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_bfin.h; path = ../libspeex/fixed_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B210907FC9900C478FC /* fixed_debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_debug.h; path = ../libspeex/fixed_debug.h; sourceTree = SOURCE_ROOT; }; + 73814B220907FC9900C478FC /* fixed_generic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_generic.h; path = ../libspeex/fixed_generic.h; sourceTree = SOURCE_ROOT; }; + 73814B230907FC9900C478FC /* gain_table_lbr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = gain_table_lbr.c; path = ../libspeex/gain_table_lbr.c; sourceTree = SOURCE_ROOT; }; + 73814B240907FC9900C478FC /* gain_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = gain_table.c; path = ../libspeex/gain_table.c; sourceTree = SOURCE_ROOT; }; + 73814B250907FC9900C478FC /* hexc_10_32_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hexc_10_32_table.c; path = ../libspeex/hexc_10_32_table.c; sourceTree = SOURCE_ROOT; }; + 73814B260907FC9900C478FC /* hexc_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hexc_table.c; path = ../libspeex/hexc_table.c; sourceTree = SOURCE_ROOT; }; + 73814B270907FC9900C478FC /* high_lsp_tables.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = high_lsp_tables.c; path = ../libspeex/high_lsp_tables.c; sourceTree = SOURCE_ROOT; }; + 73814B2A0907FC9900C478FC /* lpc_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = lpc_bfin.h; path = ../libspeex/lpc_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B2B0907FC9900C478FC /* lpc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lpc.c; path = ../libspeex/lpc.c; sourceTree = SOURCE_ROOT; }; + 73814B2C0907FC9900C478FC /* lpc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = lpc.h; path = ../libspeex/lpc.h; sourceTree = SOURCE_ROOT; }; + 73814B2D0907FC9900C478FC /* lsp_tables_nb.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lsp_tables_nb.c; path = ../libspeex/lsp_tables_nb.c; sourceTree = SOURCE_ROOT; }; + 73814B2E0907FC9900C478FC /* lsp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lsp.c; path = ../libspeex/lsp.c; sourceTree = SOURCE_ROOT; }; + 73814B2F0907FC9900C478FC /* lsp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = lsp.h; path = ../libspeex/lsp.h; sourceTree = SOURCE_ROOT; }; + 73814B300907FC9900C478FC /* ltp_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ltp_arm4.h; path = ../libspeex/ltp_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B310907FC9900C478FC /* ltp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ltp_bfin.h; path = ../libspeex/ltp_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B320907FC9900C478FC /* ltp_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ltp_sse.h; path = ../libspeex/ltp_sse.h; sourceTree = SOURCE_ROOT; }; + 73814B330907FC9900C478FC /* ltp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ltp.c; path = ../libspeex/ltp.c; sourceTree = SOURCE_ROOT; }; + 73814B340907FC9900C478FC /* ltp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ltp.h; path = ../libspeex/ltp.h; sourceTree = SOURCE_ROOT; }; + 73814B380907FC9900C478FC /* math_approx.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = math_approx.h; path = ../libspeex/math_approx.h; sourceTree = SOURCE_ROOT; }; + 73814B3A0907FC9900C478FC /* misc_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = misc_bfin.h; path = ../libspeex/misc_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B3D0907FC9900C478FC /* modes.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = modes.c; path = ../libspeex/modes.c; sourceTree = SOURCE_ROOT; }; + 73814B3E0907FC9900C478FC /* modes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = modes.h; path = ../libspeex/modes.h; sourceTree = SOURCE_ROOT; }; + 73814B3F0907FC9900C478FC /* nb_celp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = nb_celp.c; path = ../libspeex/nb_celp.c; sourceTree = SOURCE_ROOT; }; + 73814B400907FC9900C478FC /* nb_celp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = nb_celp.h; path = ../libspeex/nb_celp.h; sourceTree = SOURCE_ROOT; }; + 73814B420907FC9900C478FC /* quant_lsp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = quant_lsp.c; path = ../libspeex/quant_lsp.c; sourceTree = SOURCE_ROOT; }; + 73814B430907FC9900C478FC /* quant_lsp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = quant_lsp.h; path = ../libspeex/quant_lsp.h; sourceTree = SOURCE_ROOT; }; + 73814B440907FC9900C478FC /* sb_celp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = sb_celp.c; path = ../libspeex/sb_celp.c; sourceTree = SOURCE_ROOT; }; + 73814B450907FC9900C478FC /* sb_celp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = sb_celp.h; path = ../libspeex/sb_celp.h; sourceTree = SOURCE_ROOT; }; + 73814B460907FC9900C478FC /* smallft.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = smallft.c; path = ../libspeex/smallft.c; sourceTree = SOURCE_ROOT; }; + 73814B470907FC9900C478FC /* smallft.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = smallft.h; path = ../libspeex/smallft.h; sourceTree = SOURCE_ROOT; }; + 73814B480907FC9900C478FC /* speex_callbacks.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = speex_callbacks.c; path = ../libspeex/speex_callbacks.c; sourceTree = SOURCE_ROOT; }; + 73814B490907FC9900C478FC /* speex_header.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = speex_header.c; path = ../libspeex/speex_header.c; sourceTree = SOURCE_ROOT; }; + 73814B4A0907FC9900C478FC /* speex.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = speex.c; path = ../libspeex/speex.c; sourceTree = SOURCE_ROOT; }; + 73814B4B0907FC9900C478FC /* stack_alloc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = stack_alloc.h; path = ../libspeex/stack_alloc.h; sourceTree = SOURCE_ROOT; }; + 73814B4C0907FC9900C478FC /* stereo.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stereo.c; path = ../libspeex/stereo.c; sourceTree = SOURCE_ROOT; }; + 73814B4F0907FC9900C478FC /* testenc_uwb.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testenc_uwb.c; path = ../libspeex/testenc_uwb.c; sourceTree = SOURCE_ROOT; }; + 73814B500907FC9900C478FC /* testenc_wb.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testenc_wb.c; path = ../libspeex/testenc_wb.c; sourceTree = SOURCE_ROOT; }; + 73814B510907FC9900C478FC /* testenc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testenc.c; path = ../libspeex/testenc.c; sourceTree = SOURCE_ROOT; }; + 73814B520907FC9900C478FC /* vbr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = vbr.c; path = ../libspeex/vbr.c; sourceTree = SOURCE_ROOT; }; + 73814B530907FC9900C478FC /* vbr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vbr.h; path = ../libspeex/vbr.h; sourceTree = SOURCE_ROOT; }; + 73814B540907FC9900C478FC /* vq_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq_arm4.h; path = ../libspeex/vq_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B550907FC9900C478FC /* vq_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq_bfin.h; path = ../libspeex/vq_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B560907FC9900C478FC /* vq_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq_sse.h; path = ../libspeex/vq_sse.h; sourceTree = SOURCE_ROOT; }; + 73814B570907FC9900C478FC /* vq.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = vq.c; path = ../libspeex/vq.c; sourceTree = SOURCE_ROOT; }; + 73814B580907FC9900C478FC /* vq.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq.h; path = ../libspeex/vq.h; sourceTree = SOURCE_ROOT; }; + 738837460B193581005C7A69 /* _kiss_fft_guts.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = _kiss_fft_guts.h; path = ../libspeex/_kiss_fft_guts.h; sourceTree = SOURCE_ROOT; }; + 738837470B193581005C7A69 /* fftwrap.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = fftwrap.c; path = ../libspeex/fftwrap.c; sourceTree = SOURCE_ROOT; }; + 738837480B193581005C7A69 /* fftwrap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fftwrap.h; path = ../libspeex/fftwrap.h; sourceTree = SOURCE_ROOT; }; + 7388374B0B193581005C7A69 /* kiss_fft.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = kiss_fft.c; path = ../libspeex/kiss_fft.c; sourceTree = SOURCE_ROOT; }; + 7388374C0B193581005C7A69 /* kiss_fft.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = kiss_fft.h; path = ../libspeex/kiss_fft.h; sourceTree = SOURCE_ROOT; }; + 7388374D0B193581005C7A69 /* kiss_fftr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = kiss_fftr.c; path = ../libspeex/kiss_fftr.c; sourceTree = SOURCE_ROOT; }; + 7388374E0B193581005C7A69 /* kiss_fftr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = kiss_fftr.h; path = ../libspeex/kiss_fftr.h; sourceTree = SOURCE_ROOT; }; + 7388374F0B193581005C7A69 /* lsp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = lsp_bfin.h; path = ../libspeex/lsp_bfin.h; sourceTree = SOURCE_ROOT; }; + 738837500B193581005C7A69 /* pseudofloat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = pseudofloat.h; path = ../libspeex/pseudofloat.h; sourceTree = SOURCE_ROOT; }; + 738837510B193581005C7A69 /* quant_lsp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = quant_lsp_bfin.h; path = ../libspeex/quant_lsp_bfin.h; sourceTree = SOURCE_ROOT; }; + 738837520B193581005C7A69 /* vorbis_psy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = vorbis_psy.c; path = ../libspeex/vorbis_psy.c; sourceTree = SOURCE_ROOT; }; + 738837530B193581005C7A69 /* vorbis_psy.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vorbis_psy.h; path = ../libspeex/vorbis_psy.h; sourceTree = SOURCE_ROOT; }; + 738837770B193667005C7A69 /* libspeex.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libspeex.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8D07F2C80486CC7A007CD1D0 /* Speex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Speex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BFF73DCF0A78AA170078A4A8 /* window.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = window.c; path = ../libspeex/window.c; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 738837750B193667005C7A69 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DDFF38A45A11DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 8D07F2C80486CC7A007CD1D0 /* Speex.framework */, + 738837770B193667005C7A69 /* libspeex.a */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* Speex */ = { + isa = PBXGroup; + children = ( + 08FB77ACFE841707C02AAC07 /* Source */, + 73814AEB0907FB6400C478FC /* Headers */, + 089C1665FE841158C02AAC07 /* Resources */, + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, + 034768DDFF38A45A11DB9C8B /* Products */, + ); + name = Speex; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C1665FE841158C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 8D07F2C70486CC7A007CD1D0 /* Info.plist */, + 089C1666FE841158C02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77ACFE841707C02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 37CA8DFF0DD7352A005C8CB6 /* os_support.h */, + 37CA8DEA0DD73333005C8CB6 /* modes_wb.c */, + 738837460B193581005C7A69 /* _kiss_fft_guts.h */, + 738837470B193581005C7A69 /* fftwrap.c */, + 738837480B193581005C7A69 /* fftwrap.h */, + 7388374B0B193581005C7A69 /* kiss_fft.c */, + 7388374C0B193581005C7A69 /* kiss_fft.h */, + 7388374D0B193581005C7A69 /* kiss_fftr.c */, + 7388374E0B193581005C7A69 /* kiss_fftr.h */, + 7388374F0B193581005C7A69 /* lsp_bfin.h */, + 738837500B193581005C7A69 /* pseudofloat.h */, + 738837510B193581005C7A69 /* quant_lsp_bfin.h */, + 738837520B193581005C7A69 /* vorbis_psy.c */, + 738837530B193581005C7A69 /* vorbis_psy.h */, + 73814B0C0907FC9900C478FC /* arch.h */, + 73814B0D0907FC9900C478FC /* bits.c */, + 73814B0E0907FC9900C478FC /* cb_search_arm4.h */, + 73814B0F0907FC9900C478FC /* cb_search_bfin.h */, + 73814B100907FC9900C478FC /* cb_search_sse.h */, + BFF73DCF0A78AA170078A4A8 /* window.c */, + 73814B110907FC9900C478FC /* cb_search.c */, + 73814B120907FC9900C478FC /* cb_search.h */, + 73814B130907FC9900C478FC /* exc_5_64_table.c */, + 73814B140907FC9900C478FC /* exc_5_256_table.c */, + 73814B150907FC9900C478FC /* exc_8_128_table.c */, + 73814B160907FC9900C478FC /* exc_10_16_table.c */, + 73814B170907FC9900C478FC /* exc_10_32_table.c */, + 73814B180907FC9900C478FC /* exc_20_32_table.c */, + 73814B190907FC9900C478FC /* filters_arm4.h */, + 73814B1A0907FC9900C478FC /* filters_bfin.h */, + 73814B1B0907FC9900C478FC /* filters_sse.h */, + 73814B1C0907FC9900C478FC /* filters.c */, + 73814B1D0907FC9900C478FC /* filters.h */, + 73814B1E0907FC9900C478FC /* fixed_arm4.h */, + 73814B1F0907FC9900C478FC /* fixed_arm5e.h */, + 73814B200907FC9900C478FC /* fixed_bfin.h */, + 73814B210907FC9900C478FC /* fixed_debug.h */, + 73814B220907FC9900C478FC /* fixed_generic.h */, + 73814B230907FC9900C478FC /* gain_table_lbr.c */, + 73814B240907FC9900C478FC /* gain_table.c */, + 73814B250907FC9900C478FC /* hexc_10_32_table.c */, + 73814B260907FC9900C478FC /* hexc_table.c */, + 73814B270907FC9900C478FC /* high_lsp_tables.c */, + 73814B2A0907FC9900C478FC /* lpc_bfin.h */, + 73814B2B0907FC9900C478FC /* lpc.c */, + 73814B2C0907FC9900C478FC /* lpc.h */, + 73814B2D0907FC9900C478FC /* lsp_tables_nb.c */, + 73814B2E0907FC9900C478FC /* lsp.c */, + 73814B2F0907FC9900C478FC /* lsp.h */, + 73814B300907FC9900C478FC /* ltp_arm4.h */, + 73814B310907FC9900C478FC /* ltp_bfin.h */, + 73814B320907FC9900C478FC /* ltp_sse.h */, + 73814B330907FC9900C478FC /* ltp.c */, + 73814B340907FC9900C478FC /* ltp.h */, + 73814B380907FC9900C478FC /* math_approx.h */, + 73814B3A0907FC9900C478FC /* misc_bfin.h */, + 73814B3D0907FC9900C478FC /* modes.c */, + 73814B3E0907FC9900C478FC /* modes.h */, + 73814B3F0907FC9900C478FC /* nb_celp.c */, + 73814B400907FC9900C478FC /* nb_celp.h */, + 73814B420907FC9900C478FC /* quant_lsp.c */, + 73814B430907FC9900C478FC /* quant_lsp.h */, + 73814B440907FC9900C478FC /* sb_celp.c */, + 73814B450907FC9900C478FC /* sb_celp.h */, + 73814B460907FC9900C478FC /* smallft.c */, + 73814B470907FC9900C478FC /* smallft.h */, + 73814B480907FC9900C478FC /* speex_callbacks.c */, + 73814B490907FC9900C478FC /* speex_header.c */, + 73814B4A0907FC9900C478FC /* speex.c */, + 73814B4B0907FC9900C478FC /* stack_alloc.h */, + 73814B4C0907FC9900C478FC /* stereo.c */, + 73814B4F0907FC9900C478FC /* testenc_uwb.c */, + 73814B500907FC9900C478FC /* testenc_wb.c */, + 73814B510907FC9900C478FC /* testenc.c */, + 73814B520907FC9900C478FC /* vbr.c */, + 73814B530907FC9900C478FC /* vbr.h */, + 73814B540907FC9900C478FC /* vq_arm4.h */, + 73814B550907FC9900C478FC /* vq_bfin.h */, + 73814B560907FC9900C478FC /* vq_sse.h */, + 73814B570907FC9900C478FC /* vq.c */, + 73814B580907FC9900C478FC /* vq.h */, + 32BAE0B70371A74B00C91783 /* Speex_Prefix.pch */, + ); + name = Source; + sourceTree = ""; + }; + 73814AEB0907FB6400C478FC /* Headers */ = { + isa = PBXGroup; + children = ( + 73814AEC0907FB8200C478FC /* speex */, + ); + name = Headers; + sourceTree = ""; + }; + 73814AEC0907FB8200C478FC /* speex */ = { + isa = PBXGroup; + children = ( + 73814AEF0907FB8200C478FC /* speex.h */, + 73814AF00907FB8200C478FC /* speex_bits.h */, + 73814AF10907FB8200C478FC /* speex_callbacks.h */, + 73814AF40907FB8200C478FC /* speex_header.h */, + 73814AF70907FB8200C478FC /* speex_stereo.h */, + 73814AF80907FB8200C478FC /* speex_types.h */, + ); + name = speex; + path = ../include/speex; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 738837730B193667005C7A69 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 73814B000907FB8200C478FC /* speex_header.h in Headers */, + 73814B030907FB8200C478FC /* speex_stereo.h in Headers */, + 73814B040907FB8200C478FC /* speex_types.h in Headers */, + 73814B060907FBAB00C478FC /* speex_callbacks.h in Headers */, + 73814B070907FBAD00C478FC /* speex_bits.h in Headers */, + 73814B080907FBAE00C478FC /* speex.h in Headers */, + 738837540B193581005C7A69 /* _kiss_fft_guts.h in Headers */, + 738837560B193581005C7A69 /* fftwrap.h in Headers */, + 7388375A0B193581005C7A69 /* kiss_fft.h in Headers */, + 7388375C0B193581005C7A69 /* kiss_fftr.h in Headers */, + 7388375D0B193581005C7A69 /* lsp_bfin.h in Headers */, + 7388375E0B193581005C7A69 /* pseudofloat.h in Headers */, + 7388375F0B193581005C7A69 /* quant_lsp_bfin.h in Headers */, + 738837610B193581005C7A69 /* vorbis_psy.h in Headers */, + 37CA8E000DD7352A005C8CB6 /* os_support.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 738837760B193667005C7A69 /* libspeex (static) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 738837780B193687005C7A69 /* Build configuration list for PBXNativeTarget "libspeex (static)" */; + buildPhases = ( + 738837730B193667005C7A69 /* Headers */, + 738837740B193667005C7A69 /* Sources */, + 738837750B193667005C7A69 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "libspeex (static)"; + productName = speex; + productReference = 738837770B193667005C7A69 /* libspeex.a */; + productType = "com.apple.product-type.library.static"; + }; + 8D07F2BC0486CC7A007CD1D0 /* Speex */ = { + isa = PBXNativeTarget; + buildConfigurationList = 73814ADF0907FB1E00C478FC /* Build configuration list for PBXNativeTarget "Speex" */; + buildPhases = ( + 8D07F2BD0486CC7A007CD1D0 /* Headers */, + 8D07F2BF0486CC7A007CD1D0 /* Resources */, + 8D07F2C10486CC7A007CD1D0 /* Sources */, + 8D07F2C30486CC7A007CD1D0 /* Frameworks */, + 8D07F2C50486CC7A007CD1D0 /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Speex; + productInstallPath = "$(HOME)/Library/Frameworks"; + productName = Speex; + productReference = 8D07F2C80486CC7A007CD1D0 /* Speex.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 73814AE30907FB1E00C478FC /* Build configuration list for PBXProject "Speex" */; + compatibilityVersion = "Xcode 2.4"; + hasScannedForEncodings = 1; + mainGroup = 0867D691FE84028FC02AAC07 /* Speex */; + productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; + projectDirPath = ""; + projectRoot = ..; + targets = ( + 8D07F2BC0486CC7A007CD1D0 /* Speex */, + 738837760B193667005C7A69 /* libspeex (static) */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 8D07F2C50486CC7A007CD1D0 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 738837740B193667005C7A69 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7388377B0B193784005C7A69 /* bits.c in Sources */, + 7388377C0B193785005C7A69 /* cb_search.c in Sources */, + 7388377D0B193788005C7A69 /* exc_10_16_table.c in Sources */, + 7388377E0B193789005C7A69 /* exc_10_32_table.c in Sources */, + 7388377F0B19378A005C7A69 /* exc_20_32_table.c in Sources */, + 738837800B19378A005C7A69 /* exc_5_256_table.c in Sources */, + 738837810B19378C005C7A69 /* exc_5_64_table.c in Sources */, + 738837820B19378E005C7A69 /* exc_8_128_table.c in Sources */, + 738837830B193791005C7A69 /* fftwrap.c in Sources */, + 738837850B193793005C7A69 /* filters.c in Sources */, + 738837860B193795005C7A69 /* gain_table.c in Sources */, + 738837870B193796005C7A69 /* gain_table_lbr.c in Sources */, + 738837880B193799005C7A69 /* hexc_10_32_table.c in Sources */, + 738837890B19379B005C7A69 /* hexc_table.c in Sources */, + 7388378A0B19379E005C7A69 /* high_lsp_tables.c in Sources */, + 7388378C0B1937A4005C7A69 /* kiss_fft.c in Sources */, + 7388378D0B1937A9005C7A69 /* kiss_fftr.c in Sources */, + 7388378F0B1937B0005C7A69 /* lpc.c in Sources */, + 738837900B1937B0005C7A69 /* lsp.c in Sources */, + 738837910B1937B5005C7A69 /* lsp_tables_nb.c in Sources */, + 738837920B1937B7005C7A69 /* ltp.c in Sources */, + 738837960B1937BE005C7A69 /* modes.c in Sources */, + 738837970B1937C0005C7A69 /* nb_celp.c in Sources */, + 738837990B1937C4005C7A69 /* quant_lsp.c in Sources */, + 7388379A0B1937C6005C7A69 /* sb_celp.c in Sources */, + 7388379B0B1937C9005C7A69 /* smallft.c in Sources */, + 7388379C0B1937CB005C7A69 /* speex.c in Sources */, + 7388379D0B1937CE005C7A69 /* speex_callbacks.c in Sources */, + 7388379E0B1937D0005C7A69 /* speex_header.c in Sources */, + 7388379F0B1937D1005C7A69 /* stereo.c in Sources */, + 738837A00B1937DA005C7A69 /* vbr.c in Sources */, + 738837A10B1937DD005C7A69 /* vorbis_psy.c in Sources */, + 738837A20B1937DF005C7A69 /* vq.c in Sources */, + 738837A30B1937E1005C7A69 /* window.c in Sources */, + 37CA8DEC0DD73333005C8CB6 /* modes_wb.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2C10486CC7A007CD1D0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 73814B5A0907FC9900C478FC /* bits.c in Sources */, + 73814B5E0907FC9900C478FC /* cb_search.c in Sources */, + 73814B600907FC9900C478FC /* exc_5_64_table.c in Sources */, + 73814B610907FC9900C478FC /* exc_5_256_table.c in Sources */, + 73814B620907FC9900C478FC /* exc_8_128_table.c in Sources */, + 73814B630907FC9900C478FC /* exc_10_16_table.c in Sources */, + 73814B640907FC9900C478FC /* exc_10_32_table.c in Sources */, + 73814B650907FC9900C478FC /* exc_20_32_table.c in Sources */, + 73814B690907FC9900C478FC /* filters.c in Sources */, + 73814B700907FC9900C478FC /* gain_table_lbr.c in Sources */, + 73814B710907FC9900C478FC /* gain_table.c in Sources */, + 73814B720907FC9900C478FC /* hexc_10_32_table.c in Sources */, + 73814B730907FC9900C478FC /* hexc_table.c in Sources */, + 73814B740907FC9900C478FC /* high_lsp_tables.c in Sources */, + 73814B780907FC9900C478FC /* lpc.c in Sources */, + 73814B7A0907FC9900C478FC /* lsp_tables_nb.c in Sources */, + 73814B7B0907FC9900C478FC /* lsp.c in Sources */, + 73814B800907FC9900C478FC /* ltp.c in Sources */, + 73814B8A0907FC9900C478FC /* modes.c in Sources */, + 73814B8C0907FC9900C478FC /* nb_celp.c in Sources */, + 73814B8F0907FC9900C478FC /* quant_lsp.c in Sources */, + 73814B910907FC9900C478FC /* sb_celp.c in Sources */, + 73814B930907FC9900C478FC /* smallft.c in Sources */, + 73814B950907FC9900C478FC /* speex_callbacks.c in Sources */, + 73814B960907FC9900C478FC /* speex_header.c in Sources */, + 73814B970907FC9900C478FC /* speex.c in Sources */, + 73814B990907FC9900C478FC /* stereo.c in Sources */, + 73814B9F0907FC9900C478FC /* vbr.c in Sources */, + 73814BA40907FC9900C478FC /* vq.c in Sources */, + BFF73DD00A78AA170078A4A8 /* window.c in Sources */, + 738837550B193581005C7A69 /* fftwrap.c in Sources */, + 738837590B193581005C7A69 /* kiss_fft.c in Sources */, + 7388375B0B193581005C7A69 /* kiss_fftr.c in Sources */, + 738837600B193581005C7A69 /* vorbis_psy.c in Sources */, + 37CA8DEB0DD73333005C8CB6 /* modes_wb.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C1667FE841158C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 73814AE00907FB1E00C478FC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Speex_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Frameworks; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + PRODUCT_NAME = Speex; + WRAPPER_EXTENSION = framework; + ZERO_LINK = YES; + }; + name = Debug; + }; + 73814AE10907FB1E00C478FC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Speex_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Frameworks; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + PRODUCT_NAME = Speex; + WRAPPER_EXTENSION = framework; + ZERO_LINK = NO; + }; + name = Release; + }; + 73814AE40907FB1E00C478FC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + __MACOSX__, + FLOATING_POINT, + "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1)", + ); + GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1 = "EXPORT=__attribute__((visibility(\\\"default\\\")))"; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Debug; + }; + 73814AE50907FB1E00C478FC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + __MACOSX__, + FLOATING_POINT, + "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1)", + ); + GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1 = "EXPORT=__attribute__((visibility(\\\"default\\\")))"; + OTHER_CFLAGS = ( + "$(OTHER_CFLAGS)", + "-falign-loops=16", + ); + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Release; + }; + 738837790B193687005C7A69 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = speex; + ZERO_LINK = YES; + }; + name = Debug; + }; + 7388377A0B193687005C7A69 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = speex; + ZERO_LINK = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 73814ADF0907FB1E00C478FC /* Build configuration list for PBXNativeTarget "Speex" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73814AE00907FB1E00C478FC /* Debug */, + 73814AE10907FB1E00C478FC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 73814AE30907FB1E00C478FC /* Build configuration list for PBXProject "Speex" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73814AE40907FB1E00C478FC /* Debug */, + 73814AE50907FB1E00C478FC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 738837780B193687005C7A69 /* Build configuration list for PBXNativeTarget "libspeex (static)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 738837790B193687005C7A69 /* Debug */, + 7388377A0B193687005C7A69 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/native/codec/libraries/speex/macosx/Speex_Prefix.pch b/native/codec/libraries/speex/macosx/Speex_Prefix.pch new file mode 100644 index 0000000..13abf5e --- /dev/null +++ b/native/codec/libraries/speex/macosx/Speex_Prefix.pch @@ -0,0 +1,5 @@ +// +// Prefix header for all source files of the 'Speex' target in the 'Speex' project. +// + +#include diff --git a/native/codec/libraries/speex/macosx/Speex_UB.xcodeproj/project.pbxproj b/native/codec/libraries/speex/macosx/Speex_UB.xcodeproj/project.pbxproj new file mode 100644 index 0000000..49b0fb9 --- /dev/null +++ b/native/codec/libraries/speex/macosx/Speex_UB.xcodeproj/project.pbxproj @@ -0,0 +1,578 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 73814B000907FB8200C478FC /* speex_header.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF40907FB8200C478FC /* speex_header.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B030907FB8200C478FC /* speex_stereo.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF70907FB8200C478FC /* speex_stereo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B040907FB8200C478FC /* speex_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF80907FB8200C478FC /* speex_types.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B060907FBAB00C478FC /* speex_callbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF10907FB8200C478FC /* speex_callbacks.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B070907FBAD00C478FC /* speex_bits.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AF00907FB8200C478FC /* speex_bits.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B080907FBAE00C478FC /* speex.h in Headers */ = {isa = PBXBuildFile; fileRef = 73814AEF0907FB8200C478FC /* speex.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 73814B5A0907FC9900C478FC /* bits.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B0D0907FC9900C478FC /* bits.c */; }; + 73814B5E0907FC9900C478FC /* cb_search.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B110907FC9900C478FC /* cb_search.c */; }; + 73814B600907FC9900C478FC /* exc_5_64_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B130907FC9900C478FC /* exc_5_64_table.c */; }; + 73814B610907FC9900C478FC /* exc_5_256_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B140907FC9900C478FC /* exc_5_256_table.c */; }; + 73814B620907FC9900C478FC /* exc_8_128_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B150907FC9900C478FC /* exc_8_128_table.c */; }; + 73814B630907FC9900C478FC /* exc_10_16_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B160907FC9900C478FC /* exc_10_16_table.c */; }; + 73814B640907FC9900C478FC /* exc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B170907FC9900C478FC /* exc_10_32_table.c */; }; + 73814B650907FC9900C478FC /* exc_20_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B180907FC9900C478FC /* exc_20_32_table.c */; }; + 73814B690907FC9900C478FC /* filters.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B1C0907FC9900C478FC /* filters.c */; }; + 73814B700907FC9900C478FC /* gain_table_lbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B230907FC9900C478FC /* gain_table_lbr.c */; }; + 73814B710907FC9900C478FC /* gain_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B240907FC9900C478FC /* gain_table.c */; }; + 73814B720907FC9900C478FC /* hexc_10_32_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B250907FC9900C478FC /* hexc_10_32_table.c */; }; + 73814B730907FC9900C478FC /* hexc_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B260907FC9900C478FC /* hexc_table.c */; }; + 73814B740907FC9900C478FC /* high_lsp_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B270907FC9900C478FC /* high_lsp_tables.c */; }; + 73814B760907FC9900C478FC /* lbr_48k_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B290907FC9900C478FC /* lbr_48k_tables.c */; }; + 73814B780907FC9900C478FC /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2B0907FC9900C478FC /* lpc.c */; }; + 73814B7A0907FC9900C478FC /* lsp_tables_nb.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2D0907FC9900C478FC /* lsp_tables_nb.c */; }; + 73814B7B0907FC9900C478FC /* lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B2E0907FC9900C478FC /* lsp.c */; }; + 73814B800907FC9900C478FC /* ltp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B330907FC9900C478FC /* ltp.c */; }; + 73814B840907FC9900C478FC /* math_approx.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B370907FC9900C478FC /* math_approx.c */; }; + 73814B880907FC9900C478FC /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3B0907FC9900C478FC /* misc.c */; }; + 73814B8A0907FC9900C478FC /* modes.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3D0907FC9900C478FC /* modes.c */; }; + 73814B8C0907FC9900C478FC /* nb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B3F0907FC9900C478FC /* nb_celp.c */; }; + 73814B8F0907FC9900C478FC /* quant_lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B420907FC9900C478FC /* quant_lsp.c */; }; + 73814B910907FC9900C478FC /* sb_celp.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B440907FC9900C478FC /* sb_celp.c */; }; + 73814B930907FC9900C478FC /* smallft.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B460907FC9900C478FC /* smallft.c */; }; + 73814B950907FC9900C478FC /* speex_callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B480907FC9900C478FC /* speex_callbacks.c */; }; + 73814B960907FC9900C478FC /* speex_header.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B490907FC9900C478FC /* speex_header.c */; }; + 73814B970907FC9900C478FC /* speex.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4A0907FC9900C478FC /* speex.c */; }; + 73814B990907FC9900C478FC /* stereo.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B4C0907FC9900C478FC /* stereo.c */; }; + 73814B9F0907FC9900C478FC /* vbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B520907FC9900C478FC /* vbr.c */; }; + 73814BA40907FC9900C478FC /* vq.c in Sources */ = {isa = PBXBuildFile; fileRef = 73814B570907FC9900C478FC /* vq.c */; }; + 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildStyle section */ + 4F0BB7EC011F40E904CA0E50 /* Development */ = { + isa = PBXBuildStyle; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + ZERO_LINK = YES; + }; + name = Development; + }; + 4F0BB7ED011F40E904CA0E50 /* Deployment */ = { + isa = PBXBuildStyle; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + ZERO_LINK = NO; + }; + name = Deployment; + }; +/* End PBXBuildStyle section */ + +/* Begin PBXFileReference section */ + 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 32BAE0B70371A74B00C91783 /* Speex_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Speex_Prefix.pch; sourceTree = ""; }; + 73814AEF0907FB8200C478FC /* speex.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex.h; sourceTree = ""; }; + 73814AF00907FB8200C478FC /* speex_bits.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_bits.h; sourceTree = ""; }; + 73814AF10907FB8200C478FC /* speex_callbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_callbacks.h; sourceTree = ""; }; + 73814AF40907FB8200C478FC /* speex_header.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_header.h; sourceTree = ""; }; + 73814AF70907FB8200C478FC /* speex_stereo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_stereo.h; sourceTree = ""; }; + 73814AF80907FB8200C478FC /* speex_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = speex_types.h; sourceTree = ""; }; + 73814B0C0907FC9900C478FC /* arch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = arch.h; path = ../libspeex/arch.h; sourceTree = SOURCE_ROOT; }; + 73814B0D0907FC9900C478FC /* bits.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bits.c; path = ../libspeex/bits.c; sourceTree = SOURCE_ROOT; }; + 73814B0E0907FC9900C478FC /* cb_search_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cb_search_arm4.h; path = ../libspeex/cb_search_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B0F0907FC9900C478FC /* cb_search_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cb_search_bfin.h; path = ../libspeex/cb_search_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B100907FC9900C478FC /* cb_search_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cb_search_sse.h; path = ../libspeex/cb_search_sse.h; sourceTree = SOURCE_ROOT; }; + 73814B110907FC9900C478FC /* cb_search.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = cb_search.c; path = ../libspeex/cb_search.c; sourceTree = SOURCE_ROOT; }; + 73814B120907FC9900C478FC /* cb_search.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cb_search.h; path = ../libspeex/cb_search.h; sourceTree = SOURCE_ROOT; }; + 73814B130907FC9900C478FC /* exc_5_64_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_5_64_table.c; path = ../libspeex/exc_5_64_table.c; sourceTree = SOURCE_ROOT; }; + 73814B140907FC9900C478FC /* exc_5_256_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_5_256_table.c; path = ../libspeex/exc_5_256_table.c; sourceTree = SOURCE_ROOT; }; + 73814B150907FC9900C478FC /* exc_8_128_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_8_128_table.c; path = ../libspeex/exc_8_128_table.c; sourceTree = SOURCE_ROOT; }; + 73814B160907FC9900C478FC /* exc_10_16_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_10_16_table.c; path = ../libspeex/exc_10_16_table.c; sourceTree = SOURCE_ROOT; }; + 73814B170907FC9900C478FC /* exc_10_32_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_10_32_table.c; path = ../libspeex/exc_10_32_table.c; sourceTree = SOURCE_ROOT; }; + 73814B180907FC9900C478FC /* exc_20_32_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = exc_20_32_table.c; path = ../libspeex/exc_20_32_table.c; sourceTree = SOURCE_ROOT; }; + 73814B190907FC9900C478FC /* filters_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filters_arm4.h; path = ../libspeex/filters_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B1A0907FC9900C478FC /* filters_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filters_bfin.h; path = ../libspeex/filters_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B1B0907FC9900C478FC /* filters_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filters_sse.h; path = ../libspeex/filters_sse.h; sourceTree = SOURCE_ROOT; }; + 73814B1C0907FC9900C478FC /* filters.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = filters.c; path = ../libspeex/filters.c; sourceTree = SOURCE_ROOT; }; + 73814B1D0907FC9900C478FC /* filters.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filters.h; path = ../libspeex/filters.h; sourceTree = SOURCE_ROOT; }; + 73814B1E0907FC9900C478FC /* fixed_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_arm4.h; path = ../libspeex/fixed_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B1F0907FC9900C478FC /* fixed_arm5e.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_arm5e.h; path = ../libspeex/fixed_arm5e.h; sourceTree = SOURCE_ROOT; }; + 73814B200907FC9900C478FC /* fixed_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_bfin.h; path = ../libspeex/fixed_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B210907FC9900C478FC /* fixed_debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_debug.h; path = ../libspeex/fixed_debug.h; sourceTree = SOURCE_ROOT; }; + 73814B220907FC9900C478FC /* fixed_generic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fixed_generic.h; path = ../libspeex/fixed_generic.h; sourceTree = SOURCE_ROOT; }; + 73814B230907FC9900C478FC /* gain_table_lbr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = gain_table_lbr.c; path = ../libspeex/gain_table_lbr.c; sourceTree = SOURCE_ROOT; }; + 73814B240907FC9900C478FC /* gain_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = gain_table.c; path = ../libspeex/gain_table.c; sourceTree = SOURCE_ROOT; }; + 73814B250907FC9900C478FC /* hexc_10_32_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hexc_10_32_table.c; path = ../libspeex/hexc_10_32_table.c; sourceTree = SOURCE_ROOT; }; + 73814B260907FC9900C478FC /* hexc_table.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hexc_table.c; path = ../libspeex/hexc_table.c; sourceTree = SOURCE_ROOT; }; + 73814B270907FC9900C478FC /* high_lsp_tables.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = high_lsp_tables.c; path = ../libspeex/high_lsp_tables.c; sourceTree = SOURCE_ROOT; }; + 73814B290907FC9900C478FC /* lbr_48k_tables.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lbr_48k_tables.c; path = ../libspeex/lbr_48k_tables.c; sourceTree = SOURCE_ROOT; }; + 73814B2A0907FC9900C478FC /* lpc_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = lpc_bfin.h; path = ../libspeex/lpc_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B2B0907FC9900C478FC /* lpc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lpc.c; path = ../libspeex/lpc.c; sourceTree = SOURCE_ROOT; }; + 73814B2C0907FC9900C478FC /* lpc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = lpc.h; path = ../libspeex/lpc.h; sourceTree = SOURCE_ROOT; }; + 73814B2D0907FC9900C478FC /* lsp_tables_nb.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lsp_tables_nb.c; path = ../libspeex/lsp_tables_nb.c; sourceTree = SOURCE_ROOT; }; + 73814B2E0907FC9900C478FC /* lsp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lsp.c; path = ../libspeex/lsp.c; sourceTree = SOURCE_ROOT; }; + 73814B2F0907FC9900C478FC /* lsp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = lsp.h; path = ../libspeex/lsp.h; sourceTree = SOURCE_ROOT; }; + 73814B300907FC9900C478FC /* ltp_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ltp_arm4.h; path = ../libspeex/ltp_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B310907FC9900C478FC /* ltp_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ltp_bfin.h; path = ../libspeex/ltp_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B320907FC9900C478FC /* ltp_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ltp_sse.h; path = ../libspeex/ltp_sse.h; sourceTree = SOURCE_ROOT; }; + 73814B330907FC9900C478FC /* ltp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ltp.c; path = ../libspeex/ltp.c; sourceTree = SOURCE_ROOT; }; + 73814B340907FC9900C478FC /* ltp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ltp.h; path = ../libspeex/ltp.h; sourceTree = SOURCE_ROOT; }; + 73814B370907FC9900C478FC /* math_approx.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = math_approx.c; path = ../libspeex/math_approx.c; sourceTree = SOURCE_ROOT; }; + 73814B380907FC9900C478FC /* math_approx.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = math_approx.h; path = ../libspeex/math_approx.h; sourceTree = SOURCE_ROOT; }; + 73814B3A0907FC9900C478FC /* misc_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = misc_bfin.h; path = ../libspeex/misc_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B3B0907FC9900C478FC /* misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = misc.c; path = ../libspeex/misc.c; sourceTree = SOURCE_ROOT; }; + 73814B3C0907FC9900C478FC /* misc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = misc.h; path = ../libspeex/misc.h; sourceTree = SOURCE_ROOT; }; + 73814B3D0907FC9900C478FC /* modes.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = modes.c; path = ../libspeex/modes.c; sourceTree = SOURCE_ROOT; }; + 73814B3E0907FC9900C478FC /* modes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = modes.h; path = ../libspeex/modes.h; sourceTree = SOURCE_ROOT; }; + 73814B3F0907FC9900C478FC /* nb_celp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = nb_celp.c; path = ../libspeex/nb_celp.c; sourceTree = SOURCE_ROOT; }; + 73814B400907FC9900C478FC /* nb_celp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = nb_celp.h; path = ../libspeex/nb_celp.h; sourceTree = SOURCE_ROOT; }; + 73814B420907FC9900C478FC /* quant_lsp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = quant_lsp.c; path = ../libspeex/quant_lsp.c; sourceTree = SOURCE_ROOT; }; + 73814B430907FC9900C478FC /* quant_lsp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = quant_lsp.h; path = ../libspeex/quant_lsp.h; sourceTree = SOURCE_ROOT; }; + 73814B440907FC9900C478FC /* sb_celp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = sb_celp.c; path = ../libspeex/sb_celp.c; sourceTree = SOURCE_ROOT; }; + 73814B450907FC9900C478FC /* sb_celp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = sb_celp.h; path = ../libspeex/sb_celp.h; sourceTree = SOURCE_ROOT; }; + 73814B460907FC9900C478FC /* smallft.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = smallft.c; path = ../libspeex/smallft.c; sourceTree = SOURCE_ROOT; }; + 73814B470907FC9900C478FC /* smallft.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = smallft.h; path = ../libspeex/smallft.h; sourceTree = SOURCE_ROOT; }; + 73814B480907FC9900C478FC /* speex_callbacks.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = speex_callbacks.c; path = ../libspeex/speex_callbacks.c; sourceTree = SOURCE_ROOT; }; + 73814B490907FC9900C478FC /* speex_header.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = speex_header.c; path = ../libspeex/speex_header.c; sourceTree = SOURCE_ROOT; }; + 73814B4A0907FC9900C478FC /* speex.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = speex.c; path = ../libspeex/speex.c; sourceTree = SOURCE_ROOT; }; + 73814B4B0907FC9900C478FC /* stack_alloc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = stack_alloc.h; path = ../libspeex/stack_alloc.h; sourceTree = SOURCE_ROOT; }; + 73814B4C0907FC9900C478FC /* stereo.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stereo.c; path = ../libspeex/stereo.c; sourceTree = SOURCE_ROOT; }; + 73814B4F0907FC9900C478FC /* testenc_uwb.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testenc_uwb.c; path = ../libspeex/testenc_uwb.c; sourceTree = SOURCE_ROOT; }; + 73814B500907FC9900C478FC /* testenc_wb.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testenc_wb.c; path = ../libspeex/testenc_wb.c; sourceTree = SOURCE_ROOT; }; + 73814B510907FC9900C478FC /* testenc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testenc.c; path = ../libspeex/testenc.c; sourceTree = SOURCE_ROOT; }; + 73814B520907FC9900C478FC /* vbr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = vbr.c; path = ../libspeex/vbr.c; sourceTree = SOURCE_ROOT; }; + 73814B530907FC9900C478FC /* vbr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vbr.h; path = ../libspeex/vbr.h; sourceTree = SOURCE_ROOT; }; + 73814B540907FC9900C478FC /* vq_arm4.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq_arm4.h; path = ../libspeex/vq_arm4.h; sourceTree = SOURCE_ROOT; }; + 73814B550907FC9900C478FC /* vq_bfin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq_bfin.h; path = ../libspeex/vq_bfin.h; sourceTree = SOURCE_ROOT; }; + 73814B560907FC9900C478FC /* vq_sse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq_sse.h; path = ../libspeex/vq_sse.h; sourceTree = SOURCE_ROOT; }; + 73814B570907FC9900C478FC /* vq.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = vq.c; path = ../libspeex/vq.c; sourceTree = SOURCE_ROOT; }; + 73814B580907FC9900C478FC /* vq.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = vq.h; path = ../libspeex/vq.h; sourceTree = SOURCE_ROOT; }; + 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8D07F2C80486CC7A007CD1D0 /* Speex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Speex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DDFF38A45A11DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 8D07F2C80486CC7A007CD1D0 /* Speex.framework */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* Speex */ = { + isa = PBXGroup; + children = ( + 08FB77ACFE841707C02AAC07 /* Source */, + 73814AEB0907FB6400C478FC /* Headers */, + 089C1665FE841158C02AAC07 /* Resources */, + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, + 034768DDFF38A45A11DB9C8B /* Products */, + ); + name = Speex; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C1665FE841158C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 8D07F2C70486CC7A007CD1D0 /* Info.plist */, + 089C1666FE841158C02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77ACFE841707C02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 73814B0C0907FC9900C478FC /* arch.h */, + 73814B0D0907FC9900C478FC /* bits.c */, + 73814B0E0907FC9900C478FC /* cb_search_arm4.h */, + 73814B0F0907FC9900C478FC /* cb_search_bfin.h */, + 73814B100907FC9900C478FC /* cb_search_sse.h */, + 73814B110907FC9900C478FC /* cb_search.c */, + 73814B120907FC9900C478FC /* cb_search.h */, + 73814B130907FC9900C478FC /* exc_5_64_table.c */, + 73814B140907FC9900C478FC /* exc_5_256_table.c */, + 73814B150907FC9900C478FC /* exc_8_128_table.c */, + 73814B160907FC9900C478FC /* exc_10_16_table.c */, + 73814B170907FC9900C478FC /* exc_10_32_table.c */, + 73814B180907FC9900C478FC /* exc_20_32_table.c */, + 73814B190907FC9900C478FC /* filters_arm4.h */, + 73814B1A0907FC9900C478FC /* filters_bfin.h */, + 73814B1B0907FC9900C478FC /* filters_sse.h */, + 73814B1C0907FC9900C478FC /* filters.c */, + 73814B1D0907FC9900C478FC /* filters.h */, + 73814B1E0907FC9900C478FC /* fixed_arm4.h */, + 73814B1F0907FC9900C478FC /* fixed_arm5e.h */, + 73814B200907FC9900C478FC /* fixed_bfin.h */, + 73814B210907FC9900C478FC /* fixed_debug.h */, + 73814B220907FC9900C478FC /* fixed_generic.h */, + 73814B230907FC9900C478FC /* gain_table_lbr.c */, + 73814B240907FC9900C478FC /* gain_table.c */, + 73814B250907FC9900C478FC /* hexc_10_32_table.c */, + 73814B260907FC9900C478FC /* hexc_table.c */, + 73814B270907FC9900C478FC /* high_lsp_tables.c */, + 73814B290907FC9900C478FC /* lbr_48k_tables.c */, + 73814B2A0907FC9900C478FC /* lpc_bfin.h */, + 73814B2B0907FC9900C478FC /* lpc.c */, + 73814B2C0907FC9900C478FC /* lpc.h */, + 73814B2D0907FC9900C478FC /* lsp_tables_nb.c */, + 73814B2E0907FC9900C478FC /* lsp.c */, + 73814B2F0907FC9900C478FC /* lsp.h */, + 73814B300907FC9900C478FC /* ltp_arm4.h */, + 73814B310907FC9900C478FC /* ltp_bfin.h */, + 73814B320907FC9900C478FC /* ltp_sse.h */, + 73814B330907FC9900C478FC /* ltp.c */, + 73814B340907FC9900C478FC /* ltp.h */, + 73814B370907FC9900C478FC /* math_approx.c */, + 73814B380907FC9900C478FC /* math_approx.h */, + 73814B3A0907FC9900C478FC /* misc_bfin.h */, + 73814B3B0907FC9900C478FC /* misc.c */, + 73814B3C0907FC9900C478FC /* misc.h */, + 73814B3D0907FC9900C478FC /* modes.c */, + 73814B3E0907FC9900C478FC /* modes.h */, + 73814B3F0907FC9900C478FC /* nb_celp.c */, + 73814B400907FC9900C478FC /* nb_celp.h */, + 73814B420907FC9900C478FC /* quant_lsp.c */, + 73814B430907FC9900C478FC /* quant_lsp.h */, + 73814B440907FC9900C478FC /* sb_celp.c */, + 73814B450907FC9900C478FC /* sb_celp.h */, + 73814B460907FC9900C478FC /* smallft.c */, + 73814B470907FC9900C478FC /* smallft.h */, + 73814B480907FC9900C478FC /* speex_callbacks.c */, + 73814B490907FC9900C478FC /* speex_header.c */, + 73814B4A0907FC9900C478FC /* speex.c */, + 73814B4B0907FC9900C478FC /* stack_alloc.h */, + 73814B4C0907FC9900C478FC /* stereo.c */, + 73814B4F0907FC9900C478FC /* testenc_uwb.c */, + 73814B500907FC9900C478FC /* testenc_wb.c */, + 73814B510907FC9900C478FC /* testenc.c */, + 73814B520907FC9900C478FC /* vbr.c */, + 73814B530907FC9900C478FC /* vbr.h */, + 73814B540907FC9900C478FC /* vq_arm4.h */, + 73814B550907FC9900C478FC /* vq_bfin.h */, + 73814B560907FC9900C478FC /* vq_sse.h */, + 73814B570907FC9900C478FC /* vq.c */, + 73814B580907FC9900C478FC /* vq.h */, + 32BAE0B70371A74B00C91783 /* Speex_Prefix.pch */, + ); + name = Source; + sourceTree = ""; + }; + 73814AEB0907FB6400C478FC /* Headers */ = { + isa = PBXGroup; + children = ( + 73814AEC0907FB8200C478FC /* speex */, + ); + name = Headers; + sourceTree = ""; + }; + 73814AEC0907FB8200C478FC /* speex */ = { + isa = PBXGroup; + children = ( + 73814AEF0907FB8200C478FC /* speex.h */, + 73814AF00907FB8200C478FC /* speex_bits.h */, + 73814AF10907FB8200C478FC /* speex_callbacks.h */, + 73814AF40907FB8200C478FC /* speex_header.h */, + 73814AF70907FB8200C478FC /* speex_stereo.h */, + 73814AF80907FB8200C478FC /* speex_types.h */, + ); + name = speex; + path = ../include/speex; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 73814B000907FB8200C478FC /* speex_header.h in Headers */, + 73814B030907FB8200C478FC /* speex_stereo.h in Headers */, + 73814B040907FB8200C478FC /* speex_types.h in Headers */, + 73814B060907FBAB00C478FC /* speex_callbacks.h in Headers */, + 73814B070907FBAD00C478FC /* speex_bits.h in Headers */, + 73814B080907FBAE00C478FC /* speex.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8D07F2BC0486CC7A007CD1D0 /* Speex */ = { + isa = PBXNativeTarget; + buildConfigurationList = 73814ADF0907FB1E00C478FC /* Build configuration list for PBXNativeTarget "Speex" */; + buildPhases = ( + 8D07F2BD0486CC7A007CD1D0 /* Headers */, + 8D07F2BF0486CC7A007CD1D0 /* Resources */, + 8D07F2C10486CC7A007CD1D0 /* Sources */, + 8D07F2C30486CC7A007CD1D0 /* Frameworks */, + 8D07F2C50486CC7A007CD1D0 /* Rez */, + ); + buildRules = ( + ); + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Speex_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/Frameworks"; + LIBRARY_STYLE = DYNAMIC; + PRODUCT_NAME = Speex; + WRAPPER_EXTENSION = framework; + }; + dependencies = ( + ); + name = Speex; + productInstallPath = "$(HOME)/Library/Frameworks"; + productName = Speex; + productReference = 8D07F2C80486CC7A007CD1D0 /* Speex.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 73814AE30907FB1E00C478FC /* Build configuration list for PBXProject "Speex_UB" */; + buildSettings = { + }; + buildStyles = ( + 4F0BB7EC011F40E904CA0E50 /* Development */, + 4F0BB7ED011F40E904CA0E50 /* Deployment */, + ); + hasScannedForEncodings = 1; + mainGroup = 0867D691FE84028FC02AAC07 /* Speex */; + productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; + projectDirPath = ""; + targets = ( + 8D07F2BC0486CC7A007CD1D0 /* Speex */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 8D07F2C50486CC7A007CD1D0 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D07F2C10486CC7A007CD1D0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 73814B5A0907FC9900C478FC /* bits.c in Sources */, + 73814B5E0907FC9900C478FC /* cb_search.c in Sources */, + 73814B600907FC9900C478FC /* exc_5_64_table.c in Sources */, + 73814B610907FC9900C478FC /* exc_5_256_table.c in Sources */, + 73814B620907FC9900C478FC /* exc_8_128_table.c in Sources */, + 73814B630907FC9900C478FC /* exc_10_16_table.c in Sources */, + 73814B640907FC9900C478FC /* exc_10_32_table.c in Sources */, + 73814B650907FC9900C478FC /* exc_20_32_table.c in Sources */, + 73814B690907FC9900C478FC /* filters.c in Sources */, + 73814B700907FC9900C478FC /* gain_table_lbr.c in Sources */, + 73814B710907FC9900C478FC /* gain_table.c in Sources */, + 73814B720907FC9900C478FC /* hexc_10_32_table.c in Sources */, + 73814B730907FC9900C478FC /* hexc_table.c in Sources */, + 73814B740907FC9900C478FC /* high_lsp_tables.c in Sources */, + 73814B760907FC9900C478FC /* lbr_48k_tables.c in Sources */, + 73814B780907FC9900C478FC /* lpc.c in Sources */, + 73814B7A0907FC9900C478FC /* lsp_tables_nb.c in Sources */, + 73814B7B0907FC9900C478FC /* lsp.c in Sources */, + 73814B800907FC9900C478FC /* ltp.c in Sources */, + 73814B840907FC9900C478FC /* math_approx.c in Sources */, + 73814B880907FC9900C478FC /* misc.c in Sources */, + 73814B8A0907FC9900C478FC /* modes.c in Sources */, + 73814B8C0907FC9900C478FC /* nb_celp.c in Sources */, + 73814B8F0907FC9900C478FC /* quant_lsp.c in Sources */, + 73814B910907FC9900C478FC /* sb_celp.c in Sources */, + 73814B930907FC9900C478FC /* smallft.c in Sources */, + 73814B950907FC9900C478FC /* speex_callbacks.c in Sources */, + 73814B960907FC9900C478FC /* speex_header.c in Sources */, + 73814B970907FC9900C478FC /* speex.c in Sources */, + 73814B990907FC9900C478FC /* stereo.c in Sources */, + 73814B9F0907FC9900C478FC /* vbr.c in Sources */, + 73814BA40907FC9900C478FC /* vq.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C1667FE841158C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 73814AE00907FB1E00C478FC /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Speex_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Frameworks; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + PRODUCT_NAME = Speex; + WRAPPER_EXTENSION = framework; + ZERO_LINK = YES; + }; + name = Development; + }; + 73814AE10907FB1E00C478FC /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Speex_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Frameworks; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + PRODUCT_NAME = Speex; + WRAPPER_EXTENSION = framework; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 73814AE20907FB1E00C478FC /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Speex_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Frameworks; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + PRODUCT_NAME = Speex; + WRAPPER_EXTENSION = framework; + }; + name = Default; + }; + 73814AE40907FB1E00C478FC /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Development; + }; + 73814AE50907FB1E00C478FC /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Deployment; + }; + 73814AE60907FB1E00C478FC /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 73814ADF0907FB1E00C478FC /* Build configuration list for PBXNativeTarget "Speex" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73814AE00907FB1E00C478FC /* Development */, + 73814AE10907FB1E00C478FC /* Deployment */, + 73814AE20907FB1E00C478FC /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 73814AE30907FB1E00C478FC /* Build configuration list for PBXProject "Speex_UB" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73814AE40907FB1E00C478FC /* Development */, + 73814AE50907FB1E00C478FC /* Deployment */, + 73814AE60907FB1E00C478FC /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/native/codec/libraries/speex/speex.m4 b/native/codec/libraries/speex/speex.m4 new file mode 100644 index 0000000..be144e1 --- /dev/null +++ b/native/codec/libraries/speex/speex.m4 @@ -0,0 +1,104 @@ +# Configure paths for libspeex +# Jean-Marc Valin +# Shamelessly stolen from: +# Jack Moffitt 10-21-2000 +# Shamelessly stolen from Owen Taylor and Manish Singh + +dnl XIPH_PATH_SPEEX([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libspeex, and define SPEEX_CFLAGS and SPEEX_LIBS +dnl +AC_DEFUN([XIPH_PATH_SPEEX], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(speex,[ --with-speex=PFX Prefix where libspeex is installed (optional)], speex_prefix="$withval", speex_prefix="") +AC_ARG_WITH(speex-libraries,[ --with-speex-libraries=DIR Directory where libspeex library is installed (optional)], speex_libraries="$withval", speex_libraries="") +AC_ARG_WITH(speex-includes,[ --with-speex-includes=DIR Directory where libspeex header files are installed (optional)], speex_includes="$withval", speex_includes="") +AC_ARG_ENABLE(speextest, [ --disable-speextest Do not try to compile and run a test Speex program],, enable_speextest=yes) + + if test "x$speex_libraries" != "x" ; then + SPEEX_LIBS="-L$speex_libraries" + elif test "x$speex_prefix" != "x" ; then + SPEEX_LIBS="-L$speex_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + SPEEX_LIBS="-L$prefix/lib" + fi + + SPEEX_LIBS="$SPEEX_LIBS -lspeex" + + if test "x$speex_includes" != "x" ; then + SPEEX_CFLAGS="-I$speex_includes" + elif test "x$speex_prefix" != "x" ; then + SPEEX_CFLAGS="-I$speex_prefix/include" + elif test "x$prefix" != "xNONE"; then + SPEEX_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for Speex) + no_speex="" + + + if test "x$enable_speextest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $SPEEX_CFLAGS" + LIBS="$LIBS $SPEEX_LIBS" +dnl +dnl Now check if the installed Speex is sufficiently new. +dnl + rm -f conf.speextest + AC_TRY_RUN([ +#include +#include +#include +#include + +int main () +{ + system("touch conf.speextest"); + return 0; +} + +],, no_speex=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_speex" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.speextest ; then + : + else + echo "*** Could not run Speex test program, checking why..." + CFLAGS="$CFLAGS $SPEEX_CFLAGS" + LIBS="$LIBS $SPEEX_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Speex or finding the wrong" + echo "*** version of Speex. If it is not finding Speex, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means Speex was incorrectly installed" + echo "*** or that you have moved Speex since it was installed." ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + SPEEX_CFLAGS="" + SPEEX_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(SPEEX_CFLAGS) + AC_SUBST(SPEEX_LIBS) + rm -f conf.speextest +]) diff --git a/native/codec/libraries/speex/speex.pc.in b/native/codec/libraries/speex/speex.pc.in new file mode 100644 index 0000000..97bba4f --- /dev/null +++ b/native/codec/libraries/speex/speex.pc.in @@ -0,0 +1,15 @@ +# libspeex pkg-config source file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: speex +Description: Speex is an audio codec tuned for speech +Version: @SPEEX_VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -lspeex +Libs.private: @LIBM@ +Cflags: -I${includedir} diff --git a/native/codec/libraries/speex/speexclient/README b/native/codec/libraries/speex/speexclient/README new file mode 100644 index 0000000..69140d3 --- /dev/null +++ b/native/codec/libraries/speex/speexclient/README @@ -0,0 +1,18 @@ +This is a VERY SIMPLE Speex VoIP client. It is not a complete VoIP application, +isn't compatible with anything else (including probably future versions of +itself) and does not support any form of standard protocols. It is intended +only as a way to show how to use Speex in a VoIP application. + +To use it: + +On Alices machine: +% speexclient plughw:0,0 bob.somewhere.net alice_port bob_port + +On Bob's machine: +% speexclient plughw:0,0 alice.somewhere.net bob_port alice_port + +where bob_port is the UDP port on which bob receives and alice_port is the +UDP port on which alice receives. In most cases, the two ports can be the same. + +Note that the clients do not even know whether they are connected or not. All +they do is send/receive the audio to/from a specific port. diff --git a/native/codec/libraries/speex/speexclient/alsa_device.c b/native/codec/libraries/speex/speexclient/alsa_device.c new file mode 100644 index 0000000..90b9fe4 --- /dev/null +++ b/native/codec/libraries/speex/speexclient/alsa_device.c @@ -0,0 +1,431 @@ +/* + Copyright (C) 2004-2006 Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "alsa_device.h" +#include +#include + +struct AlsaDevice_ { + char *device_name; + int channels; + int period; + snd_pcm_t *capture_handle; + snd_pcm_t *playback_handle; + int readN, writeN; + struct pollfd *read_fd, *write_fd; +}; + +AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period) +{ + int dir; + int err; + snd_pcm_hw_params_t *hw_params; + snd_pcm_sw_params_t *sw_params; + snd_pcm_uframes_t period_size = period; + snd_pcm_uframes_t buffer_size = 2*period; + static snd_output_t *jcd_out; + AlsaDevice *dev = malloc(sizeof(*dev)); + if (!dev) + return NULL; + dev->device_name = malloc(1+strlen(device_name)); + if (!dev->device_name) + { + free(dev); + return NULL; + } + strcpy(dev->device_name, device_name); + dev->channels = channels; + dev->period = period; + err = snd_output_stdio_attach(&jcd_out, stdout, 0); + + if ((err = snd_pcm_open (&dev->capture_handle, dev->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { + fprintf (stderr, "cannot open audio device %s (%s)\n", + dev->device_name, + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_any (dev->capture_handle, hw_params)) < 0) { + fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_access (dev->capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf (stderr, "cannot set access type (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_format (dev->capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + fprintf (stderr, "cannot set sample format (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_rate_near (dev->capture_handle, hw_params, &rate, 0)) < 0) { + fprintf (stderr, "cannot set sample rate (%s)\n", + snd_strerror (err)); + assert(0); + } + /*fprintf (stderr, "rate = %d\n", rate);*/ + + if ((err = snd_pcm_hw_params_set_channels (dev->capture_handle, hw_params, channels)) < 0) { + fprintf (stderr, "cannot set channel count (%s)\n", + snd_strerror (err)); + assert(0); + } + + period_size = period; + dir = 0; + if ((err = snd_pcm_hw_params_set_period_size_near (dev->capture_handle, hw_params, &period_size, &dir)) < 0) { + fprintf (stderr, "cannot set period size (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_periods (dev->capture_handle, hw_params, 2, 0)) < 0) { + fprintf (stderr, "cannot set number of periods (%s)\n", + snd_strerror (err)); + assert(0); + } + + buffer_size = period_size * 2; + dir=0; + if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->capture_handle, hw_params, &buffer_size)) < 0) { + fprintf (stderr, "cannot set buffer time (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params (dev->capture_handle, hw_params)) < 0) { + fprintf (stderr, "cannot set capture parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + /*snd_pcm_dump_setup(dev->capture_handle, jcd_out);*/ + snd_pcm_hw_params_free (hw_params); + + if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { + fprintf (stderr, "cannot allocate software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_current (dev->capture_handle, sw_params)) < 0) { + fprintf (stderr, "cannot initialize software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_avail_min (dev->capture_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set minimum available count (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params (dev->capture_handle, sw_params)) < 0) { + fprintf (stderr, "cannot set software parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + + if ((err = snd_pcm_open (&dev->playback_handle, dev->device_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + fprintf (stderr, "cannot open audio device %s (%s)\n", + dev->device_name, + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_any (dev->playback_handle, hw_params)) < 0) { + fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_access (dev->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf (stderr, "cannot set access type (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_format (dev->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + fprintf (stderr, "cannot set sample format (%s)\n", + snd_strerror (err)); + assert(0); + } + + if ((err = snd_pcm_hw_params_set_rate_near (dev->playback_handle, hw_params, &rate, 0)) < 0) { + fprintf (stderr, "cannot set sample rate (%s)\n", + snd_strerror (err)); + assert(0); + } + /*fprintf (stderr, "rate = %d\n", rate);*/ + + if ((err = snd_pcm_hw_params_set_channels (dev->playback_handle, hw_params, channels)) < 0) { + fprintf (stderr, "cannot set channel count (%s)\n", + snd_strerror (err)); + assert(0); + } + + period_size = period; + dir = 0; + if ((err = snd_pcm_hw_params_set_period_size_near (dev->playback_handle, hw_params, &period_size, &dir)) < 0) { + fprintf (stderr, "cannot set period size (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_hw_params_set_periods (dev->playback_handle, hw_params, 2, 0)) < 0) { + fprintf (stderr, "cannot set number of periods (%s)\n", + snd_strerror (err)); + assert(0); + } + buffer_size = period_size * 2; + dir=0; + if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->playback_handle, hw_params, &buffer_size)) < 0) { + fprintf (stderr, "cannot set buffer time (%s)\n", + snd_strerror (err)); + assert(0); + } + + + if ((err = snd_pcm_hw_params (dev->playback_handle, hw_params)) < 0) { + fprintf (stderr, "cannot set playback parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + /*snd_pcm_dump_setup(dev->playback_handle, jcd_out);*/ + snd_pcm_hw_params_free (hw_params); + + + if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { + fprintf (stderr, "cannot allocate software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_current (dev->playback_handle, sw_params)) < 0) { + fprintf (stderr, "cannot initialize software parameters structure (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_avail_min (dev->playback_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set minimum available count (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params_set_start_threshold (dev->playback_handle, sw_params, period)) < 0) { + fprintf (stderr, "cannot set start mode (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_sw_params (dev->playback_handle, sw_params)) < 0) { + fprintf (stderr, "cannot set software parameters (%s)\n", + snd_strerror (err)); + assert(0); + } + + + snd_pcm_link(dev->capture_handle, dev->playback_handle); + if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + assert(0); + } + if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + assert(0); + } + + dev->readN = snd_pcm_poll_descriptors_count(dev->capture_handle); + dev->writeN = snd_pcm_poll_descriptors_count(dev->playback_handle); + + dev->read_fd = malloc(dev->readN*sizeof(*dev->read_fd)); + /*printf ("descriptors: %d %d\n", dev->readN, dev->writeN);*/ + if (snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd, dev->readN) != dev->readN) + { + fprintf (stderr, "cannot obtain capture file descriptors (%s)\n", + snd_strerror (err)); + assert(0); + } + + dev->write_fd = malloc(dev->writeN*sizeof(*dev->read_fd)); + if (snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd, dev->writeN) != dev->writeN) + { + fprintf (stderr, "cannot obtain playback file descriptors (%s)\n", + snd_strerror (err)); + assert(0); + } + return dev; +} + +void alsa_device_close(AlsaDevice *dev) +{ + snd_pcm_close(dev->capture_handle); + snd_pcm_close(dev->playback_handle); + free(dev->device_name); + free(dev); +} + +int alsa_device_read(AlsaDevice *dev, short *pcm, int len) +{ + int err; + /*fprintf (stderr, "-");*/ + if ((err = snd_pcm_readi (dev->capture_handle, pcm, len)) != len) + { + if (err<0) + { + //fprintf(stderr, "error %d, EPIPE = %d\n", err, EPIPE); + if (err == -EPIPE) + { + fprintf (stderr, "An overrun has occured, reseting capture\n"); + } else + { + fprintf (stderr, "read from audio interface failed (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_start (dev->capture_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + /*alsa_device_read(dev,pcm,len);*/ + } else { + fprintf (stderr, "Couldn't read as many samples as I wanted (%d instead of %d)\n", err, len); + } + return 1; + } + return 0; +} + +int alsa_device_write(AlsaDevice *dev, const short *pcm, int len) +{ + int err; + /*fprintf (stderr, "+");*/ + if ((err = snd_pcm_writei (dev->playback_handle, pcm, len)) != len) + { + if (err<0) + { + if (err == -EPIPE) + { + fprintf (stderr, "An underrun has occured, reseting playback, len=%d\n", len); + } else + { + fprintf (stderr, "write to audio interface failed (%s)\n", + snd_strerror (err)); + } + if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) + { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + } + } else { + fprintf (stderr, "Couldn't write as many samples as I wanted (%d instead of %d)\n", err, len); + } + /*alsa_device_write(dev,pcm,len);*/ + return 1; + } + return 0; +} + +int alsa_device_capture_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + unsigned short revents=0; + int err; + if ((err = snd_pcm_poll_descriptors_revents(dev->capture_handle, pfds, dev->readN, &revents)) < 0) + { + //cerr << "error in snd_pcm_poll_descriptors_revents for capture: " << snd_strerror (err) << endl; + //FIXME: This is a kludge + fprintf (stderr, "error in alsa_device_capture_ready: %s\n", snd_strerror (err)); + return pfds[0].revents & POLLIN; + } + //cerr << (revents & POLLERR) << endl; + return revents & POLLIN; +} + +int alsa_device_playback_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + unsigned short revents=0; + int err; + if ((err = snd_pcm_poll_descriptors_revents(dev->playback_handle, pfds+dev->readN, dev->writeN, &revents)) < 0) + { + //cerr << "error in snd_pcm_poll_descriptors_revents for playback: " << snd_strerror (err) << endl; + //FIXME: This is a kludge + fprintf (stderr, "error in alsa_device_playback_ready: %s\n", snd_strerror (err)); + return pfds[1].revents & POLLOUT; + } + //cerr << (revents & POLLERR) << endl; + return revents & POLLOUT; +} + +void alsa_device_start(AlsaDevice *dev) +{ + int i; + short pcm[dev->period*dev->channels]; + for (i=0;iperiod*dev->channels;i++) + pcm[i] = 0; + alsa_device_write(dev, pcm, dev->period); + alsa_device_write(dev, pcm, dev->period); + snd_pcm_start(dev->capture_handle); + snd_pcm_start(dev->playback_handle); +} + +int alsa_device_nfds(AlsaDevice *dev) +{ + return dev->writeN+dev->readN; +} + +void alsa_device_getfds(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds) +{ + int i; + assert (nfds >= dev->writeN+dev->readN); + for (i=0;ireadN;i++) + pfds[i] = dev->read_fd[i]; + for (i=0;iwriteN;i++) + pfds[i+dev->readN] = dev->write_fd[i]; +} diff --git a/native/codec/libraries/speex/speexclient/alsa_device.h b/native/codec/libraries/speex/speexclient/alsa_device.h new file mode 100644 index 0000000..a5b3787 --- /dev/null +++ b/native/codec/libraries/speex/speexclient/alsa_device.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2004-2006 Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef ALSA_DEVICE_H +#define ALSA_DEVICE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct AlsaDevice_; + +typedef struct AlsaDevice_ AlsaDevice; + +AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period); + +void alsa_device_close(AlsaDevice *dev); + +int alsa_device_read(AlsaDevice *dev, short *pcm, int len); + +int alsa_device_write(AlsaDevice *dev, const short *pcm, int len); + +int alsa_device_capture_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +int alsa_device_playback_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +void alsa_device_start(AlsaDevice *dev); + +int alsa_device_nfds(AlsaDevice *dev); + +void alsa_device_getfds(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/codec/libraries/speex/speexclient/compile.sh b/native/codec/libraries/speex/speexclient/compile.sh new file mode 100755 index 0000000..fae58a0 --- /dev/null +++ b/native/codec/libraries/speex/speexclient/compile.sh @@ -0,0 +1,3 @@ +#!/bin/sh +gcc -Wall -I../include speex_jitter_buffer.c speexclient.c alsa_device.c `pkg-config --cflags speexdsp` -o speexclient -lspeex -lspeexdsp -lasound -lm `pkg-config --libs speexdsp` + diff --git a/native/codec/libraries/speex/speexclient/speex_jitter_buffer.c b/native/codec/libraries/speex/speexclient/speex_jitter_buffer.c new file mode 100644 index 0000000..aa76d26 --- /dev/null +++ b/native/codec/libraries/speex/speexclient/speex_jitter_buffer.c @@ -0,0 +1,91 @@ +#include +#include "speex_jitter_buffer.h" + +#ifndef NULL +#define NULL 0 +#endif + + +void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate) +{ + jitter->dec = decoder; + speex_decoder_ctl(decoder, SPEEX_GET_FRAME_SIZE, &jitter->frame_size); + + jitter->packets = jitter_buffer_init(jitter->frame_size); + + speex_bits_init(&jitter->current_packet); + jitter->valid_bits = 0; + +} + +void speex_jitter_destroy(SpeexJitter *jitter) +{ + jitter_buffer_destroy(jitter->packets); + speex_bits_destroy(&jitter->current_packet); +} + +void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp) +{ + JitterBufferPacket p; + p.data = packet; + p.len = len; + p.timestamp = timestamp; + p.span = jitter->frame_size; + jitter_buffer_put(jitter->packets, &p); +} + +void speex_jitter_get(SpeexJitter *jitter, spx_int16_t *out, int *current_timestamp) +{ + int i; + int ret; + spx_int32_t activity; + char data[2048]; + JitterBufferPacket packet; + packet.data = data; + packet.len = 2048; + + if (jitter->valid_bits) + { + /* Try decoding last received packet */ + ret = speex_decode_int(jitter->dec, &jitter->current_packet, out); + if (ret == 0) + { + jitter_buffer_tick(jitter->packets); + return; + } else { + jitter->valid_bits = 0; + } + } + + ret = jitter_buffer_get(jitter->packets, &packet, jitter->frame_size, NULL); + + if (ret != JITTER_BUFFER_OK) + { + /* No packet found */ + + /*fprintf (stderr, "lost/late frame\n");*/ + /*Packet is late or lost*/ + speex_decode_int(jitter->dec, NULL, out); + } else { + speex_bits_read_from(&jitter->current_packet, packet.data, packet.len); + /* Decode packet */ + ret = speex_decode_int(jitter->dec, &jitter->current_packet, out); + if (ret == 0) + { + jitter->valid_bits = 1; + } else { + /* Error while decoding */ + for (i=0;iframe_size;i++) + out[i]=0; + } + } + speex_decoder_ctl(jitter->dec, SPEEX_GET_ACTIVITY, &activity); + if (activity < 30) + jitter_buffer_update_delay(jitter->packets, &packet, NULL); + jitter_buffer_tick(jitter->packets); +} + +int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter) +{ + return jitter_buffer_get_pointer_timestamp(jitter->packets); +} diff --git a/native/codec/libraries/speex/speexclient/speex_jitter_buffer.h b/native/codec/libraries/speex/speexclient/speex_jitter_buffer.h new file mode 100644 index 0000000..0d81ebb --- /dev/null +++ b/native/codec/libraries/speex/speexclient/speex_jitter_buffer.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file speex_jitter_buffer.h + @brief Adaptive jitter buffer for Speex packets only +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup SpeexJitter SpeexJitter: Adaptive jitter buffer specifically for Speex + * This is the jitter buffer that reorders UDP/RTP packets and adjusts the buffer size + * to maintain good quality and low latency. This is a simplified version that works only + * with Speex, but is much easier to use. + * @{ +*/ + +/** Speex jitter-buffer state. Never use it directly! */ +typedef struct SpeexJitter { + SpeexBits current_packet; /**< Current Speex packet */ + int valid_bits; /**< True if Speex bits are valid */ + JitterBuffer *packets; /**< Generic jitter buffer state */ + void *dec; /**< Pointer to Speex decoder */ + spx_int32_t frame_size; /**< Frame size of Speex decoder */ +} SpeexJitter; + +/** Initialise jitter buffer + * + * @param jitter State of the Speex jitter buffer + * @param decoder Speex decoder to call + * @param sampling_rate Sampling rate used by the decoder +*/ +void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate); + +/** Destroy jitter buffer */ +void speex_jitter_destroy(SpeexJitter *jitter); + +/** Put one packet into the jitter buffer */ +void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp); + +/** Get one packet from the jitter buffer */ +void speex_jitter_get(SpeexJitter *jitter, spx_int16_t *out, int *start_offset); + +/** Get pointer timestamp of jitter buffer */ +int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter); + +#ifdef __cplusplus +} +#endif + +/* @} */ diff --git a/native/codec/libraries/speex/speexclient/speexclient.c b/native/codec/libraries/speex/speexclient/speexclient.c new file mode 100644 index 0000000..116befe --- /dev/null +++ b/native/codec/libraries/speex/speexclient/speexclient.c @@ -0,0 +1,250 @@ +/*************************************************************************** + Copyright (C) 2004-2006 by Jean-Marc Valin + Copyright (C) 2006 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include /* close() */ +#include /* memset() */ + +#include "alsa_device.h" +#include +#include +#include +#include +#include "speex_jitter_buffer.h" + +#include + +#define MAX_MSG 1500 + +#define SAMPLING_RATE 16000 +#define FRAME_SIZE 320 + +int main(int argc, char *argv[]) +{ + + int sd, rc, n; + int i; + struct sockaddr_in cliAddr, remoteAddr; + char msg[MAX_MSG]; + struct hostent *h; + int local_port, remote_port; + int nfds; + struct pollfd *pfds; + SpeexPreprocessState *preprocess; + AlsaDevice *audio_dev; + int tmp; + + if (argc != 5) + { + fprintf(stderr, "wrong options\n"); + exit(1); + } + + h = gethostbyname(argv[2]); + if(h==NULL) { + fprintf(stderr, "%s: unknown host '%s' \n", argv[0], argv[1]); + exit(1); + } + + local_port = atoi(argv[3]); + remote_port = atoi(argv[4]); + + printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name, + inet_ntoa(*(struct in_addr *)h->h_addr_list[0])); + + { + remoteAddr.sin_family = h->h_addrtype; + memcpy((char *) &remoteAddr.sin_addr.s_addr, + h->h_addr_list[0], h->h_length); + remoteAddr.sin_port = htons(remote_port); + } + /* socket creation */ + sd=socket(AF_INET, SOCK_DGRAM, 0); + if(sd<0) { + printf("%s: cannot open socket \n",argv[0]); + exit(1); + } + + /* bind any port */ + cliAddr.sin_family = AF_INET; + cliAddr.sin_addr.s_addr = htonl(INADDR_ANY); + cliAddr.sin_port = htons(local_port); + + rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr)); + if(rc<0) { + printf("%s: cannot bind port\n", argv[0]); + exit(1); + } + + /* Setup audio device */ + audio_dev = alsa_device_open(argv[1], SAMPLING_RATE, 1, FRAME_SIZE); + + /* Setup the encoder and decoder in wideband */ + void *enc_state, *dec_state; + enc_state = speex_encoder_init(&speex_wb_mode); + tmp = 8; + speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp); + tmp = 2; + speex_encoder_ctl(enc_state, SPEEX_SET_COMPLEXITY, &tmp); + dec_state = speex_decoder_init(&speex_wb_mode); + tmp = 1; + speex_decoder_ctl(dec_state, SPEEX_SET_ENH, &tmp); + SpeexBits enc_bits, dec_bits; + speex_bits_init(&enc_bits); + speex_bits_init(&dec_bits); + + + struct sched_param param; + /*param.sched_priority = 40; */ + param.sched_priority = sched_get_priority_min(SCHED_FIFO); + if (sched_setscheduler(0,SCHED_FIFO,¶m)) + perror("sched_setscheduler"); + + int send_timestamp = 0; + int recv_started=0; + + /* Setup all file descriptors for poll()ing */ + nfds = alsa_device_nfds(audio_dev); + pfds = malloc(sizeof(*pfds)*(nfds+1)); + alsa_device_getfds(audio_dev, pfds, nfds); + pfds[nfds].fd = sd; + pfds[nfds].events = POLLIN; + + /* Setup jitter buffer using decoder */ + SpeexJitter jitter; + speex_jitter_init(&jitter, dec_state, SAMPLING_RATE); + + /* Echo canceller with 200 ms tail length */ + SpeexEchoState *echo_state = speex_echo_state_init(FRAME_SIZE, 10*FRAME_SIZE); + tmp = SAMPLING_RATE; + speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp); + + /* Setup preprocessor and associate with echo canceller for residual echo suppression */ + preprocess = speex_preprocess_state_init(FRAME_SIZE, SAMPLING_RATE); + speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE, echo_state); + + alsa_device_start(audio_dev); + + /* Infinite loop on capture, playback and receiving packets */ + while (1) + { + /* Wait for either 1) capture 2) playback 3) socket data */ + poll(pfds, nfds+1, -1); + /* Received packets */ + if (pfds[nfds].revents & POLLIN) + { + /*fprintf (stderr, "x");*/ + n = recv(sd, msg, MAX_MSG, 0); + int recv_timestamp = ((int*)msg)[1]; + int payload = ((int*)msg)[0]; + + if ((payload & 0x80000000) == 0) + { + /* Put content of the packet into the jitter buffer, except for the pseudo-header */ + speex_jitter_put(&jitter, msg+8, n-8, recv_timestamp); + recv_started = 1; + } + + } + /* Ready to play a frame (playback) */ + if (alsa_device_playback_ready(audio_dev, pfds, nfds)) + { + short pcm[FRAME_SIZE]; + if (recv_started) + { + /* Get audio from the jitter buffer */ + speex_jitter_get(&jitter, pcm, NULL); + } else { + for (i=0;i. + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt_win.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +#include + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/native/codec/libraries/speex/src/getopt1.c b/native/codec/libraries/speex/src/getopt1.c new file mode 100644 index 0000000..fe2eb1d --- /dev/null +++ b/native/codec/libraries/speex/src/getopt1.c @@ -0,0 +1,188 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C 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. + + The GNU C 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 the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt_win.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/native/codec/libraries/speex/src/getopt_win.h b/native/codec/libraries/speex/src/getopt_win.h new file mode 100644 index 0000000..b0147e9 --- /dev/null +++ b/native/codec/libraries/speex/src/getopt_win.h @@ -0,0 +1,169 @@ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C 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. + + The GNU C 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 the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +# if defined __STDC__ && __STDC__ + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#if defined __STDC__ && __STDC__ +# ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int __argc, char *const *__argv, const char *__shortopts); +# else /* not __GNU_LIBRARY__ */ +extern int getopt (); +# endif /* __GNU_LIBRARY__ */ + +# ifndef __need_getopt +extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); +# endif +#else /* not __STDC__ */ +extern int getopt (); +# ifndef __need_getopt +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +# endif +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/native/codec/libraries/speex/src/skeleton.c b/native/codec/libraries/speex/src/skeleton.c new file mode 100644 index 0000000..24089cb --- /dev/null +++ b/native/codec/libraries/speex/src/skeleton.c @@ -0,0 +1,188 @@ +/* + * skeleton.c + * author: Tahseen Mohammad + */ + +#include +#include +#include + +#include + +#include "skeleton.h" + +/* write an ogg_page to a file pointer */ +int write_ogg_page_to_file(ogg_page *og, FILE *out) { + int written; + + written = fwrite(og->header,1, og->header_len, out); + written += fwrite(og->body,1, og->body_len, out); + + return written; +} + +int add_message_header_field(fisbone_packet *fp, + char *header_key, + char *header_value) { + + /* size of both key and value + ': ' + CRLF */ + int this_message_size = strlen(header_key) + strlen(header_value) + 4; + if (fp->message_header_fields == NULL) { + fp->message_header_fields = _ogg_calloc(this_message_size, sizeof(char)); + } else { + int new_size = (fp->current_header_size + this_message_size) * sizeof(char); + fp->message_header_fields = _ogg_realloc(fp->message_header_fields, new_size); + } + snprintf(fp->message_header_fields + fp->current_header_size, + this_message_size+1, + "%s: %s\r\n", + header_key, + header_value); + fp->current_header_size += this_message_size; + + return 0; +} + +/* create a ogg_packet from a fishead_packet structure */ +ogg_packet ogg_from_fishead(fishead_packet *fp) { + + ogg_packet op; + + memset(&op, 0, sizeof(op)); + op.packet = _ogg_calloc(FISHEAD_SIZE, sizeof(unsigned char)); + memset(op.packet, 0, FISHEAD_SIZE); + + memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */ + *((ogg_uint16_t*)(op.packet+8)) = SKELETON_VERSION_MAJOR; /* version major */ + *((ogg_uint16_t*)(op.packet+10)) = SKELETON_VERSION_MINOR; /* version minor */ + *((ogg_int64_t*)(op.packet+12)) = (ogg_int64_t)fp->ptime_n; /* presentationtime numerator */ + *((ogg_int64_t*)(op.packet+20)) = (ogg_int64_t)fp->ptime_d; /* presentationtime denominator */ + *((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)fp->btime_n; /* basetime numerator */ + *((ogg_int64_t*)(op.packet+36)) = (ogg_int64_t)fp->btime_d; /* basetime denominator */ + /* TODO: UTC time, set to zero for now */ + + op.b_o_s = 1; /* its the first packet of the stream */ + op.e_o_s = 0; /* its not the last packet of the stream */ + op.bytes = FISHEAD_SIZE; /* length of the packet in bytes */ + + return op; +} + +/* create a ogg_packet from a fisbone_packet structure. + * call this method after the fisbone_packet is filled and all message header fields are added + * by calling add_message_header_field method. + */ +ogg_packet ogg_from_fisbone(fisbone_packet *fp) { + + ogg_packet op; + int packet_size = FISBONE_SIZE + fp->current_header_size; + + memset (&op, 0, sizeof (op)); + op.packet = _ogg_calloc (packet_size, sizeof(unsigned char)); + memset (op.packet, 0, packet_size); + memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */ + *((ogg_uint32_t*)(op.packet+8)) = FISBONE_MESSAGE_HEADER_OFFSET; /* offset of the message header fields */ + *((ogg_uint32_t*)(op.packet+12)) = fp->serial_no; /* serialno of the respective stream */ + *((ogg_uint32_t*)(op.packet+16)) = fp->nr_header_packet; /* number of header packets */ + *((ogg_int64_t*)(op.packet+20)) = fp->granule_rate_n; /* granulrate numerator */ + *((ogg_int64_t*)(op.packet+28)) = fp->granule_rate_d; /* granulrate denominator */ + *((ogg_int64_t*)(op.packet+36)) = fp->start_granule; /* start granule */ + *((ogg_uint32_t*)(op.packet+44)) = fp->preroll; /* preroll, for theora its 0 */ + *(op.packet+48) = fp->granule_shift; /* granule shift */ + memcpy((op.packet+FISBONE_SIZE), fp->message_header_fields, fp->current_header_size); + + op.b_o_s = 0; + op.e_o_s = 0; + op.bytes = packet_size; /* size of the packet in bytes */ + + return op; +} + +/* fills up a fishead_packet from a fishead ogg_packet of a skeleton bistream */ +fishead_packet fishead_from_ogg(ogg_packet *op) { + + fishead_packet fp; + + if (memcmp(op->packet, FISHEAD_IDENTIFIER, 8)) + ; /* invalid packet what do we do? */ + + fp.version_major = *((ogg_uint16_t*)(op->packet+8)); /* version major */ + fp.version_minor = *((ogg_uint16_t*)(op->packet+10)); /* version minor */ + fp.ptime_n = *((ogg_int64_t*)(op->packet+12)); /* presentationtime numerator */ + fp.ptime_d = *((ogg_int64_t*)(op->packet+20)); /* presentationtime denominator */ + fp.btime_n = *((ogg_int64_t*)(op->packet+28)); /* basetime numerator */ + fp.btime_d = *((ogg_int64_t*)(op->packet+36)); /* basetime denominator */ + memcpy(fp.UTC, op->packet+44, 20); + + return fp; +} + +/* fills up a fisbone_packet from a fisbone ogg_packet of a skeleton bitstream */ +fisbone_packet fisbone_from_ogg(ogg_packet *op) { + + fisbone_packet fp; + + if (memcmp(op->packet, FISBONE_IDENTIFIER, 8)) + ; /* invalid value, what do we do? */ + fp.serial_no = *((ogg_uint32_t*)(op->packet+12)); /* serialno of the stream represented by this fisbone packet */ + fp.nr_header_packet = *((ogg_uint32_t*)(op->packet+16)); /* number of header packets */ + fp.granule_rate_n = *((ogg_int64_t*)(op->packet+20)); /* granulrate numerator */ + fp.granule_rate_d = *((ogg_int64_t*)(op->packet+28)); /* granulrate denominator */ + fp.start_granule = *((ogg_int64_t*)(op->packet+36)); /* start granule */ + fp.preroll = *((ogg_uint32_t*)(op->packet+44)); /* preroll, for theora its 0 */ + fp.granule_shift = *(op->packet+48); /* granule shift */ + fp.current_header_size = op->bytes - FISBONE_SIZE; + fp.message_header_fields = _ogg_calloc(fp.current_header_size+1, sizeof(char)); + memcpy(fp.message_header_fields, op->packet+FISBONE_SIZE, fp.current_header_size); + + return fp; +} + +int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) { + + ogg_packet op; + + op = ogg_from_fishead(fp); + ogg_stream_packetin(os, &op); + _ogg_free(op.packet); + + return 0; +} + +int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) { + + ogg_packet op; + + op = ogg_from_fisbone(fp); + ogg_stream_packetin(os, &op); + _ogg_free(op.packet); + + return 0; +} + +int add_eos_packet_to_stream(ogg_stream_state *os) { + + ogg_packet op; + + memset (&op, 0, sizeof(op)); + op.e_o_s = 1; + ogg_stream_packetin(os, &op); + + return 0; +} + +int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) { + + ogg_page og; + int result; + + while((result = ogg_stream_flush(os, &og))) + { + if(!result) break; + result = write_ogg_page_to_file(&og, out); + if(result != og.header_len + og.body_len) + return 1; + } + + return 0; +} diff --git a/native/codec/libraries/speex/src/skeleton.h b/native/codec/libraries/speex/src/skeleton.h new file mode 100644 index 0000000..1559f8f --- /dev/null +++ b/native/codec/libraries/speex/src/skeleton.h @@ -0,0 +1,78 @@ +/* + * skeleton.h + * author: Tahseen Mohammad + */ + +#ifndef _SKELETON_H +#define _SKELETON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +#include + +#define SKELETON_VERSION_MAJOR 3 +#define SKELETON_VERSION_MINOR 0 +#define FISHEAD_IDENTIFIER "fishead\0" +#define FISBONE_IDENTIFIER "fisbone\0" +#define FISHEAD_SIZE 64 +#define FISBONE_SIZE 52 +#define FISBONE_MESSAGE_HEADER_OFFSET 44 + +/* fishead_packet holds a fishead header packet. */ +typedef struct { + ogg_uint16_t version_major; /* skeleton version major */ + ogg_uint16_t version_minor; /* skeleton version minor */ + /* Start time of the presentation + * For a new stream presentationtime & basetime is same. */ + ogg_int64_t ptime_n; /* presentation time numerator */ + ogg_int64_t ptime_d; /* presentation time denominator */ + ogg_int64_t btime_n; /* basetime numerator */ + ogg_int64_t btime_d; /* basetime denominator */ + /* will holds the time of origin of the stream, a 20 bit field. */ + unsigned char UTC[20]; +} fishead_packet; + +/* fisbone_packet holds a fisbone header packet. */ +typedef struct { + ogg_uint32_t serial_no; /* serial no of the corresponding stream */ + ogg_uint32_t nr_header_packet; /* number of header packets */ + /* granule rate is the temporal resolution of the logical bitstream */ + ogg_int64_t granule_rate_n; /* granule rate numerator */ + ogg_int64_t granule_rate_d; /* granule rate denominator */ + ogg_int64_t start_granule; /* start granule value */ + ogg_uint32_t preroll; /* preroll */ + unsigned char granule_shift; /* 1 byte value holding the granule shift */ + char *message_header_fields; /* holds all the message header fields */ + /* current total size of the message header fields, for realloc purpose, initially zero */ + ogg_uint32_t current_header_size; +} fisbone_packet; + +extern int write_ogg_page_to_file(ogg_page *og, FILE *out); +extern int add_message_header_field(fisbone_packet *fp, char *header_key, char *header_value); +/* remember to deallocate the returned ogg_packet properly */ +extern ogg_packet ogg_from_fishead(fishead_packet *fp); +extern ogg_packet ogg_from_fisbone(fisbone_packet *fp); +extern fishead_packet fishead_from_ogg(ogg_packet *op); +extern fisbone_packet fisbone_from_ogg(ogg_packet *op); +extern int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp); +extern int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp); +extern int add_eos_packet_to_stream(ogg_stream_state *os); +extern int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out); + +#ifdef __cplusplus +} +#endif + +#endif /* _SKELETON_H */ + + + + + + diff --git a/native/codec/libraries/speex/src/speexdec.1 b/native/codec/libraries/speex/src/speexdec.1 new file mode 100644 index 0000000..3545f09 --- /dev/null +++ b/native/codec/libraries/speex/src/speexdec.1 @@ -0,0 +1,78 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29. +.TH SPEEXDEC "1" "September 2003" "speexdec version 1.1" "User Commands" +.SH NAME +speexdec \- The reference implementation speex decoder. +.SH SYNOPSIS +.B speexdec +[\fIoptions\fR] \fIinput_file.spx \fR[\fIoutput_file\fR] +.SH DESCRIPTION +Decodes a Speex file and produce a WAV file or raw file +.SS "input_file can be:" +.TP +filename.spx +regular Speex file +.TP +- +stdin +.SS "output_file can be:" +.TP +filename.wav +Wav file +.TP +filename.* +Raw PCM file (any extension other that .wav) +.TP +- +stdout +.TP +(nothing) +Will be played to soundcard +.SH OPTIONS +.TP +\fB\-\-enh\fR +Enable perceptual enhancement (default) +.TP +\fB\-\-no\-enh\fR +Disable perceptual enhancement +.TP +\fB\-\-force\-nb\fR +Force decoding in narrowband +.TP +\fB\-\-force\-wb\fR +Force decoding in wideband +.TP +\fB\-\-force\-uwb\fR +Force decoding in ultra-wideband +.TP +\fB\-\-mono\fR +Force decoding in mono +.TP +\fB\-\-stereo\fR +Force decoding in stereo +.TP +\fB\-\-rate\fR n +Force decoding at sampling rate n Hz +.TP +\fB\-\-packet\-loss\fR n +Simulate n % random packet loss +.TP +\fB\-V\fR +Verbose mode (show bit-rate) +.TP +\fB\-h\fR, \fB\-\-help\fR +This help +.TP +\fB\-v\fR, \fB\-\-version\fR +Version information +.TP +\fB\-\-pf\fR +Deprecated, use \fB\-\-enh\fR instead +.TP +\fB\-\-no\-pf\fR +Deprecated, use \fB\-\-no\-enh\fR instead +.PP +More information is available from the Speex site: http://www.speex.org +.PP +Please report bugs to the mailing list `speex-dev@xiph.org'. +.SH COPYRIGHT +Copyright \(co 2002 Jean-Marc Valin diff --git a/native/codec/libraries/speex/src/speexdec.c b/native/codec/libraries/speex/src/speexdec.c new file mode 100644 index 0000000..4721dc1 --- /dev/null +++ b/native/codec/libraries/speex/src/speexdec.c @@ -0,0 +1,807 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: speexdec.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#if !defined WIN32 && !defined _WIN32 +#include +#endif +#ifdef HAVE_GETOPT_H +#include +#endif +#ifndef HAVE_GETOPT_LONG +#include "getopt_win.h" +#endif +#include +#include + +#include + +#if defined WIN32 || defined _WIN32 +#include "wave_out.h" +/* We need the following two to set stdout to binary */ +#include +#include +#endif +#include + +#ifdef __MINGW32__ +#include "wave_out.c" +#endif + +#ifdef HAVE_SYS_SOUNDCARD_H +#include +#include +#include +#include +#include + +#elif defined HAVE_SYS_AUDIOIO_H +#include +#include +#include +#include +#ifndef AUDIO_ENCODING_SLINEAR +#define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_LINEAR /* Solaris */ +#endif + +#endif + +#include +#include "wav_io.h" +#include "speex/speex_header.h" +#include "speex/speex_stereo.h" +#include "speex/speex_callbacks.h" + +#define MAX_FRAME_SIZE 2000 + +#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ + ((buf[base+2]<<16)&0xff0000)| \ + ((buf[base+1]<<8)&0xff00)| \ + (buf[base]&0xff)) + +static void print_comments(char *comments, int length) +{ + char *c=comments; + int len, i, nb_fields; + char *end; + + if (length<8) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + end = c+length; + len=readint(c, 0); + c+=4; + if (len < 0 || c+len>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + fwrite(c, 1, len, stderr); + c+=len; + fprintf (stderr, "\n"); + if (c+4>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + nb_fields=readint(c, 0); + c+=4; + for (i=0;iend) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + len=readint(c, 0); + c+=4; + if (len < 0 || c+len>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + fwrite(c, 1, len, stderr); + c+=len; + fprintf (stderr, "\n"); + } +} + +FILE *out_file_open(char *outFile, int rate, int *channels) +{ + FILE *fout=NULL; + /*Open output file*/ + if (strlen(outFile)==0) + { +#if defined HAVE_SYS_SOUNDCARD_H + int audio_fd, format, stereo; + audio_fd=open("/dev/dsp", O_WRONLY); + if (audio_fd<0) + { + perror("Cannot open /dev/dsp"); + exit(1); + } + + format=AFMT_S16_NE; + if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1) + { + perror("SNDCTL_DSP_SETFMT"); + close(audio_fd); + exit(1); + } + + stereo=0; + if (*channels==2) + stereo=1; + if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1) + { + perror("SNDCTL_DSP_STEREO"); + close(audio_fd); + exit(1); + } + if (stereo!=0) + { + if (*channels==1) + fprintf (stderr, "Cannot set mono mode, will decode in stereo\n"); + *channels=2; + } + + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1) + { + perror("SNDCTL_DSP_SPEED"); + close(audio_fd); + exit(1); + } + fout = fdopen(audio_fd, "w"); +#elif defined HAVE_SYS_AUDIOIO_H + audio_info_t info; + int audio_fd; + + audio_fd = open("/dev/audio", O_WRONLY); + if (audio_fd<0) + { + perror("Cannot open /dev/audio"); + exit(1); + } + + AUDIO_INITINFO(&info); +#ifdef AUMODE_PLAY /* NetBSD/OpenBSD */ + info.mode = AUMODE_PLAY; +#endif + info.play.encoding = AUDIO_ENCODING_SLINEAR; + info.play.precision = 16; + info.play.sample_rate = rate; + info.play.channels = *channels; + + if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) + { + perror ("AUDIO_SETINFO"); + exit(1); + } + fout = fdopen(audio_fd, "w"); +#elif defined WIN32 || defined _WIN32 + { + unsigned int speex_channels = *channels; + if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, speex_channels)) + { + fprintf (stderr, "Can't access %s\n", "WAVE OUT"); + exit(1); + } + } +#else + fprintf (stderr, "No soundcard support\n"); + exit(1); +#endif + } else { + if (strcmp(outFile,"-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdout), _O_BINARY); +#elif defined OS2 + _fsetmode(stdout,"b"); +#endif + fout=stdout; + } + else + { + fout = fopen(outFile, "wb"); + if (!fout) + { + perror(outFile); + exit(1); + } + if (strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0) + write_wav_header(fout, rate, *channels, 0, 0); + } + } + return fout; +} + +void usage() +{ + printf ("Usage: speexdec [options] input_file.spx [output_file]\n"); + printf ("\n"); + printf ("Decodes a Speex file and produce a WAV file or raw file\n"); + printf ("\n"); + printf ("input_file can be:\n"); + printf (" filename.spx regular Speex file\n"); + printf (" - stdin\n"); + printf ("\n"); + printf ("output_file can be:\n"); + printf (" filename.wav Wav file\n"); + printf (" filename.* Raw PCM file (any extension other that .wav)\n"); + printf (" - stdout\n"); + printf (" (nothing) Will be played to soundcard\n"); + printf ("\n"); + printf ("Options:\n"); + printf (" --enh Enable perceptual enhancement (default)\n"); + printf (" --no-enh Disable perceptual enhancement\n"); + printf (" --force-nb Force decoding in narrowband\n"); + printf (" --force-wb Force decoding in wideband\n"); + printf (" --force-uwb Force decoding in ultra-wideband\n"); + printf (" --mono Force decoding in mono\n"); + printf (" --stereo Force decoding in stereo\n"); + printf (" --rate n Force decoding at sampling rate n Hz\n"); + printf (" --packet-loss n Simulate n %% random packet loss\n"); + printf (" -V Verbose mode (show bit-rate)\n"); + printf (" -h, --help This help\n"); + printf (" -v, --version Version information\n"); + printf (" --pf Deprecated, use --enh instead\n"); + printf (" --no-pf Deprecated, use --no-enh instead\n"); + printf ("\n"); + printf ("More information is available from the Speex site: http://www.speex.org\n"); + printf ("\n"); + printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n"); +} + +void version() +{ + const char* speex_version; + speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version); + printf ("speexdec (Speex decoder) version %s (compiled " __DATE__ ")\n", speex_version); + printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n"); +} + +void version_short() +{ + const char* speex_version; + speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version); + printf ("speexdec version %s\n", speex_version); + printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n"); +} + +static void *process_header(ogg_packet *op, spx_int32_t enh_enabled, spx_int32_t *frame_size, int *granule_frame_size, spx_int32_t *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers, int quiet) +{ + void *st; + const SpeexMode *mode; + SpeexHeader *header; + int modeID; + SpeexCallback callback; + + header = speex_packet_to_header((char*)op->packet, op->bytes); + if (!header) + { + fprintf (stderr, "Cannot read header\n"); + return NULL; + } + if (header->mode >= SPEEX_NB_MODES || header->mode<0) + { + fprintf (stderr, "Mode number %d does not (yet/any longer) exist in this version\n", + header->mode); + free(header); + return NULL; + } + + modeID = header->mode; + if (forceMode!=-1) + modeID = forceMode; + + mode = speex_lib_get_mode (modeID); + + if (header->speex_version_id > 1) + { + fprintf (stderr, "This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", header->speex_version_id); + free(header); + return NULL; + } + + if (mode->bitstream_version < header->mode_bitstream_version) + { + fprintf (stderr, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n"); + free(header); + return NULL; + } + if (mode->bitstream_version > header->mode_bitstream_version) + { + fprintf (stderr, "The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n"); + free(header); + return NULL; + } + + st = speex_decoder_init(mode); + if (!st) + { + fprintf (stderr, "Decoder initialization failed.\n"); + free(header); + return NULL; + } + speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled); + speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size); + *granule_frame_size = *frame_size; + + if (!*rate) + *rate = header->rate; + /* Adjust rate if --force-* options are used */ + if (forceMode!=-1) + { + if (header->mode < forceMode) + { + *rate <<= (forceMode - header->mode); + *granule_frame_size >>= (forceMode - header->mode); + } + if (header->mode > forceMode) + { + *rate >>= (header->mode - forceMode); + *granule_frame_size <<= (header->mode - forceMode); + } + } + + + speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate); + + *nframes = header->frames_per_packet; + + if (*channels==-1) + *channels = header->nb_channels; + + if (!(*channels==1)) + { + *channels = 2; + callback.callback_id = SPEEX_INBAND_STEREO; + callback.func = speex_std_stereo_request_handler; + callback.data = stereo; + speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback); + } + + if (!quiet) + { + fprintf (stderr, "Decoding %d Hz audio using %s mode", + *rate, mode->modeName); + + if (*channels==1) + fprintf (stderr, " (mono"); + else + fprintf (stderr, " (stereo"); + + if (header->vbr) + fprintf (stderr, ", VBR)\n"); + else + fprintf(stderr, ")\n"); + /*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n", + *rate, mode->bitrate, mode->modeName);*/ + } + + *extra_headers = header->extra_headers; + + free(header); + return st; +} + +int main(int argc, char **argv) +{ + int c; + int option_index = 0; + char *inFile, *outFile; + FILE *fin, *fout=NULL; + short out[MAX_FRAME_SIZE]; + short output[MAX_FRAME_SIZE]; + int frame_size=0, granule_frame_size=0; + void *st=NULL; + SpeexBits bits; + int packet_count=0; + int stream_init = 0; + int quiet = 0; + ogg_int64_t page_granule=0, last_granule=0; + int skip_samples=0, page_nb_packets; + struct option long_options[] = + { + {"help", no_argument, NULL, 0}, + {"quiet", no_argument, NULL, 0}, + {"version", no_argument, NULL, 0}, + {"version-short", no_argument, NULL, 0}, + {"enh", no_argument, NULL, 0}, + {"no-enh", no_argument, NULL, 0}, + {"pf", no_argument, NULL, 0}, + {"no-pf", no_argument, NULL, 0}, + {"force-nb", no_argument, NULL, 0}, + {"force-wb", no_argument, NULL, 0}, + {"force-uwb", no_argument, NULL, 0}, + {"rate", required_argument, NULL, 0}, + {"mono", no_argument, NULL, 0}, + {"stereo", no_argument, NULL, 0}, + {"packet-loss", required_argument, NULL, 0}, + {0, 0, 0, 0} + }; + ogg_sync_state oy; + ogg_page og; + ogg_packet op; + ogg_stream_state os; + int enh_enabled; + int nframes=2; + int print_bitrate=0; + int close_in=0; + int eos=0; + int forceMode=-1; + int audio_size=0; + float loss_percent=-1; + SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; + int channels=-1; + int rate=0; + int extra_headers=0; + int wav_format=0; + int lookahead; + int speex_serialno = -1; + + enh_enabled = 1; + + /*Process options*/ + while(1) + { + c = getopt_long (argc, argv, "hvV", + long_options, &option_index); + if (c==-1) + break; + + switch(c) + { + case 0: + if (strcmp(long_options[option_index].name,"help")==0) + { + usage(); + exit(0); + } else if (strcmp(long_options[option_index].name,"quiet")==0) + { + quiet = 1; + } else if (strcmp(long_options[option_index].name,"version")==0) + { + version(); + exit(0); + } else if (strcmp(long_options[option_index].name,"version-short")==0) + { + version_short(); + exit(0); + } else if (strcmp(long_options[option_index].name,"enh")==0) + { + enh_enabled=1; + } else if (strcmp(long_options[option_index].name,"no-enh")==0) + { + enh_enabled=0; + } else if (strcmp(long_options[option_index].name,"pf")==0) + { + fprintf (stderr, "--pf is deprecated, use --enh instead\n"); + enh_enabled=1; + } else if (strcmp(long_options[option_index].name,"no-pf")==0) + { + fprintf (stderr, "--no-pf is deprecated, use --no-enh instead\n"); + enh_enabled=0; + } else if (strcmp(long_options[option_index].name,"force-nb")==0) + { + forceMode=0; + } else if (strcmp(long_options[option_index].name,"force-wb")==0) + { + forceMode=1; + } else if (strcmp(long_options[option_index].name,"force-uwb")==0) + { + forceMode=2; + } else if (strcmp(long_options[option_index].name,"mono")==0) + { + channels=1; + } else if (strcmp(long_options[option_index].name,"stereo")==0) + { + channels=2; + } else if (strcmp(long_options[option_index].name,"rate")==0) + { + rate=atoi (optarg); + } else if (strcmp(long_options[option_index].name,"packet-loss")==0) + { + loss_percent = atof(optarg); + } + break; + case 'h': + usage(); + exit(0); + break; + case 'v': + version(); + exit(0); + break; + case 'V': + print_bitrate=1; + break; + case '?': + usage(); + exit(1); + break; + } + } + if (argc-optind!=2 && argc-optind!=1) + { + usage(); + exit(1); + } + inFile=argv[optind]; + + if (argc-optind==2) + outFile=argv[optind+1]; + else + outFile = ""; + wav_format = strlen(outFile)>=4 && ( + strcmp(outFile+strlen(outFile)-4,".wav")==0 + || strcmp(outFile+strlen(outFile)-4,".WAV")==0); + /*Open input file*/ + if (strcmp(inFile, "-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdin), _O_BINARY); +#endif + fin=stdin; + } + else + { + fin = fopen(inFile, "rb"); + if (!fin) + { + perror(inFile); + exit(1); + } + close_in=1; + } + + + /*Init Ogg data struct*/ + ogg_sync_init(&oy); + + speex_bits_init(&bits); + /*Main decoding loop*/ + + while (1) + { + char *data; + int i, j, nb_read; + /*Get the ogg buffer for writing*/ + data = ogg_sync_buffer(&oy, 200); + /*Read bitstream from input file*/ + nb_read = fread(data, sizeof(char), 200, fin); + ogg_sync_wrote(&oy, nb_read); + + /*Loop for all complete pages we got (most likely only one)*/ + while (ogg_sync_pageout(&oy, &og)==1) + { + int packet_no; + if (stream_init == 0) { + ogg_stream_init(&os, ogg_page_serialno(&og)); + stream_init = 1; + } + if (ogg_page_serialno(&og) != os.serialno) { + /* so all streams are read. */ + ogg_stream_reset_serialno(&os, ogg_page_serialno(&og)); + } + /*Add page to the bitstream*/ + ogg_stream_pagein(&os, &og); + page_granule = ogg_page_granulepos(&og); + page_nb_packets = ogg_page_packets(&og); + if (page_granule>0 && frame_size) + { + /* FIXME: shift the granule values if --force-* is specified */ + skip_samples = frame_size*(page_nb_packets*granule_frame_size*nframes - (page_granule-last_granule))/granule_frame_size; + if (ogg_page_eos(&og)) + skip_samples = -skip_samples; + /*else if (!ogg_page_bos(&og)) + skip_samples = 0;*/ + } else + { + skip_samples = 0; + } + /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/ + last_granule = page_granule; + /*Extract all available packets*/ + packet_no=0; + while (!eos && ogg_stream_packetout(&os, &op) == 1) + { + if (op.bytes>=5 && !memcmp(op.packet, "Speex", 5)) { + speex_serialno = os.serialno; + } + if (speex_serialno == -1 || os.serialno != speex_serialno) + break; + /*If first packet, process as Speex header*/ + if (packet_count==0) + { + st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers, quiet); + if (!st) + exit(1); + speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); + if (!nframes) + nframes=1; + fout = out_file_open(outFile, rate, &channels); + + } else if (packet_count==1) + { + if (!quiet) + print_comments((char*)op.packet, op.bytes); + } else if (packet_count<=1+extra_headers) + { + /* Ignore extra headers */ + } else { + int lost=0; + packet_no++; + if (loss_percent>0 && 100*((float)rand())/RAND_MAX 0) + { + /*printf ("chopping first packet\n");*/ + new_frame_size -= skip_samples+lookahead; + frame_offset = skip_samples+lookahead; + } + if (packet_no == page_nb_packets && skip_samples < 0) + { + int packet_length = nframes*frame_size+skip_samples+lookahead; + new_frame_size = packet_length - j*frame_size; + if (new_frame_size<0) + new_frame_size = 0; + if (new_frame_size>frame_size) + new_frame_size = frame_size; + /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/ + } + if (new_frame_size>0) + { +#if defined WIN32 || defined _WIN32 + if (strlen(outFile)==0) + WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels); + else +#endif + fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout); + + audio_size+=sizeof(short)*new_frame_size*channels; + } + } + } + } + packet_count++; + } + } + if (feof(fin)) + break; + + } + + if (fout && wav_format) + { + if (fseek(fout,4,SEEK_SET)==0) + { + int tmp; + tmp = le_int(audio_size+36); + fwrite(&tmp,4,1,fout); + if (fseek(fout,32,SEEK_CUR)==0) + { + tmp = le_int(audio_size); + fwrite(&tmp,4,1,fout); + } else + { + fprintf (stderr, "First seek worked, second didn't\n"); + } + } else { + fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n"); + } + } + + if (st) + speex_decoder_destroy(st); + else + { + fprintf (stderr, "This doesn't look like a Speex file\n"); + } + speex_bits_destroy(&bits); + if (stream_init) + ogg_stream_clear(&os); + ogg_sync_clear(&oy); + +#if defined WIN32 || defined _WIN32 + if (strlen(outFile)==0) + WIN_Audio_close (); +#endif + + if (close_in) + fclose(fin); + if (fout != NULL) + fclose(fout); + + return 0; +} diff --git a/native/codec/libraries/speex/src/speexenc.1 b/native/codec/libraries/speex/src/speexenc.1 new file mode 100644 index 0000000..9b0d6a7 --- /dev/null +++ b/native/codec/libraries/speex/src/speexenc.1 @@ -0,0 +1,105 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29. +.TH SPEEXENC "1" "September 2003" "speexenc version 1.1" "User Commands" +.SH NAME +speexenc \- The reference implementation speex encoder. +.SH SYNOPSIS +.B speexenc +[\fIoptions\fR] \fIinput_file output_file\fR +.SH DESCRIPTION +Encodes input_file using Speex. It can read the WAV or raw files. +.SS "input_file can be:" +.TP +filename.wav +wav file +.TP +filename.* +Raw PCM file (any extension other than .wav) +.TP +- +stdin +.SS "output_file can be:" +.TP +filename.spx +Speex file +.TP +- +stdout +.SH OPTIONS +.TP +\fB\-n\fR, \fB\-\-narrowband\fR +Narrowband (8 kHz) input file +.TP +\fB\-w\fR, \fB\-\-wideband\fR +Wideband (16 kHz) input file +.HP +\fB\-u\fR, \fB\-\-ultra\-wideband\fR "Ultra-wideband" (32 kHz) input file +.TP +\fB\-\-quality\fR n +Encoding quality (0-10), default 8 +.TP +\fB\-\-bitrate\fR n +Encoding bit-rate (use bit-rate n or lower) +.TP +\fB\-\-vbr\fR +Enable variable bit-rate (VBR) +.TP +\fB\-\-abr\fR rate +Enable average bit-rate (ABR) at rate bps +.TP +\fB\-\-vad\fR +Enable voice activity detection (VAD) +.TP +\fB\-\-dtx\fR +Enable file-based discontinuous transmission (DTX) +.TP +\fB\-\-comp\fR n +Set encoding complexity (0-10), default 3 +.TP +\fB\-\-nframes\fR n +Number of frames per Ogg packet (1-10), default 1 +.TP +\fB\-\-comment\fR +Add the given string as an extra comment. This may be +used multiple times +.TP +\fB\-\-author\fR +Author of this track +.TP +\fB\-\-title\fR +Title for this track +.TP +\fB\-h\fR, \fB\-\-help\fR +This help +.TP +\fB\-v\fR, \fB\-\-version\fR +Version information +.TP +\fB\-V\fR +Verbose mode (show bit-rate) +.SS "Raw input options:" +.TP +\fB\-\-rate\fR n +Sampling rate for raw input +.TP +\fB\-\-stereo\fR +Consider raw input as stereo +.TP +\fB\-\-le\fR +Raw input is little-endian +.TP +\fB\-\-be\fR +Raw input is big-endian +.TP +\fB\-\-8bit\fR +Raw input is 8-bit unsigned +.TP +\fB\-\-16bit\fR +Raw input is 16-bit signed +.PP +Default raw PCM input is 16-bit, little-endian, mono +.PP +More information is available from the Speex site: http://www.speex.org +.PP +Please report bugs to the mailing list `speex-dev@xiph.org'. +.SH COPYRIGHT +Copyright \(co 2002 Jean-Marc Valin diff --git a/native/codec/libraries/speex/src/speexenc.c b/native/codec/libraries/speex/src/speexenc.c new file mode 100644 index 0000000..5273339 --- /dev/null +++ b/native/codec/libraries/speex/src/speexenc.c @@ -0,0 +1,1044 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: speexenc.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#if !defined WIN32 && !defined _WIN32 +#include +#endif +#ifdef HAVE_GETOPT_H +#include +#endif +#ifndef HAVE_GETOPT_LONG +#include "getopt_win.h" +#endif +#include +#include +#include + +#include "speex/speex.h" +#include "speex/speex_header.h" +#include "speex/speex_stereo.h" +#include +#include "wav_io.h" +#ifdef USE_SPEEXDSP +#include +#endif + +#if defined WIN32 || defined _WIN32 +/* We need the following two to set stdout to binary */ +#include +#include +#endif + +#include "skeleton.h" + + +void comment_init(char **comments, int* length, char *vendor_string); +void comment_add(char **comments, int* length, char *tag, char *val); + + +/*Write an Ogg page to a file pointer*/ +int oe_write_page(ogg_page *page, FILE *fp) +{ + int written; + written = fwrite(page->header,1,page->header_len, fp); + written += fwrite(page->body,1,page->body_len, fp); + + return written; +} + +#define MAX_FRAME_SIZE 2000 +#define MAX_FRAME_BYTES 2000 + +/* Convert input audio bits, endians and channels */ +static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, spx_int32_t *size) +{ + unsigned char in[MAX_FRAME_BYTES*2]; + int i; + short *s; + int nb_read; + size_t to_read; + + if (size && *size<=0) + { + return 0; + } + + to_read = bits/8*channels*frame_size; + + /*Read input audio*/ + if (size) + { + if (*size >= to_read) + { + *size -= to_read; + } + else + { + to_read = *size; + *size = 0; + } + } + + if (buff) + { + for (i=0;i<12;i++) + in[i]=buff[i]; + nb_read = fread(in+12,1,to_read-12,fin) + 12; + if (size) + *size += 12; + } else { + nb_read = fread(in,1,to_read,fin); + } + + nb_read /= bits/8*channels; + + /*fprintf (stderr, "%d\n", nb_read);*/ + if (nb_read==0) + return 0; + + s=(short*)in; + if(bits==8) + { + /* Convert 8->16 bits */ + for(i=frame_size*channels-1;i>=0;i--) + { + s[i]=(in[i]<<8)^0x8000; + } + } else + { + /* convert to our endian format */ + for(i=0;iextra_headers; + fp.granule_rate_n = header->rate; + fp.granule_rate_d = 1; + fp.start_granule = 0; + fp.preroll = 3; + fp.granule_shift = 0; + + add_message_header_field(&fp, "Content-Type", "audio/x-speex"); + + add_fisbone_to_stream(os, &fp); +} + +void version() +{ + const char* speex_version; + speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version); + printf ("speexenc (Speex encoder) version %s (compiled " __DATE__ ")\n", speex_version); + printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n"); +} + +void version_short() +{ + const char* speex_version; + speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version); + printf ("speexenc version %s\n", speex_version); + printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n"); +} + +void usage() +{ + printf ("Usage: speexenc [options] input_file output_file\n"); + printf ("\n"); + printf ("Encodes input_file using Speex. It can read the WAV or raw files.\n"); + printf ("\n"); + printf ("input_file can be:\n"); + printf (" filename.wav wav file\n"); + printf (" filename.* Raw PCM file (any extension other than .wav)\n"); + printf (" - stdin\n"); + printf ("\n"); + printf ("output_file can be:\n"); + printf (" filename.spx Speex file\n"); + printf (" - stdout\n"); + printf ("\n"); + printf ("Options:\n"); + printf (" -n, --narrowband Narrowband (8 kHz) input file\n"); + printf (" -w, --wideband Wideband (16 kHz) input file\n"); + printf (" -u, --ultra-wideband \"Ultra-wideband\" (32 kHz) input file\n"); + printf (" --quality n Encoding quality (0-10), default 8\n"); + printf (" --bitrate n Encoding bit-rate (use bit-rate n or lower)\n"); + printf (" --vbr Enable variable bit-rate (VBR)\n"); + printf (" --vbr-max-bitrate Set max VBR bit-rate allowed\n"); + printf (" --abr rate Enable average bit-rate (ABR) at rate bps\n"); + printf (" --vad Enable voice activity detection (VAD)\n"); + printf (" --dtx Enable file-based discontinuous transmission (DTX)\n"); + printf (" --comp n Set encoding complexity (0-10), default 3\n"); + printf (" --nframes n Number of frames per Ogg packet (1-10), default 1\n"); +#ifdef USE_SPEEXDSP + printf (" --denoise Denoise the input before encoding\n"); + printf (" --agc Apply adaptive gain control (AGC) before encoding\n"); +#endif + printf (" --no-highpass Disable the encoder's built-in high-pass filter\n"); + printf (" --skeleton Outputs ogg skeleton metadata (may cause incompatibilities)\n"); + printf (" --comment Add the given string as an extra comment. This may be\n"); + printf (" used multiple times\n"); + printf (" --author Author of this track\n"); + printf (" --title Title for this track\n"); + printf (" -h, --help This help\n"); + printf (" -v, --version Version information\n"); + printf (" -V Verbose mode (show bit-rate)\n"); + printf (" --print-rate Print the bitrate for each frame to standard output\n"); + printf ("Raw input options:\n"); + printf (" --rate n Sampling rate for raw input\n"); + printf (" --stereo Consider raw input as stereo\n"); + printf (" --le Raw input is little-endian\n"); + printf (" --be Raw input is big-endian\n"); + printf (" --8bit Raw input is 8-bit unsigned\n"); + printf (" --16bit Raw input is 16-bit signed\n"); + printf ("Default raw PCM input is 16-bit, little-endian, mono\n"); + printf ("\n"); + printf ("More information is available from the Speex site: http://www.speex.org\n"); + printf ("\n"); + printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n"); +} + + +int main(int argc, char **argv) +{ + int nb_samples, total_samples=0, nb_encoded; + int c; + int option_index = 0; + char *inFile, *outFile; + FILE *fin, *fout; + short input[MAX_FRAME_SIZE]; + spx_int32_t frame_size; + int quiet=0; + spx_int32_t vbr_enabled=0; + spx_int32_t vbr_max=0; + int abr_enabled=0; + spx_int32_t vad_enabled=0; + spx_int32_t dtx_enabled=0; + int nbBytes; + const SpeexMode *mode=NULL; + int modeID = -1; + void *st; + SpeexBits bits; + char cbits[MAX_FRAME_BYTES]; + int with_skeleton = 0; + struct option long_options[] = + { + {"wideband", no_argument, NULL, 0}, + {"ultra-wideband", no_argument, NULL, 0}, + {"narrowband", no_argument, NULL, 0}, + {"vbr", no_argument, NULL, 0}, + {"vbr-max-bitrate", required_argument, NULL, 0}, + {"abr", required_argument, NULL, 0}, + {"vad", no_argument, NULL, 0}, + {"dtx", no_argument, NULL, 0}, + {"quality", required_argument, NULL, 0}, + {"bitrate", required_argument, NULL, 0}, + {"nframes", required_argument, NULL, 0}, + {"comp", required_argument, NULL, 0}, +#ifdef USE_SPEEXDSP + {"denoise", no_argument, NULL, 0}, + {"agc", no_argument, NULL, 0}, +#endif + {"no-highpass", no_argument, NULL, 0}, + {"skeleton",no_argument,NULL, 0}, + {"help", no_argument, NULL, 0}, + {"quiet", no_argument, NULL, 0}, + {"le", no_argument, NULL, 0}, + {"be", no_argument, NULL, 0}, + {"8bit", no_argument, NULL, 0}, + {"16bit", no_argument, NULL, 0}, + {"stereo", no_argument, NULL, 0}, + {"rate", required_argument, NULL, 0}, + {"version", no_argument, NULL, 0}, + {"version-short", no_argument, NULL, 0}, + {"comment", required_argument, NULL, 0}, + {"author", required_argument, NULL, 0}, + {"title", required_argument, NULL, 0}, + {"print-rate", no_argument, NULL, 0}, + {0, 0, 0, 0} + }; + int print_bitrate=0; + spx_int32_t rate=0; + spx_int32_t size; + int chan=1; + int fmt=16; + spx_int32_t quality=-1; + float vbr_quality=-1; + int lsb=1; + ogg_stream_state os; + ogg_stream_state so; /* ogg stream for skeleton bitstream */ + ogg_page og; + ogg_packet op; + int bytes_written=0, ret, result; + int id=-1; + SpeexHeader header; + int nframes=1; + spx_int32_t complexity=3; + const char* speex_version; + char vendor_string[64]; + char *comments; + int comments_length; + int close_in=0, close_out=0; + int eos=0; + spx_int32_t bitrate=0; + double cumul_bits=0, enc_frames=0; + char first_bytes[12]; + int wave_input=0; + spx_int32_t tmp; +#ifdef USE_SPEEXDSP + SpeexPreprocessState *preprocess = NULL; + int denoise_enabled=0, agc_enabled=0; +#endif + int highpass_enabled=1; + int output_rate=0; + spx_int32_t lookahead = 0; + + speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version); + snprintf(vendor_string, sizeof(vendor_string), "Encoded with Speex %s", speex_version); + + comment_init(&comments, &comments_length, vendor_string); + + /*Process command-line options*/ + while(1) + { + c = getopt_long (argc, argv, "nwuhvV", + long_options, &option_index); + if (c==-1) + break; + + switch(c) + { + case 0: + if (strcmp(long_options[option_index].name,"narrowband")==0) + { + modeID = SPEEX_MODEID_NB; + } else if (strcmp(long_options[option_index].name,"wideband")==0) + { + modeID = SPEEX_MODEID_WB; + } else if (strcmp(long_options[option_index].name,"ultra-wideband")==0) + { + modeID = SPEEX_MODEID_UWB; + } else if (strcmp(long_options[option_index].name,"vbr")==0) + { + vbr_enabled=1; + } else if (strcmp(long_options[option_index].name,"vbr-max-bitrate")==0) + { + vbr_max=atoi(optarg); + if (vbr_max<1) + { + fprintf (stderr, "Invalid VBR max bit-rate value: %d\n", vbr_max); + exit(1); + } + } else if (strcmp(long_options[option_index].name,"abr")==0) + { + abr_enabled=atoi(optarg); + if (!abr_enabled) + { + fprintf (stderr, "Invalid ABR value: %d\n", abr_enabled); + exit(1); + } + } else if (strcmp(long_options[option_index].name,"vad")==0) + { + vad_enabled=1; + } else if (strcmp(long_options[option_index].name,"dtx")==0) + { + dtx_enabled=1; + } else if (strcmp(long_options[option_index].name,"quality")==0) + { + quality = atoi (optarg); + vbr_quality=atof(optarg); + } else if (strcmp(long_options[option_index].name,"bitrate")==0) + { + bitrate = atoi (optarg); + } else if (strcmp(long_options[option_index].name,"nframes")==0) + { + nframes = atoi (optarg); + if (nframes<1) + nframes=1; + if (nframes>10) + nframes=10; + } else if (strcmp(long_options[option_index].name,"comp")==0) + { + complexity = atoi (optarg); +#ifdef USE_SPEEXDSP + } else if (strcmp(long_options[option_index].name,"denoise")==0) + { + denoise_enabled=1; + } else if (strcmp(long_options[option_index].name,"agc")==0) + { + agc_enabled=1; +#endif + } else if (strcmp(long_options[option_index].name,"no-highpass")==0) + { + highpass_enabled=0; + } else if (strcmp(long_options[option_index].name,"skeleton")==0) + { + with_skeleton=1; + } else if (strcmp(long_options[option_index].name,"help")==0) + { + usage(); + exit(0); + } else if (strcmp(long_options[option_index].name,"quiet")==0) + { + quiet = 1; + } else if (strcmp(long_options[option_index].name,"version")==0) + { + version(); + exit(0); + } else if (strcmp(long_options[option_index].name,"version-short")==0) + { + version_short(); + exit(0); + } else if (strcmp(long_options[option_index].name,"print-rate")==0) + { + output_rate=1; + } else if (strcmp(long_options[option_index].name,"le")==0) + { + lsb=1; + } else if (strcmp(long_options[option_index].name,"be")==0) + { + lsb=0; + } else if (strcmp(long_options[option_index].name,"8bit")==0) + { + fmt=8; + } else if (strcmp(long_options[option_index].name,"16bit")==0) + { + fmt=16; + } else if (strcmp(long_options[option_index].name,"stereo")==0) + { + chan=2; + } else if (strcmp(long_options[option_index].name,"rate")==0) + { + rate=atoi (optarg); + } else if (strcmp(long_options[option_index].name,"comment")==0) + { + if (!strchr(optarg, '=')) + { + fprintf (stderr, "Invalid comment: %s\n", optarg); + fprintf (stderr, "Comments must be of the form name=value\n"); + exit(1); + } + comment_add(&comments, &comments_length, NULL, optarg); + } else if (strcmp(long_options[option_index].name,"author")==0) + { + comment_add(&comments, &comments_length, "author=", optarg); + } else if (strcmp(long_options[option_index].name,"title")==0) + { + comment_add(&comments, &comments_length, "title=", optarg); + } + + break; + case 'n': + modeID = SPEEX_MODEID_NB; + break; + case 'h': + usage(); + exit(0); + break; + case 'v': + version(); + exit(0); + break; + case 'V': + print_bitrate=1; + break; + case 'w': + modeID = SPEEX_MODEID_WB; + break; + case 'u': + modeID = SPEEX_MODEID_UWB; + break; + case '?': + usage(); + exit(1); + break; + } + } + if (argc-optind!=2) + { + usage(); + exit(1); + } + inFile=argv[optind]; + outFile=argv[optind+1]; + + /*Initialize Ogg stream struct*/ + srand(time(NULL)); + if (ogg_stream_init(&os, rand())==-1) + { + fprintf(stderr,"Error: stream init failed\n"); + exit(1); + } + if (with_skeleton && ogg_stream_init(&so, rand())==-1) + { + fprintf(stderr,"Error: stream init failed\n"); + exit(1); + } + + if (strcmp(inFile, "-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdin), _O_BINARY); +#elif defined OS2 + _fsetmode(stdin,"b"); +#endif + fin=stdin; + } + else + { + fin = fopen(inFile, "rb"); + if (!fin) + { + perror(inFile); + exit(1); + } + close_in=1; + } + + { + if (fread(first_bytes, 1, 12, fin) != 12) + { + perror("short file"); + exit(1); + } + if (strncmp(first_bytes,"RIFF",4)==0 || strncmp(first_bytes,"riff",4)==0) + { + if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1) + exit(1); + wave_input=1; + lsb=1; /* CHECK: exists big-endian .wav ?? */ + } + } + + if (modeID==-1 && !rate) + { + /* By default, use narrowband/8 kHz */ + modeID = SPEEX_MODEID_NB; + rate=8000; + } else if (modeID!=-1 && rate) + { + mode = speex_lib_get_mode (modeID); + if (rate>48000) + { + fprintf (stderr, "Error: sampling rate too high: %d Hz, try down-sampling\n", rate); + exit(1); + } else if (rate>25000) + { + if (modeID != SPEEX_MODEID_UWB) + { + fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try ultra-wideband instead\n", mode->modeName , rate); + } + } else if (rate>12500) + { + if (modeID != SPEEX_MODEID_WB) + { + fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try wideband instead\n", mode->modeName , rate); + } + } else if (rate>=6000) + { + if (modeID != SPEEX_MODEID_NB) + { + fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try narrowband instead\n", mode->modeName , rate); + } + } else { + fprintf (stderr, "Error: sampling rate too low: %d Hz\n", rate); + exit(1); + } + } else if (modeID==-1) + { + if (rate>48000) + { + fprintf (stderr, "Error: sampling rate too high: %d Hz, try down-sampling\n", rate); + exit(1); + } else if (rate>25000) + { + modeID = SPEEX_MODEID_UWB; + } else if (rate>12500) + { + modeID = SPEEX_MODEID_WB; + } else if (rate>=6000) + { + modeID = SPEEX_MODEID_NB; + } else { + fprintf (stderr, "Error: Sampling rate too low: %d Hz\n", rate); + exit(1); + } + } else if (!rate) + { + if (modeID == SPEEX_MODEID_NB) + rate=8000; + else if (modeID == SPEEX_MODEID_WB) + rate=16000; + else if (modeID == SPEEX_MODEID_UWB) + rate=32000; + } + + if (!quiet) + if (rate!=8000 && rate!=16000 && rate!=32000) + fprintf (stderr, "Warning: Speex is only optimized for 8, 16 and 32 kHz. It will still work at %d Hz but your mileage may vary\n", rate); + + if (!mode) + mode = speex_lib_get_mode (modeID); + + speex_init_header(&header, rate, 1, mode); + header.frames_per_packet=nframes; + header.vbr=vbr_enabled; + header.nb_channels = chan; + + { + char *st_string="mono"; + if (chan==2) + st_string="stereo"; + if (!quiet) + fprintf (stderr, "Encoding %d Hz audio using %s mode (%s)\n", + header.rate, mode->modeName, st_string); + } + /*fprintf (stderr, "Encoding %d Hz audio at %d bps using %s mode\n", + header.rate, mode->bitrate, mode->modeName);*/ + + /*Initialize Speex encoder*/ + st = speex_encoder_init(mode); + + if (strcmp(outFile,"-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdout), _O_BINARY); +#endif + fout=stdout; + } + else + { + fout = fopen(outFile, "wb"); + if (!fout) + { + perror(outFile); + exit(1); + } + close_out=1; + } + + speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size); + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &complexity); + speex_encoder_ctl(st, SPEEX_SET_SAMPLING_RATE, &rate); + + if (quality >= 0) + { + if (vbr_enabled) + { + if (vbr_max>0) + speex_encoder_ctl(st, SPEEX_SET_VBR_MAX_BITRATE, &vbr_max); + speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_quality); + } + else + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &quality); + } + if (bitrate) + { + if (quality >= 0 && vbr_enabled) + fprintf (stderr, "Warning: --bitrate option is overriding --quality\n"); + speex_encoder_ctl(st, SPEEX_SET_BITRATE, &bitrate); + } + if (vbr_enabled) + { + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + } else if (vad_enabled) + { + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_VAD, &tmp); + } + if (dtx_enabled) + speex_encoder_ctl(st, SPEEX_SET_DTX, &tmp); + if (dtx_enabled && !(vbr_enabled || abr_enabled || vad_enabled)) + { + fprintf (stderr, "Warning: --dtx is useless without --vad, --vbr or --abr\n"); + } else if ((vbr_enabled || abr_enabled) && (vad_enabled)) + { + fprintf (stderr, "Warning: --vad is already implied by --vbr or --abr\n"); + } + if (with_skeleton) { + fprintf (stderr, "Warning: Enabling skeleton output may cause some decoders to fail.\n"); + } + + if (abr_enabled) + { + speex_encoder_ctl(st, SPEEX_SET_ABR, &abr_enabled); + } + + speex_encoder_ctl(st, SPEEX_SET_HIGHPASS, &highpass_enabled); + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); + +#ifdef USE_SPEEXDSP + if (denoise_enabled || agc_enabled) + { + preprocess = speex_preprocess_state_init(frame_size, rate); + speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &denoise_enabled); + speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC, &agc_enabled); + lookahead += frame_size; + } +#endif + /* first packet should be the skeleton header. */ + + if (with_skeleton) { + add_fishead_packet(&so); + if ((ret = flush_ogg_stream_to_file(&so, fout))) { + fprintf (stderr,"Error: failed skeleton (fishead) header to output stream\n"); + exit(1); + } else + bytes_written += ret; + } + + /*Write header*/ + { + int packet_size; + op.packet = (unsigned char *)speex_header_to_packet(&header, &packet_size); + op.bytes = packet_size; + op.b_o_s = 1; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = 0; + ogg_stream_packetin(&os, &op); + free(op.packet); + + while((result = ogg_stream_flush(&os, &og))) + { + if(!result) break; + ret = oe_write_page(&og, fout); + if(ret != og.header_len + og.body_len) + { + fprintf (stderr,"Error: failed writing header to output stream\n"); + exit(1); + } + else + bytes_written += ret; + } + + op.packet = (unsigned char *)comments; + op.bytes = comments_length; + op.b_o_s = 0; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = 1; + ogg_stream_packetin(&os, &op); + } + + /* fisbone packet should be write after all bos pages */ + if (with_skeleton) { + add_fisbone_packet(&so, os.serialno, &header); + if ((ret = flush_ogg_stream_to_file(&so, fout))) { + fprintf (stderr,"Error: failed writing skeleton (fisbone )header to output stream\n"); + exit(1); + } else + bytes_written += ret; + } + + /* writing the rest of the speex header packets */ + while((result = ogg_stream_flush(&os, &og))) + { + if(!result) break; + ret = oe_write_page(&og, fout); + if(ret != og.header_len + og.body_len) + { + fprintf (stderr,"Error: failed writing header to output stream\n"); + exit(1); + } + else + bytes_written += ret; + } + + free(comments); + + /* write the skeleton eos packet */ + if (with_skeleton) { + add_eos_packet_to_stream(&so); + if ((ret = flush_ogg_stream_to_file(&so, fout))) { + fprintf (stderr,"Error: failed writing skeleton header to output stream\n"); + exit(1); + } else + bytes_written += ret; + } + + + speex_bits_init(&bits); + + if (!wave_input) + { + nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL); + } else { + nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size); + } + if (nb_samples==0) + eos=1; + total_samples += nb_samples; + nb_encoded = -lookahead; + /*Main encoding loop (one frame per iteration)*/ + while (!eos || total_samples>nb_encoded) + { + id++; + /*Encode current frame*/ + if (chan==2) + speex_encode_stereo_int(input, frame_size, &bits); + +#ifdef USE_SPEEXDSP + if (preprocess) + speex_preprocess(preprocess, input, NULL); +#endif + speex_encode_int(st, input, &bits); + + nb_encoded += frame_size; + if (print_bitrate) { + int tmp; + char ch=13; + speex_encoder_ctl(st, SPEEX_GET_BITRATE, &tmp); + fputc (ch, stderr); + cumul_bits += tmp; + enc_frames += 1; + if (!quiet) + { + if (vad_enabled || vbr_enabled || abr_enabled) + fprintf (stderr, "Bitrate is use: %d bps (average %d bps) ", tmp, (int)(cumul_bits/enc_frames)); + else + fprintf (stderr, "Bitrate is use: %d bps ", tmp); + if (output_rate) + printf ("%d\n", tmp); + } + + } + + if (wave_input) + { + nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size); + } else { + nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL); + } + if (nb_samples==0) + { + eos=1; + } + if (eos && total_samples<=nb_encoded) + op.e_o_s = 1; + else + op.e_o_s = 0; + total_samples += nb_samples; + + if ((id+1)%nframes!=0) + continue; + speex_bits_insert_terminator(&bits); + nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_BYTES); + speex_bits_reset(&bits); + op.packet = (unsigned char *)cbits; + op.bytes = nbBytes; + op.b_o_s = 0; + /*Is this redundent?*/ + if (eos && total_samples<=nb_encoded) + op.e_o_s = 1; + else + op.e_o_s = 0; + op.granulepos = (id+1)*frame_size-lookahead; + if (op.granulepos>total_samples) + op.granulepos = total_samples; + /*printf ("granulepos: %d %d %d %d %d %d\n", (int)op.granulepos, id, nframes, lookahead, 5, 6);*/ + op.packetno = 2+id/nframes; + ogg_stream_packetin(&os, &op); + + /*Write all new pages (most likely 0 or 1)*/ + while (ogg_stream_pageout(&os,&og)) + { + ret = oe_write_page(&og, fout); + if(ret != og.header_len + og.body_len) + { + fprintf (stderr,"Error: failed writing header to output stream\n"); + exit(1); + } + else + bytes_written += ret; + } + } + if ((id+1)%nframes!=0) + { + while ((id+1)%nframes!=0) + { + id++; + speex_bits_pack(&bits, 15, 5); + } + nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_BYTES); + op.packet = (unsigned char *)cbits; + op.bytes = nbBytes; + op.b_o_s = 0; + op.e_o_s = 1; + op.granulepos = (id+1)*frame_size-lookahead; + if (op.granulepos>total_samples) + op.granulepos = total_samples; + + op.packetno = 2+id/nframes; + ogg_stream_packetin(&os, &op); + } + /*Flush all pages left to be written*/ + while (ogg_stream_flush(&os, &og)) + { + ret = oe_write_page(&og, fout); + if(ret != og.header_len + og.body_len) + { + fprintf (stderr,"Error: failed writing header to output stream\n"); + exit(1); + } + else + bytes_written += ret; + } + + speex_encoder_destroy(st); + speex_bits_destroy(&bits); + ogg_stream_clear(&os); + + if (close_in) + fclose(fin); + if (close_out) + fclose(fout); + return 0; +} + +/* + Comments will be stored in the Vorbis style. + It is describled in the "Structure" section of + http://www.xiph.org/ogg/vorbis/doc/v-comment.html + +The comment header is decoded as follows: + 1) [vendor_length] = read an unsigned integer of 32 bits + 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets + 3) [user_comment_list_length] = read an unsigned integer of 32 bits + 4) iterate [user_comment_list_length] times { + 5) [length] = read an unsigned integer of 32 bits + 6) this iteration's user comment = read a UTF-8 vector as [length] octets + } + 7) [framing_bit] = read a single bit as boolean + 8) if ( [framing_bit] unset or end of packet ) then ERROR + 9) done. + + If you have troubles, please write to ymnk@jcraft.com. + */ + +#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ + ((buf[base+2]<<16)&0xff0000)| \ + ((buf[base+1]<<8)&0xff00)| \ + (buf[base]&0xff)) +#define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \ + buf[base+2]=((val)>>16)&0xff; \ + buf[base+1]=((val)>>8)&0xff; \ + buf[base]=(val)&0xff; \ + }while(0) + +void comment_init(char **comments, int* length, char *vendor_string) +{ + int vendor_length=strlen(vendor_string); + int user_comment_list_length=0; + int len=4+vendor_length+4; + char *p=(char*)malloc(len); + if(p==NULL){ + fprintf (stderr, "malloc failed in comment_init()\n"); + exit(1); + } + writeint(p, 0, vendor_length); + memcpy(p+4, vendor_string, vendor_length); + writeint(p, 4+vendor_length, user_comment_list_length); + *length=len; + *comments=p; +} +void comment_add(char **comments, int* length, char *tag, char *val) +{ + char* p=*comments; + int vendor_length=readint(p, 0); + int user_comment_list_length=readint(p, 4+vendor_length); + int tag_len=(tag?strlen(tag):0); + int val_len=strlen(val); + int len=(*length)+4+tag_len+val_len; + + p=(char*)realloc(p, len); + if(p==NULL){ + fprintf (stderr, "realloc failed in comment_add()\n"); + exit(1); + } + + writeint(p, *length, tag_len+val_len); /* length of comment */ + if(tag) memcpy(p+*length+4, tag, tag_len); /* comment */ + memcpy(p+*length+4+tag_len, val, val_len); /* comment */ + writeint(p, 4+vendor_length, user_comment_list_length+1); + + *comments=p; + *length=len; +} +#undef readint +#undef writeint diff --git a/native/codec/libraries/speex/src/wav_io.c b/native/codec/libraries/speex/src/wav_io.c new file mode 100644 index 0000000..b518301 --- /dev/null +++ b/native/codec/libraries/speex/src/wav_io.c @@ -0,0 +1,238 @@ +/* Copyright (C) 2002 Jean-Marc Valin + File: wav_io.c + Routines to handle wav (RIFF) headers + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include "wav_io.h" + + +int read_wav_header(FILE *file, int *rate, int *channels, int *format, spx_int32_t *size) +{ + char ch[5]; + spx_int32_t itmp; + spx_int16_t stmp; + spx_int32_t bpersec; + spx_int16_t balign; + int skip_bytes; + int i; + + ch[4]=0; +#if 0 + fread(ch, 1, 4, file); + if (strcmp(ch, "RIFF")!=0) + { + fseek(file, 0, SEEK_SET); + return 0; + } + + fread(&itmp, 4, 1, file); + *size = le_int(itmp-36); + + fread(ch, 1, 4, file); + if (strcmp(ch, "WAVE")!=0) + { + fprintf (stderr, "RIFF file is not a WAVE file\n"); + return -1; + } +#endif + fread(ch, 1, 4, file); + while (strcmp(ch, "fmt ")!=0) + { + fread(&itmp, 4, 1, file); + itmp = le_int(itmp); + /*fprintf (stderr, "skip=%d\n", itmp);*/ + /*strange way of seeking, but it works even for pipes*/ + for (i=0;i2) + { + fprintf (stderr, "Only mono and (intensity) stereo supported\n"); + return -1; + } + + fread(&itmp, 4, 1, file); + itmp = le_int(itmp); + *rate = itmp; + if (*rate != 8000 && *rate != 16000 && *rate != 11025 && *rate != 22050 && *rate != 32000 && *rate != 44100 && *rate != 48000) + { + fprintf (stderr, "Only 8 kHz (narrowband) and 16 kHz (wideband) supported (plus 11.025 kHz and 22.05 kHz, but your mileage may vary)\n"); + return -1; + } + + fread(&itmp, 4, 1, file); + bpersec = le_int(itmp); + + fread(&stmp, 2, 1, file); + balign = le_short(stmp); + + fread(&stmp, 2, 1, file); + stmp = le_short(stmp); + if (stmp!=16 && stmp!=8) + { + fprintf (stderr, "Only 8/16-bit linear supported\n"); + return -1; + } + *format=stmp; + + if (bpersec!=*rate**channels*stmp/8) + { + fprintf (stderr, "Corrupted header: ByteRate mismatch\n"); + return -1; + } + + if (balign!=*channels*stmp/8) + { + fprintf (stderr, "Corrupted header: BlockAlign mismatch\n"); + return -1; + } + + + /*strange way of seeking, but it works even for pipes*/ + if (skip_bytes>0) { + for (i=0;i +#include "speex/speex_types.h" + +#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) +#define le_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8)) +#define be_short(s) ((short) (s)) +#else +#define le_short(s) ((short) (s)) +#define be_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8)) +#endif + +/** Convert little endian */ +static inline spx_int32_t le_int(spx_int32_t i) +{ +#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) + spx_uint32_t ui, ret; + ui = i; + ret = ui>>24; + ret |= (ui>>8)&0x0000ff00; + ret |= (ui<<8)&0x00ff0000; + ret |= (ui<<24); + return ret; +#else + return i; +#endif +} + +int read_wav_header(FILE *file, int *rate, int *channels, int *format, spx_int32_t *size); + +void write_wav_header(FILE *file, int rate, int channels, int format, int size); + +#endif diff --git a/native/codec/libraries/speex/src/wave_out.c b/native/codec/libraries/speex/src/wave_out.c new file mode 100644 index 0000000..0f871b9 --- /dev/null +++ b/native/codec/libraries/speex/src/wave_out.c @@ -0,0 +1,220 @@ +/* Copyright (c) 2002, John Edwards + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Set TABS = 4 */ +/******************************************************************** + + function: To provide playback of 16 bit PCM wave data in Win32 + environments from decoded compressed files. + + ********************************************************************/ + +#if defined WIN32 || defined _WIN32 + +#include +#include +#include "wave_out.h" + +#define MAXWAVESIZE 4294967040LU +#define MAX_WAVEBLOCKS 32 + +// This is modified for USE_WIN_AUDIO - ONLY 2002-02-27 + + +static CRITICAL_SECTION cs; +static HWAVEOUT dev = NULL; +static int ScheduledBlocks = 0; +static int PlayedWaveHeadersCount = 0; // free index +static WAVEHDR* PlayedWaveHeaders [MAX_WAVEBLOCKS]; + +static int +Box ( const char* msg ) +{ + MessageBox ( NULL, msg, " "VERSION_STRING": Error Message . . .", MB_OK | MB_ICONEXCLAMATION ); + return -1; +} + + +/* + * This function registers already played WAVE chunks. Freeing is done by free_memory(), + */ + +static void CALLBACK +wave_callback ( HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ) +{ + if ( uMsg == WOM_DONE ) { + EnterCriticalSection ( &cs ); + PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1; + LeaveCriticalSection ( &cs ); + } +} + + +static void +free_memory ( void ) +{ + WAVEHDR* wh; + HGLOBAL hg; + + EnterCriticalSection ( &cs ); + wh = PlayedWaveHeaders [--PlayedWaveHeadersCount]; + ScheduledBlocks--; // decrease the number of USED blocks + LeaveCriticalSection ( &cs ); + + waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) ); + + hg = GlobalHandle ( wh -> lpData ); // Deallocate the buffer memory + GlobalUnlock (hg); + GlobalFree (hg); + + hg = GlobalHandle ( wh ); // Deallocate the header memory + GlobalUnlock (hg); + GlobalFree (hg); +} + + +Int +Set_WIN_Params ( FILE_T dummyFile , + Ldouble SampleFreq, + Uint BitsPerSample, + Uint Channels ) +{ + WAVEFORMATEX outFormat; + UINT deviceID = WAVE_MAPPER; + + (void) dummyFile; + + if ( waveOutGetNumDevs () == 0 ) + return Box ( "No audio device present." ); + + outFormat.wFormatTag = WAVE_FORMAT_PCM; + outFormat.wBitsPerSample = BitsPerSample; + outFormat.nChannels = Channels; + outFormat.nSamplesPerSec = (unsigned long)(SampleFreq + 0.5); + outFormat.nBlockAlign = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels; + outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign; + + switch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD_PTR)wave_callback, 0, CALLBACK_FUNCTION ) ) + { + case MMSYSERR_ALLOCATED: return Box ( "Device is already open." ); + case MMSYSERR_BADDEVICEID: return Box ( "The specified device is out of range." ); + case MMSYSERR_NODRIVER: return Box ( "There is no audio driver in this system." ); + case MMSYSERR_NOMEM: return Box ( "Unable to allocate sound memory." ); + case WAVERR_BADFORMAT: return Box ( "This audio format is not supported." ); + case WAVERR_SYNC: return Box ( "The device is synchronous." ); + default: return Box ( "Unknown media error." ); + case MMSYSERR_NOERROR: break; + } + + waveOutReset ( dev ); + InitializeCriticalSection ( &cs ); + SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS ); + return 0; +} + + +int +WIN_Play_Samples ( const void* data, size_t len ) +{ + HGLOBAL hg; + HGLOBAL hg2; + LPWAVEHDR wh; + void* allocptr; + + do { + while ( PlayedWaveHeadersCount > 0 ) // free used blocks ... + free_memory (); + + if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ... + break; + Sleep (26); + } while (1); + + if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL ) // allocate some memory for a copy of the buffer + return Box ( "GlobalAlloc failed." ); + + allocptr = GlobalLock (hg2); + CopyMemory ( allocptr, data, len ); // Here we can call any modification output functions we want.... + + if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT! + return -1; + + wh = GlobalLock (hg); + wh -> dwBufferLength = len; + wh -> lpData = allocptr; + + if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) { + GlobalUnlock (hg); + GlobalFree (hg); + return -1; + } + + if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) { + GlobalUnlock (hg); + GlobalFree (hg); + return -1; + } + + EnterCriticalSection ( &cs ); + ScheduledBlocks++; + LeaveCriticalSection ( &cs ); + + return len; +} + + +int +WIN_Audio_close ( void ) +{ + if ( dev != NULL ) { + + while ( ScheduledBlocks > 0 ) { + Sleep (ScheduledBlocks); + while ( PlayedWaveHeadersCount > 0 ) // free used blocks ... + free_memory (); + } + + waveOutReset (dev); // reset the device + waveOutClose (dev); // close the device + dev = NULL; + } + + DeleteCriticalSection ( &cs ); + ScheduledBlocks = 0; + return 0; +} + +#endif + +/* end of wave_out.c */ diff --git a/native/codec/libraries/speex/src/wave_out.h b/native/codec/libraries/speex/src/wave_out.h new file mode 100644 index 0000000..a4aa3c1 --- /dev/null +++ b/native/codec/libraries/speex/src/wave_out.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2002, John Edwards + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// WAVE_OUT.H - Necessary stuff for WIN_AUDIO + +#ifndef WAVE_OUT_H +#define WAVE_OUT_H + +#include +#include +#ifdef __MINGW32__ +#include +#endif + +#define VERSION_STRING "\n 0.7.0\n" + +#define Cdecl __cdecl +#define __attribute__(x) +#define sleep(__sec) Sleep ((__sec) * 1000) +#define inline __inline +#define restrict + +//// constants ///////////////////////////////////////////////////// + +#define CD_SAMPLE_FREQ 44.1e3 +#define SAMPLE_SIZE 16 +#define SAMPLE_SIZE_STRING "" +#define WINAUDIO_FD ((FILE_T)-128) +#define FILE_T FILE* +#define INVALID_FILEDESC NULL + +//// Simple types ////////////////////////////////////////////////// + +typedef signed int Int; // at least -32767...+32767, fast type +typedef unsigned int Uint; // at least 0...65535, fast type +typedef long double Ldouble; // most exact floating point format + +//// procedures/functions ////////////////////////////////////////// +// wave_out.c +Int Set_WIN_Params ( FILE_T dummyFile , Ldouble SampleFreq, Uint BitsPerSample, Uint Channels); +int WIN_Play_Samples ( const void* buff, size_t len ); +int WIN_Audio_close ( void ); + +#endif /* WAVE_OUT_H */ diff --git a/native/codec/libraries/speex/symbian/Makefile.am b/native/codec/libraries/speex/symbian/Makefile.am new file mode 100644 index 0000000..6cdaf24 --- /dev/null +++ b/native/codec/libraries/speex/symbian/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = bld.inf config.h speex.mmp diff --git a/native/codec/libraries/speex/symbian/bld.inf b/native/codec/libraries/speex/symbian/bld.inf new file mode 100644 index 0000000..07f8f6f --- /dev/null +++ b/native/codec/libraries/speex/symbian/bld.inf @@ -0,0 +1,46 @@ +/* + Copyright (C) 2003 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of CSIRO Australia nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +PRJ_EXPORTS + +..\include\speex\speex_bits.h \epoc32\include\speex\speex_bits.h +..\include\speex\speex_callbacks.h \epoc32\include\speex\speex_callbacks.h +..\include\speex\speex_config_types.h \epoc32\include\speex\speex_config_types.h +..\include\speex\speex.h \epoc32\include\speex\speex.h +..\include\speex\speex_header.h \epoc32\include\speex\speex_header.h +..\include\speex\speex_stereo.h \epoc32\include\speex\speex_stereo.h +..\include\speex\speex_types.h \epoc32\include\speex\speex_types.h + + +PRJ_MMPFILES + +speex.mmp diff --git a/native/codec/libraries/speex/symbian/speex.mmp b/native/codec/libraries/speex/symbian/speex.mmp new file mode 100644 index 0000000..d50ad5b --- /dev/null +++ b/native/codec/libraries/speex/symbian/speex.mmp @@ -0,0 +1,45 @@ +/* + Copyright (C) 2003 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of CSIRO Australia nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +TARGET speex.lib +TARGETTYPE lib +UID 0 +MACRO HAVE_CONFIG_H +SOURCEPATH ..\libspeex +SOURCE bits.c cb_search.c exc_5_64_table.c exc_5_256_table.c exc_8_128_table.c +SOURCE exc_10_16_table.c exc_10_32_table.c exc_20_32_table.c fftwrap.c kiss_fft.c kiss_fftr.c filters.c gain_table.c +SOURCE gain_table_lbr.c hexc_10_32_table.c hexc_table.c high_lsp_tables.c +SOURCE lbr_48k_tables.c lpc.c lsp.c lsp_tables_nb.c ltp.c math_approx.c misc.c +SOURCE modes.c nb_celp.c quant_lsp.c sb_celp.c smallft.c +SOURCE speex.c speex_callbacks.c speex_header.c stereo.c vbr.c vq.c window.c +USERINCLUDE . ..\include\speex +SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\include diff --git a/native/codec/libraries/speex/ti/Makefile.am b/native/codec/libraries/speex/ti/Makefile.am new file mode 100644 index 0000000..200ca19 --- /dev/null +++ b/native/codec/libraries/speex/ti/Makefile.am @@ -0,0 +1,9 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +SUBDIRS = speex_C54_test speex_C55_test speex_C64_test + +EXTRA_DIST = config.h testenc-TI-C5x.c os_support_custom.h testenc-TI-C64x.c + diff --git a/native/codec/libraries/speex/ti/os_support_custom.h b/native/codec/libraries/speex/ti/os_support_custom.h new file mode 100644 index 0000000..1accbcb --- /dev/null +++ b/native/codec/libraries/speex/ti/os_support_custom.h @@ -0,0 +1,128 @@ +/* Copyright (C) 2007 Psi Systems, Inc. + Author: Jean-Marc Valin + File: os_support_custom.h + Memory Allocation overrides to allow user control rather than C alloc/free. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef MANUAL_ALLOC + +/* To avoid changing the Speex call model, this file relies on four static variables + The user main creates two linear buffers, and initializes spxGlobalHeap/ScratchPtr + to point to the start of the two buffers, and initializes spxGlobalHeap/ScratchEnd + to point to the first address following the last byte of the two buffers. + + This mechanism allows, for example, data caching for multichannel applications, + where the Speex state is swapped from a large slow memory to a small fast memory + each time the codec runs. + + Persistent data is allocated in spxGlobalHeap (instead of calloc), while scratch + data is allocated in spxGlobalScratch. +*/ + +extern char *spxGlobalHeapPtr, *spxGlobalHeapEnd; +extern char *spxGlobalScratchPtr, *spxGlobalScratchEnd; + +/* Make sure that all structures are aligned to largest type */ +#define BLOCK_MASK (sizeof(long double)-1) +extern inline void speex_warning(const char *str); + +#define OVERRIDE_SPEEX_ALLOC +static inline void *speex_alloc (int size) +{ + void *ptr; + + ptr = (void *) (((int)spxGlobalHeapPtr + BLOCK_MASK) & ~BLOCK_MASK); //Start on 8 boundary + + spxGlobalHeapPtr = (char *)((int)ptr + size); // Update pointer to next free location + + if (spxGlobalHeapPtr > spxGlobalHeapEnd ) + { +#ifdef VERBOSE_ALLOC + fprintf (stderr, "insufficient space for persistent alloc request %d bytes\n", size); +#endif + return 0; + } + +#ifdef VERBOSE_ALLOC + fprintf (stderr, "Persist Allocated %d chars at %x, %d remaining\n", size, ptr, ((int)spxGlobalHeapEnd - (int)spxGlobalHeapPtr)); +#endif + memset(ptr, 0, size); + return ptr; +} + +#define OVERRIDE_SPEEX_ALLOC_SCRATCH +static inline void *speex_alloc_scratch (int size) +{ + void *ptr; + + ptr = (void *) (((int)spxGlobalScratchPtr + BLOCK_MASK) & ~BLOCK_MASK); //Start on 8 boundary + + spxGlobalScratchPtr = (char *)((int)ptr + size); // Update pointer to next free location + + if (spxGlobalScratchPtr > spxGlobalScratchEnd ) + { +#ifdef VERBOSE_ALLOC + fprintf (stderr, "insufficient space for scratch alloc request %d bytes\n", size); +#endif + return 0; + } + +#ifdef VERBOSE_ALLOC + fprintf (stderr, "Scratch Allocated %d chars at %x, %d remaining\n", size, ptr, ((int)spxGlobalScratchEnd - (int)spxGlobalScratchPtr)); +#endif + memset(ptr, 0, size); + return ptr; +} + +#define OVERRIDE_SPEEX_REALLOC +static inline void *speex_realloc (void *ptr, int size) +{ +#ifdef VERBOSE_ALLOC + speex_warning("realloc attempted, not allowed"); +#endif + return 0; +} + +#define OVERRIDE_SPEEX_FREE +static inline void speex_free (void *ptr) +{ +#ifdef VERBOSE_ALLOC + speex_warning("at speex_free"); +#endif +} +#define OVERRIDE_SPEEX_FREE_SCRATCH +static inline void speex_free_scratch (void *ptr) +{ +#ifdef VERBOSE_ALLOC + speex_warning("at speex_free_scratch"); +#endif +} + +#endif /* !MANUAL_ALLOC */ diff --git a/native/codec/libraries/speex/ti/speex_C54_test/Makefile.am b/native/codec/libraries/speex/ti/speex_C54_test/Makefile.am new file mode 100644 index 0000000..f7b10bc --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C54_test/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speex_C54_test.cmd speex_C54_test.pjt + + diff --git a/native/codec/libraries/speex/ti/speex_C54_test/speex_C54_test.cmd b/native/codec/libraries/speex/ti/speex_C54_test/speex_C54_test.cmd new file mode 100644 index 0000000..4989a35 --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C54_test/speex_C54_test.cmd @@ -0,0 +1,71 @@ +/* Copyright (C) 2005 Psi Systems, Inc. + File: speex_C54_test.cmd + Linker command file with memory allocation for TI TMS320VC5416 processor + for use with TI Code Composer (TM) DSP development tools. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +-c +-stack 0x2000 +-heap 0x1000 /* If private memory allocation is used for Speex */ +/*-heap 0x6000 /* If calloc is used for Speex */ +-lrts_ext.lib + +MEMORY +{ +/* PAGE 0: P_DARAM03: origin = 0x80, len = 0x7f00*/ + PAGE 0: P_DARAM03: origin = 0x5000, len = 0x2f80 + PAGE 0: VECT: origin = 0x7f80, len = 0x80 + PAGE 0: P_DARAM47: origin = 0x18000, len = 0x8000 + PAGE 0: SARAM03: origin = 0x28000, len = 0x8000 + PAGE 0: SARAM47: origin = 0x38000, len = 0x8000 + + PAGE 1: USERREGS: origin = 0x60, len = 0x1a + PAGE 1: BIOSREGS: origin = 0x7c, len = 0x4 + PAGE 1: CSLREGS: origin = 0x7a, len = 0x2 + D_DARAM03: origin = 0x80, len = 0x4f80 + D_DARAM47: origin = 0x8000, len = 0x8000 +} + +SECTIONS +{ + .vectors: {} > VECT PAGE 0 + .bootmem: {rts_ext.lib (.text)} > P_DARAM03 PAGE 0 +/* .bootmem: {} > P_DARAM03 PAGE 0 */ + .text: {} > SARAM03 PAGE 0 + .cinit: {} > SARAM03 PAGE 0 + .switch: {} > SARAM03 PAGE 0 + .bss: {} > D_DARAM03 | D_DARAM47 PAGE 1 + .far: {} > D_DARAM03 | D_DARAM47 PAGE 1 + .const: {} > D_DARAM03 | D_DARAM47 PAGE 1 + .sysmem: {} > D_DARAM47 PAGE 1 + .cio: {} > D_DARAM03 | D_DARAM47 PAGE 1 + .stack: {} > D_DARAM03 | D_DARAM47 PAGE 1 + .myheap: {} > D_DARAM47 PAGE 1 +} diff --git a/native/codec/libraries/speex/ti/speex_C54_test/speex_C54_test.pjt b/native/codec/libraries/speex/ti/speex_C54_test/speex_C54_test.pjt new file mode 100644 index 0000000..e02a14e --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C54_test/speex_C54_test.pjt @@ -0,0 +1,59 @@ +; Code Composer Project File, Version 2.0 (do not modify or remove this line) + +[Project Settings] +ProjectDir="C:\Speex\speex_14274\ti\speex_C54_test\" +ProjectType=Executable +CPUFamily=TMS320C54XX +Tool="Compiler" +Tool="CustomBuilder" +Tool="DspBiosBuilder" +Tool="Linker" +Config="Debug" +Config="Release" + +[Source Files] +Source="..\..\libspeex\bits.c" +Source="..\..\libspeex\cb_search.c" +Source="..\..\libspeex\exc_10_16_table.c" +Source="..\..\libspeex\exc_10_32_table.c" +Source="..\..\libspeex\exc_20_32_table.c" +Source="..\..\libspeex\exc_5_256_table.c" +Source="..\..\libspeex\exc_5_64_table.c" +Source="..\..\libspeex\exc_8_128_table.c" +Source="..\..\libspeex\filters.c" +Source="..\..\libspeex\gain_table.c" +Source="..\..\libspeex\gain_table_lbr.c" +Source="..\..\libspeex\lpc.c" +Source="..\..\libspeex\lsp.c" +Source="..\..\libspeex\lsp_tables_nb.c" +Source="..\..\libspeex\ltp.c" +Source="..\..\libspeex\modes.c" +Source="..\..\libspeex\nb_celp.c" +Source="..\..\libspeex\quant_lsp.c" +Source="..\..\libspeex\sb_celp.c" +Source="..\..\libspeex\speex.c" +Source="..\..\libspeex\speex_callbacks.c" +Source="..\..\libspeex\vbr.c" +Source="..\..\libspeex\vq.c" +Source="..\..\libspeex\window.c" +Source="..\..\ti\testenc-TI-C5x.c" +Source="speex_C54_test.cmd" + +["Compiler" Settings: "Debug"] +Options=-g -q -o3 -fr"..\ti\speex_C54_test\Debug" -i"..\ti" -i"..\include" -d"_DEBUG" -d"CONFIG_TI_C54X" -d"HAVE_CONFIG_H" -d"NO_LONGLONG" -mf -ms + +["Compiler" Settings: "Release"] +Options=-q -o2 -fr"..\ti\speex_C54_test\Release" -i"..\ti" -i"..\include" -d"CONFIG_TI_C54X" -d"HAVE_CONFIG_H" -d"NO_LONGLONG" -mf -ms + +["DspBiosBuilder" Settings: "Debug"] +Options=-v54 + +["DspBiosBuilder" Settings: "Release"] +Options=-v54 + +["Linker" Settings: "Debug"] +Options=-q -c -heap4096 -m".\Debug\speex_C54_test.map" -o".\Debug\speex_C54_test.out" -stack4096 -w -x + +["Linker" Settings: "Release"] +Options=-q -c -m".\Release\speex_C54_test.map" -o".\Release\speex_C54_test.out" -w -x + diff --git a/native/codec/libraries/speex/ti/speex_C55_test/Makefile.am b/native/codec/libraries/speex/ti/speex_C55_test/Makefile.am new file mode 100644 index 0000000..6c89ed7 --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C55_test/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speex_C55_test.cmd speex_C55_test.pjt diff --git a/native/codec/libraries/speex/ti/speex_C55_test/speex_C55_test.cmd b/native/codec/libraries/speex/ti/speex_C55_test/speex_C55_test.cmd new file mode 100644 index 0000000..17cbf01 --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C55_test/speex_C55_test.cmd @@ -0,0 +1,65 @@ +/* Copyright (C) 2005 Psi Systems, Inc. + File: speex_C55_test.cmd + Linker command file with memory allocation for TI TMS320VC5509A processor + for use with TI Code Composer (TM) DSP development tools. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +-c +-stack 0x1c00 +-heap 0x1000 /* If private memory allocation is used for Speex */ +/*-heap 0x6000 / * If calloc is used for Speex */ +-sysstack 0x200 +-lrts55.lib + +MEMORY +{ + DARAM: origin = 0x200, len = 0x7e00 + DARAM_B: origin = 0x8000, len = 0x8000 + VECT: origin = 0x100, len = 0x100 + SARAM_A: origin = 0x10000, len = 0x10000 + SARAM_B: origin = 0x20000, len = 0x20000 +} + +SECTIONS +{ + .vectors: {} > VECT + .bootmem: {} > DARAM + .text: {} > SARAM_B + .cinit: {} > SARAM_B + .switch: {} > SARAM_B + .bss: {} > DARAM +/* .far: {} > DARAM*/ + .const: {} > DARAM + .sysmem: {} > DARAM_B + .cio: {} > DARAM + .stack: {} > DARAM + .sysstack: {} > DARAM + .myheap: {} > SARAM_A +} diff --git a/native/codec/libraries/speex/ti/speex_C55_test/speex_C55_test.pjt b/native/codec/libraries/speex/ti/speex_C55_test/speex_C55_test.pjt new file mode 100644 index 0000000..b4d6b66 --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C55_test/speex_C55_test.pjt @@ -0,0 +1,59 @@ +; Code Composer Project File, Version 2.0 (do not modify or remove this line) + +[Project Settings] +ProjectDir="C:\Speex\speex_14274\ti\speex_C55_test\" +ProjectType=Executable +CPUFamily=TMS320C55XX +Tool="Compiler" +Tool="CustomBuilder" +Tool="DspBiosBuilder" +Tool="Linker" +Config="Debug" +Config="Release" + +[Source Files] +Source="..\..\libspeex\bits.c" +Source="..\..\libspeex\cb_search.c" +Source="..\..\libspeex\exc_10_16_table.c" +Source="..\..\libspeex\exc_10_32_table.c" +Source="..\..\libspeex\exc_20_32_table.c" +Source="..\..\libspeex\exc_5_256_table.c" +Source="..\..\libspeex\exc_5_64_table.c" +Source="..\..\libspeex\exc_8_128_table.c" +Source="..\..\libspeex\filters.c" +Source="..\..\libspeex\gain_table.c" +Source="..\..\libspeex\gain_table_lbr.c" +Source="..\..\libspeex\lpc.c" +Source="..\..\libspeex\lsp.c" +Source="..\..\libspeex\lsp_tables_nb.c" +Source="..\..\libspeex\ltp.c" +Source="..\..\libspeex\modes.c" +Source="..\..\libspeex\nb_celp.c" +Source="..\..\libspeex\quant_lsp.c" +Source="..\..\libspeex\sb_celp.c" +Source="..\..\libspeex\speex.c" +Source="..\..\libspeex\speex_callbacks.c" +Source="..\..\libspeex\vbr.c" +Source="..\..\libspeex\vq.c" +Source="..\..\libspeex\window.c" +Source="..\..\ti\testenc-TI-C5x.c" +Source="speex_C55_test.cmd" + +["Compiler" Settings: "Debug"] +Options=-g -q -o3 -fr"..\ti\speex_C55_test\Debug" -i"..\ti" -i"..\include" -d"_DEBUG" -d"CONFIG_TI_C55X" -d"HAVE_CONFIG_H" -mn + +["Compiler" Settings: "Release"] +Options=-q -o2 -fr"..\ti\speex_C55_test\Release" -i"..\ti" -i"..\include" -d"CONFIG_TI_C55X" -d"HAVE_CONFIG_H" -mn + +["DspBiosBuilder" Settings: "Debug"] +Options=-v55 + +["DspBiosBuilder" Settings: "Release"] +Options=-v55 + +["Linker" Settings: "Debug"] +Options=-q -c -m".\Debug\speex_C55_test.map" -o".\Debug\speex_C55_test.out" -w -x + +["Linker" Settings: "Release"] +Options=-q -c -m".\Release\speex_C55_test.map" -o".\Release\speex_C55_test.out" -w -x + diff --git a/native/codec/libraries/speex/ti/speex_C64_test/Makefile.am b/native/codec/libraries/speex/ti/speex_C64_test/Makefile.am new file mode 100644 index 0000000..14ea2ba --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C64_test/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speex_C64_test.cmd speex_C64_test.pjt diff --git a/native/codec/libraries/speex/ti/speex_C64_test/speex_C64_test.cmd b/native/codec/libraries/speex/ti/speex_C64_test/speex_C64_test.cmd new file mode 100644 index 0000000..1e023db --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C64_test/speex_C64_test.cmd @@ -0,0 +1,59 @@ +/* Copyright (C) 2005 Psi Systems, Inc. + File: speex_C64_test.cmd + Linker command file with memory allocation for TI TMS320C6415 processor + for use with TI Code Composer (TM) DSP development tools. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +-stack 0x10000 +-heap 0x10000 + + +MEMORY +{ + VECRAM : origin = 0x0, len = 0x200 + IPRAM : origin = 0x200, len = 0x40000 + IDRAM : origin = 0x80000, len = 0x70000 +} + +SECTIONS +{ + .vectors > VECRAM + .text > IPRAM + + .bss > IDRAM + .cinit > IDRAM + .const > IDRAM + .far > IDRAM + .stack > IDRAM + .cio > IDRAM + .sysmem > IDRAM + .switch > IDRAM + .myheap > IDRAM +} diff --git a/native/codec/libraries/speex/ti/speex_C64_test/speex_C64_test.pjt b/native/codec/libraries/speex/ti/speex_C64_test/speex_C64_test.pjt new file mode 100644 index 0000000..1fec98f --- /dev/null +++ b/native/codec/libraries/speex/ti/speex_C64_test/speex_C64_test.pjt @@ -0,0 +1,60 @@ +; Code Composer Project File, Version 2.0 (do not modify or remove this line) + +[Project Settings] +ProjectDir="C:\Speex\speex_14274\ti\speex_C64_test\" +ProjectType=Executable +CPUFamily=TMS320C64XX +Tool="Compiler" +Tool="CustomBuilder" +Tool="DspBiosBuilder" +Tool="Linker" +Config="Debug" +Config="Release" + +[Source Files] +Source="..\..\..\..\CCStudio_v3.1\C6000\cgtools\lib\rts6400.lib" +Source="..\..\libspeex\bits.c" +Source="..\..\libspeex\cb_search.c" +Source="..\..\libspeex\exc_10_16_table.c" +Source="..\..\libspeex\exc_10_32_table.c" +Source="..\..\libspeex\exc_20_32_table.c" +Source="..\..\libspeex\exc_5_256_table.c" +Source="..\..\libspeex\exc_5_64_table.c" +Source="..\..\libspeex\exc_8_128_table.c" +Source="..\..\libspeex\filters.c" +Source="..\..\libspeex\gain_table.c" +Source="..\..\libspeex\gain_table_lbr.c" +Source="..\..\libspeex\lpc.c" +Source="..\..\libspeex\lsp.c" +Source="..\..\libspeex\lsp_tables_nb.c" +Source="..\..\libspeex\ltp.c" +Source="..\..\libspeex\modes.c" +Source="..\..\libspeex\nb_celp.c" +Source="..\..\libspeex\quant_lsp.c" +Source="..\..\libspeex\sb_celp.c" +Source="..\..\libspeex\speex.c" +Source="..\..\libspeex\speex_callbacks.c" +Source="..\..\libspeex\vbr.c" +Source="..\..\libspeex\vq.c" +Source="..\..\libspeex\window.c" +Source="..\testenc-TI-C64x.c" +Source="speex_C64_test.cmd" + +["Compiler" Settings: "Debug"] +Options=-g -o3 -fr"$(Proj_dir)\Debug" -i"..\ti" -i"..\include" -d"_DEBUG" -d"CONFIG_TI_C6X" -d"HAVE_CONFIG_H" -mv6400 + +["Compiler" Settings: "Release"] +Options=-o3 -fr"$(Proj_dir)\Release" -i"..\ti" -i"..\include" -d"HAVE_CONFIG_H" -mv6400 + +["DspBiosBuilder" Settings: "Debug"] +Options=-v6x + +["DspBiosBuilder" Settings: "Release"] +Options=-v6x + +["Linker" Settings: "Debug"] +Options=-c -m".\Debug\speex_C64_test.map" -o".\Debug\speex_C64_test.out" -w -x + +["Linker" Settings: "Release"] +Options=-c -m".\Release\speex_C64_test.map" -o".\Release\speex_C64_test.out" -w -x + diff --git a/native/codec/libraries/speex/ti/testenc-TI-C5x.c b/native/codec/libraries/speex/ti/testenc-TI-C5x.c new file mode 100644 index 0000000..45979e6 --- /dev/null +++ b/native/codec/libraries/speex/ti/testenc-TI-C5x.c @@ -0,0 +1,294 @@ +/* Copyright (C) 2005 Psi Systems, Inc. + File: testenc-TI-C5x.c + Encoder/Decoder Loop Main file for TI C54xx and C55xx processors + for use with TI Code Composer (TM) DSP development tools. + Modified from speexlib/testenc.c + + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Modified from speexlib/testenc.c for Code Composer simulator */ + +#include +#include +#include +#include +#include <..\libspeex\arch.h> + +#undef DECODE_ONLY +#define CHECK_RESULT /* Compares original file with encoded/decoder file */ +#define TESTENC_BYTES_PER_FRAME 20 /* 8kbps */ +#define TESTENC_QUALITY 4 /* 8kbps */ +//#define TESTENC_BYTES_PER_FRAME 28 /* 11kbps */ +//#define TESTENC_QUALITY 5 /* 11 kbps */ + +/* For narrowband, QUALITY maps to these bit rates (see modes.c, manual.pdf) + * {1, 8, 2, 3, 3, 4, 4, 5, 5, 6, 7} + * 0 -> 2150 + * 1 -> 3950 + * 2 -> 5950 + * 3 -> 8000 + * 4 -> 8000 + * 5 -> 11000 + * 6 -> 11000 + * 7 -> 15000 + * 8 -> 15000 + * 9 -> 18200 + *10 -> 26400 */ + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif +#include + +#ifdef MANUAL_ALLOC +/* Take all Speex space from this private heap */ +/* This is useful for multichannel applications */ +#pragma DATA_SECTION(spxHeap, ".myheap"); +static char spxHeap[SPEEX_PERSIST_STACK_SIZE]; + +#pragma DATA_SECTION(spxScratch, ".myheap"); +static char spxScratch[SPEEX_SCRATCH_STACK_SIZE]; + +char *spxGlobalHeapPtr, *spxGlobalHeapEnd; +char *spxGlobalScratchPtr, *spxGlobalScratchEnd; +#endif + +void byte2word(short* pInBuf, short* pOutBuf, int nWords) +{ + short *pIn, *pOut, sNext; + int i; + + pIn = pInBuf; + pOut = pOutBuf; + for(i=0;i> 8); + } +} + +void main() +{ + char *outFile, *bitsFile; + FILE *fout, *fbits=NULL; +#if !defined(DECODE_ONLY) || defined(CHECK_RESULT) + char *inFile; + FILE *fin; + short in_short[FRAME_SIZE]; +#endif + short out_short[FRAME_SIZE]; + short inout_byte[2*FRAME_SIZE]; +#ifndef DECODE_ONLY + int nbChars; +#endif +#ifdef CHECK_RESULT + float sigpow,errpow,snr, seg_snr=0; + int snr_frames = 0; + int i; +#endif + char cbits[TESTENC_BYTES_PER_FRAME/2 + 2]; /* temp store for encoded data */ + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + unsigned long bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + /* C54xx defaults to max wait states, even for parts like C5416 with + larger internal memory. Need to force the wait state register to zero */ + +#ifdef CONFIG_TI_C54X + asm(" STM #0,SWWSR"); +#endif + +#ifdef CHECK_RESULT + sigpow = 0; + errpow = 0; +#endif + +#ifdef MANUAL_ALLOC + spxGlobalHeapPtr = spxHeap; + spxGlobalHeapEnd = spxHeap + sizeof(spxHeap); + + spxGlobalScratchPtr = spxScratch; + spxGlobalScratchEnd = spxScratch + sizeof(spxScratch); +#endif + st = speex_encoder_init(&speex_nb_mode); +#ifdef MANUAL_ALLOC + spxGlobalScratchPtr = spxScratch; /* Reuse scratch for decoder */ +#endif + dec = speex_decoder_init(&speex_nb_mode); + + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + tmp=0; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=TESTENC_QUALITY; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=1; /* Lowest */ + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + +#ifdef DISABLE_HIGHPASS + /* Turn this off if you want to measure SNR (on by default) */ + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_HIGHPASS, &tmp); + speex_decoder_ctl(dec, SPEEX_SET_HIGHPASS, &tmp); +#endif + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + fprintf (stderr, "decoder lookahead = %ld\n", skip_group_delay); + +#ifdef DECODE_ONLY + bitsFile = "c:\\speextrunktest\\samples\\malebitsin.dat"; + fbits = fopen(bitsFile, "rb"); +#else + bitsFile = "c:\\speextrunktest\\samples\\malebits5x.dat"; + fbits = fopen(bitsFile, "wb"); +#endif +#if !defined(DECODE_ONLY) || defined(CHECK_RESULT) + inFile = "c:\\speextrunktest\\samples\\male.snd"; + fin = fopen(inFile, "rb"); +#endif + outFile = "c:\\speextrunktest\\samples\\maleout5x.snd"; + fout = fopen(outFile, "wb+"); + + speex_bits_init(&bits); +#ifndef DECODE_ONLY + while (!feof(fin)) + { + fread(inout_byte, 2, FRAME_SIZE, fin); + byte2word(inout_byte, in_short, FRAME_SIZE); /* C5x has 16-bit char */ + + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbChars = speex_bits_write(&bits, cbits, + sizeof(cbits)*BYTES_PER_CHAR) /BYTES_PER_CHAR; + bitCount+=bits.nbBits; + + word2byte((short *) cbits, inout_byte, nbChars); + fwrite(inout_byte, 2, nbChars, fbits); + speex_bits_rewind(&bits); + +#else /* DECODE_ONLY */ + while (!feof(fbits)) + { + fread(inout_byte, 1, TESTENC_BYTES_PER_FRAME, fbits); + + if (feof(fbits)) + break; + + byte2word(inout_byte, (short *)cbits, TESTENC_BYTES_PER_FRAME/2); + speex_bits_read_from(&bits, cbits, TESTENC_BYTES_PER_FRAME); + bitCount+=160; +#endif + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + word2byte(&out_short[skip_group_delay], inout_byte, FRAME_SIZE-skip_group_delay); + fwrite(inout_byte, 2, FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; +#if 1 + fprintf (stderr, "Bits so far: %lu \n", bitCount); +#endif + } + fprintf (stderr, "Total encoded size: %lu bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + +#ifdef CHECK_RESULT + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(inout_byte, 2, FRAME_SIZE, fin)) + { + float s=0, e=0; + + byte2word(inout_byte, in_short, FRAME_SIZE); + fread(inout_byte, 2, FRAME_SIZE, fout); + byte2word(inout_byte, out_short, FRAME_SIZE); + + for (i=0;i +#include +#include +#include + +#undef DECODE_ONLY +#define CHECK_RESULT /* Compares original file with encoded/decoder file */ +#define TESTENC_BYTES_PER_FRAME 20 /* 8kbps */ +#define TESTENC_QUALITY 4 /* 8kbps */ +//#define TESTENC_BYTES_PER_FRAME 28 /* 11kbps */ +//#define TESTENC_QUALITY 5 /* 11 kbps */ + +/* For narrowband, QUALITY maps to these bit rates (see modes.c, manual.pdf) + * {1, 8, 2, 3, 3, 4, 4, 5, 5, 6, 7} + * 0 -> 2150 + * 1 -> 3950 + * 2 -> 5950 + * 3 -> 8000 + * 4 -> 8000 + * 5 -> 11000 + * 6 -> 11000 + * 7 -> 15000 + * 8 -> 15000 + * 9 -> 18200 + *10 -> 26400 */ + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#ifdef MANUAL_ALLOC +/* Take all Speex space from this private heap */ +/* This is useful for multichannel applications */ +#pragma DATA_SECTION(spxHeap, ".myheap"); +static char spxHeap[SPEEX_PERSIST_STACK_SIZE]; + +#pragma DATA_SECTION(spxScratch, ".myheap"); +static char spxScratch[SPEEX_SCRATCH_STACK_SIZE]; + +char *spxGlobalHeapPtr, *spxGlobalHeapEnd; +char *spxGlobalScratchPtr, *spxGlobalScratchEnd; +#endif /* MANUAL_ALLOC */ + +#include +void main() +{ + char *outFile, *bitsFile; + FILE *fout, *fbits=NULL; +#if !defined(DECODE_ONLY) || defined(CHECK_RESULT) + char *inFile; + FILE *fin; + short in_short[FRAME_SIZE]; +#endif + short out_short[FRAME_SIZE]; +#ifndef DECODE_ONLY + int nbBits; +#endif +#ifdef CHECK_RESULT + float sigpow,errpow,snr, seg_snr=0; + int snr_frames = 0; + int i; +#endif + char cbits[200]; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + unsigned long bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + +#ifdef CHECK_RESULT + sigpow = 0; + errpow = 0; +#endif + +#ifdef MANUAL_ALLOC + spxGlobalHeapPtr = spxHeap; + spxGlobalHeapEnd = spxHeap + sizeof(spxHeap); + + spxGlobalScratchPtr = spxScratch; + spxGlobalScratchEnd = spxScratch + sizeof(spxScratch); +#endif + st = speex_encoder_init(&speex_nb_mode); +#ifdef MANUAL_ALLOC + spxGlobalScratchPtr = spxScratch; /* Reuse scratch for decoder */ +#endif + dec = speex_decoder_init(&speex_nb_mode); + + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + tmp=0; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=TESTENC_QUALITY; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=1; /* Lowest */ + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + +#ifdef DISABLE_HIGHPASS + /* Turn this off if you want to measure SNR (on by default) */ + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_HIGHPASS, &tmp); + speex_decoder_ctl(dec, SPEEX_SET_HIGHPASS, &tmp); +#endif + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + fprintf (stderr, "decoder lookahead = %d\n", skip_group_delay); + +#ifdef DECODE_ONLY + bitsFile = "c:\\speextrunktest\\samples\\malebitsin.dat"; + fbits = fopen(bitsFile, "rb"); +#else + bitsFile = "c:\\speextrunktest\\samples\\malebits6x.dat"; + fbits = fopen(bitsFile, "wb"); +#endif +#if !defined(DECODE_ONLY) || defined(CHECK_RESULT) + inFile = "c:\\speextrunktest\\samples\\male.snd"; + fin = fopen(inFile, "rb"); +#endif + outFile = "c:\\speextrunktest\\samples\\maleout6x.snd"; + fout = fopen(outFile, "wb+"); + + speex_bits_init(&bits); +#ifndef DECODE_ONLY + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + +#else /* DECODE_ONLY */ + while (!feof(fbits)) + { + fread(cbits, 1, TESTENC_BYTES_PER_FRAME, fbits); + + if (feof(fbits)) + break; + + speex_bits_read_from(&bits, cbits, TESTENC_BYTES_PER_FRAME); +// bitCount+=160; /* only correct for 8kbps, but just for the printf */ + bitCount+=bits.nbBits; +#endif + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; +#if 1 + fprintf (stderr, "Bits so far: %lu \n", bitCount); +#endif + } + fprintf (stderr, "Total encoded size: %lu bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + +#ifdef CHECK_RESULT + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i + +#ifdef FIXED_POINT + +#undef sround +#define sround(x) sex16(((x) + (1<<(FRACBITS-1)) ) >> FRACBITS) + +#undef MIN +#undef MAX +#define MIN(a,b) imin(a,b) +#define MAX(a,b) imax(a,b) + +#define TM_MUL(res,a,b) \ + { register int a0, a1, b0, b1; \ + \ + a0 = sex16((a)); \ + a1 = asri(16,(a)); \ + b0 = sex16((b)); \ + b1 = asri(16,(b)); \ + (res)= pack16lsb( \ + sround(ifir16((a),funshift2((b),(b)))), \ + sround(a0*b0-a1*b1)); \ + } \ + +#define TM_ADD(res,a,b) \ + { (res)=dspidualadd((a),(b)); \ + } \ + +#define TM_SUB(res,a,b) \ + { (res)=dspidualsub((a),(b)); \ + } \ + +#define TM_SHR(res,a,shift) \ + { (res)=dualasr((a),(shift)); \ + } \ + +#define TM_DIV(res,c,frac) \ + { register int c1, c0; \ + \ + c1 = asri(16,(c)); \ + c0 = sex16((c)); \ + (res) = pack16lsb(sround(c1 * (32767/(frac))), sround(c0 * (32767/(frac))));\ + } \ + +#define TM_NEGMSB(res, a) \ + { (res) = pack16lsb((ineg(asri(16,(a)))), (a)); \ + } \ + +#else + +#undef MIN +#undef MAX +#define MIN(a,b) fmin(a,b) +#define MAX(a,b) fmax(a,b) + +#endif +#endif + +#undef CHECKBUF +#define CHECKBUF(buf,nbuf,n) \ + { \ + if ( nbuf < (size_t)(n) ) { \ + speex_free(buf); \ + buf = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx)*(n)); \ + nbuf = (size_t)(n); \ + } \ + } \ + +#undef C_ADD +#define C_ADD( res, a,b) \ + { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r) \ + CHECK_OVERFLOW_OP((a).i,+,(b).i) \ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + } \ + + +#undef C_SUB +#define C_SUB( res, a,b) \ + { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r) \ + CHECK_OVERFLOW_OP((a).i,-,(b).i) \ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + } \ + +#undef C_ADDTO +#define C_ADDTO( res , a) \ + { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r) \ + CHECK_OVERFLOW_OP((res).i,+,(a).i) \ + (res).r += (a).r; (res).i += (a).i; \ + } \ + +#undef C_SUBFROM +#define C_SUBFROM( res, a) \ + { \ + CHECK_OVERFLOW_OP((res).r,-,(a).r) \ + CHECK_OVERFLOW_OP((res).i,-,(a).i) \ + (res).r -= (a).r; (res).i -= (a).i; \ + } \ + +#undef kf_cexp +#define kf_cexp(x,phase) \ + { (x)->r = KISS_FFT_COS(phase); \ + (x)->i = KISS_FFT_SIN(phase); } \ + +#undef kf_cexp2 +#define kf_cexp2(x,phase) \ + { (x)->r = spx_cos_norm((phase)); \ + (x)->i = spx_cos_norm((phase)-32768); } \ + + +#ifdef FIXED_POINT + +#undef C_MUL +#define C_MUL(m,a,b) \ + { (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ + (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); } \ + +#undef C_FIXDIV +#define C_FIXDIV(c,div) \ + { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); } \ + +#undef C_MULBYSCALAR +#define C_MULBYSCALAR( c, s ) \ + { (c).r = sround( smul( (c).r , s ) ) ; \ + (c).i = sround( smul( (c).i , s ) ) ; } \ + +#else + +#undef C_MUL +#define C_MUL(m,a,b) \ + { (m).r = (a).r*(b).r - (a).i*(b).i; \ + (m).i = (a).r*(b).i + (a).i*(b).r; } \ + + +#undef C_MULBYSCALAR +#define C_MULBYSCALAR( c, s ) \ + { (c).r *= (s); \ + (c).i *= (s); } \ + + + +#endif + +#endif + diff --git a/native/codec/libraries/speex/tmv/cb_search_tm.h b/native/codec/libraries/speex/tmv/cb_search_tm.h new file mode 100644 index 0000000..05ec711 --- /dev/null +++ b/native/codec/libraries/speex/tmv/cb_search_tm.h @@ -0,0 +1,149 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file cb_search_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK +static void compute_weighted_codebook( + const signed char * restrict shape_cb, + const Int16 * restrict r, + Int16 * restrict resp, + Int16 * restrict resp2, + Int32 * restrict E, + int shape_cb_size, int subvect_size, char *stack) +{ + register int i, j; + register int quadsize; + + TMDEBUG_ALIGNMEM(r); + TMDEBUG_ALIGNMEM(resp); + TMDEBUG_ALIGNMEM(resp2); + + COMPUTEWEIGHTEDCODEBOOK_START(); + + quadsize = subvect_size << 2; + + for ( i=0 ; i>= 13; + resj1 >>= 13; + resj2 >>= 13; + resj3 >>= 13; + + e0 += resj0 * resj0; + e1 += resj1 * resj1; + e2 += resj2 * resj2; + e3 += resj3 * resj3; + + resp[j] = resj0; + resp[j+subvect_size] = resj1; + resp[j+2*subvect_size] = resj2; + resp[j+3*subvect_size] = resj3; + } + + E[i] = e0; + E[i+1] = e1; + E[i+2] = e2; + E[i+3] = e3; + + resp += quadsize; + shape_cb += quadsize; + } + +#ifndef REMARK_ON + (void)resp2; + (void)stack; +#endif + + COMPUTEWEIGHTEDCODEBOOK_STOP(); +} + +#define OVERRIDE_TARGET_UPDATE +static inline void target_update(Int16 * restrict t, Int16 g, Int16 * restrict r, int len) +{ + register int n; + register int gr1, gr2, t1, t2, r1, r2; + register int quadsize; + + TARGETUPDATE_START(); + + quadsize = len & 0xFFFFFFFC; + + for ( n=0; n +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define OVERRIDE_MAXIMIZE_RANGE +static int maximize_range(Int16 *in, Int16 *out, int bound, int len) +{ + register int max_val=0; + register int shift=0; + register int i, j; + + TMDEBUG_ALIGNMEM(in); + TMDEBUG_ALIGNMEM(out); + + MAXIMIZERANGE_START(); + + len >>= 1; + + for ( i=0 ; i>1) && max_val != 0 ) + { max_val <<= 1; + shift++; + } + + if ( shift != 0 ) + { + for ( i=0,j=0 ; i>1); + s = pack16lsb(s,s); + + len >>= 1; + l = len & (int)0xFFFFFFFE; + + for ( i=0,j=0 ; i>= 1; + + for( i=1 ; i +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define OVERRIDE_FILTERBANK_COMPUTE_BANK32 +void filterbank_compute_bank32(FilterBank * restrict bank, spx_word32_t * restrict ps, spx_word32_t * restrict mel) +{ + register int i, j, k, banks, len, zero, s; + register int * restrict left; + register int * restrict right; + register int * restrict bleft; + register int * restrict bright; + + left = (int*)bank->filter_left; + right = (int*)bank->filter_right; + bleft = (int*)bank->bank_left; + bright = (int*)bank->bank_right; + + TMDEBUG_ALIGNMEM(ps); + TMDEBUG_ALIGNMEM(mel); + TMDEBUG_ALIGNMEM(left); + TMDEBUG_ALIGNMEM(right); + TMDEBUG_ALIGNMEM(bleft); + TMDEBUG_ALIGNMEM(bright); + + FILTERBANKCOMPUTEBANK32_START(); + + banks = bank->nb_banks << 2; + zero = 0; + len = bank->len; + s = (1<<((15))>>1); + +#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i> 15; + ps0_lsb = ps0 & 0x00007fff; + left0 = sex16(left10); + right0 = sex16(right10); + + _mel += left0 * ps0_msb + ((left0 * ps0_lsb + s ) >> 15); + mel[il0]= _mel; + _mel = ld32x(mel,ir0); + _mel += right0 * ps0_msb + ((right0 * ps0_lsb + s ) >> 15); + mel[ir0]= _mel; + + ps1 = ld32x(ps,j); + il1 = ld32x(bleft,j); + _mel = ld32x(mel,il1); + ir1 = ld32x(bright,j); + + left1 = asri(16,left10); + right1 = asri(16,right10); + ps1_msb = ps1 >> 15; + ps1_lsb = ps1 & 0x00007fff; + + _mel += left1 * ps1_msb + ((left1 * ps1_lsb + s ) >> 15); + mel[il1]= _mel; + _mel = ld32x(mel,ir1); + _mel += right1 * ps1_msb + ((right1 * ps1_lsb + s ) >> 15); + mel[ir1]= _mel; + } +#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + FILTERBANKCOMPUTEBANK32_STOP(); +} + +#define OVERRIDE_FILTERBANK_COMPUTE_PSD16 +void filterbank_compute_psd16(FilterBank * restrict bank, spx_word16_t * restrict mel, spx_word16_t * restrict ps) +{ + register int i, j, k, len, s; + register int * restrict left; + register int * restrict right; + register int * restrict bleft; + register int * restrict bright; + + left = (int*)bank->filter_left; + right = (int*)bank->filter_right; + bleft = (int*)bank->bank_left; + bright = (int*)bank->bank_right; + + TMDEBUG_ALIGNMEM(ps); + TMDEBUG_ALIGNMEM(mel); + TMDEBUG_ALIGNMEM(left); + TMDEBUG_ALIGNMEM(right); + TMDEBUG_ALIGNMEM(bleft); + TMDEBUG_ALIGNMEM(bright); + + FILTERBANKCOMPUTEPSD16_START(); + + len = bank->len; + s = (1<<((15))>>1); + +#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEPSD16) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0,j=0,k=0 ; i>= 15; + + il1 = ld32x(bleft, i+1); + ir1 = ld32x(bright,i+1); + mell1 = mel[il1]; + melr1 = mel[ir1]; + mel1 = pack16lsb(mell1, melr1); + lr1 = pack16msb(left10, right10); + + acc1 += ifir16(mel1, lr1); + acc1 >>= 15; + + ps10 = pack16lsb(acc1, acc0); + + st32d(j, ps, ps10); + } +#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEPSD16) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + FILTERBANKCOMPUTEPSD16_STOP(); +} + +#else + +#define OVERRIDE_FILTERBANK_COMPUTE_BANK32 +void filterbank_compute_bank32(FilterBank * restrict bank, float * restrict ps, float * restrict mel) +{ + register int i, banks, len; + register int * restrict bleft, * restrict bright; + register float * restrict left, * restrict right; + + banks = bank->nb_banks; + len = bank->len; + bleft = bank->bank_left; + bright= bank->bank_right; + left = bank->filter_left; + right = bank->filter_right; + + FILTERBANKCOMPUTEBANK32_START(); + + memset(mel, 0, banks * sizeof(float)); + +#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEBANK32) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; ilen; + bleft = bank->bank_left; + bright= bank->bank_right; + left = bank->filter_left; + right = bank->filter_right; + + FILTERBANKCOMPUTEPSD16_START(); + +#if (TM_UNROLL && TM_UNROLL_FILTERBANKCOMPUTEPSD16) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define iadd(a,b) ((a) + (b)) + +#define OVERRIDE_BW_LPC +void bw_lpc(Int16 gamma, const Int16 *lpc_in, Int16 *lpc_out, int order) +{ + register int tmp, g, i; + + TMDEBUG_ALIGNMEM(lpc_in); + TMDEBUG_ALIGNMEM(lpc_out); + + BWLPC_START(); + + tmp = g = gamma; + for ( i=0 ; i<4 ; i+=2,lpc_out+=4 ) + { register int in10, y1, y0, y10; + register int in32, y3, y2, y32; + + in10 = ld32x(lpc_in,i); + y0 = ((tmp * sex16(in10)) + 16384) >> 15; + tmp = ((tmp * g) + 16384) >> 15; + y1 = ((tmp * asri(16,in10)) + 16384) >> 15; + tmp = ((tmp * g) + 16384) >> 15; + y10 = pack16lsb(y1,y0); + st32(lpc_out,y10); + + in32 = ld32x(lpc_in,i+1); + y2 = ((tmp * sex16(in32)) + 16384) >> 15; + tmp = ((tmp * g) + 16384) >> 15; + y3 = ((tmp * asri(16,in32)) + 16384) >> 15; + tmp = ((tmp * g) + 16384) >> 15; + y32 = pack16lsb(y3,y2); + st32d(4,lpc_out,y32); + } + + if ( order == 10 ) + { register int in10, y1, y0, y10; + + in10 = ld32x(lpc_in,i); + y0 = ((tmp * sex16(in10)) + 16384) >> 15; + tmp = ((tmp * g) + 16384) >> 15; + y1 = ((tmp * asri(16,in10)) + 16384) >> 15; + tmp = ((tmp * g) + 16384) >> 15; + y10 = pack16lsb(y1,y0); + st32(lpc_out,y10); + } + + BWLPC_STOP(); +} + + +#define OVERRIDE_HIGHPASS +void highpass(const Int16 *x, Int16 *y, int len, int filtID, Int32 *mem) +{ + const Int16 Pcoef[5][3] = {{16384, -31313, 14991}, {16384, -31569, 15249}, {16384, -31677, 15328}, {16384, -32313, 15947}, {16384, -22446, 6537}}; + const Int16 Zcoef[5][3] = {{15672, -31344, 15672}, {15802, -31601, 15802}, {15847, -31694, 15847}, {16162, -32322, 16162}, {14418, -28836, 14418}}; + register int i; + register int den1, den2, num0, num1, num2, den11, den22, mem0, mem1; + + TMDEBUG_ALIGNMEM(mem); + + HIGHPASS_START(); + + filtID = imin(4, filtID); + + den1 = -Pcoef[filtID][1]; + den2 = -Pcoef[filtID][2]; + num0 = Zcoef[filtID][0]; + num1 = Zcoef[filtID][1]; + num2 = Zcoef[filtID][2]; + den11 = den1 << 1; + den22 = den2 << 1; + mem0 = mem[0]; + mem1 = mem[1]; + +#if (TM_UNROLL && TM_UNROLL_HIGHPASS) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i> 15; + vout_d = vout & 0x7FFF; + yi = iclipi(PSHR32(vout,14),32767); + mem0 = (mem1 + num1 * xi) + (den11 * vout_i) + (((den1 * vout_d) >> 15) << 1); + mem1 = (num2 * xi) + (den22 * vout_i) + (((den2 * vout_d) >> 15) << 1); + + y[i] = yi; + } +#if (TM_UNROLL && TM_UNROLL_HIGHPASS) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + mem[0] = mem0; + mem[1] = mem1; + + HIGHPASS_STOP(); +} + + +#define OVERRIDE_SIGNALMUL +void signal_mul(const Int32 *x, Int32 *y, Int32 scale, int len) +{ + register int i, scale_i, scale_d; + + SIGNALMUL_START(); + + scale_i = scale >> 14; + scale_d = scale & 0x3FFF; + +#if (TM_UNROLL && TM_UNROLL_SIGNALMUL) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i> 7; + + y[i] = ((xi * scale_i + ((xi * scale_d) >> 14)) << 7); + + } +#if (TM_UNROLL && TM_UNROLL_SIGNALMUL) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + SIGNALMUL_STOP(); +} + +#define OVERRIDE_SIGNALDIV +void signal_div(const Int16 *x, Int16 *y, Int32 scale, int len) +{ + register int i; + + SIGNALDIV_START(); + + if (scale > SHL32(EXTEND32(SIG_SCALING), 8)) + { + register int scale_1; + scale = PSHR32(scale, SIG_SHIFT); + scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),7),scale); +#if (TM_UNROLL && TM_UNROLL_SIGNALDIV) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i SHR32(EXTEND32(SIG_SCALING), 2)) { + + register int scale_1; + scale = PSHR32(scale, SIG_SHIFT-5); + scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),3),scale); +#if (TM_UNROLL && TM_UNROLL_SIGNALDIV) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for (i=0;i16383 ) + { sig_shift++; + max_val >>= 1; + } + + + for ( i=0 ; i> sig_shift, ld32x(x,i+1) >> sig_shift); + acc1 = pack16lsb(ld32x(x,i+2) >> sig_shift, ld32x(x,i+3) >> sig_shift); + acc2 = ifir16(acc0,acc0) + ifir16(acc1, acc1); + sum += acc2 >> 6; + } + + return EXTRACT16(PSHR32(SHL32(EXTEND32(spx_sqrt(DIV32(sum,len))),(sig_shift+3)),SIG_SHIFT)); +} + +#define OVERRIDE_COMPUTE_RMS16 +Int16 compute_rms16(const Int16 *x, int len) +{ + register int max_val, i; + + COMPUTERMS16_START(); + + max_val = 10; + +#if 0 + + { + register int len2 = len >> 1; +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i16383) + { + register int sum = 0; +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i> 6; + } +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + COMPUTERMS16_STOP(); + return spx_sqrt(sum/len) << 4; + } else + { + register int sig_shift; + register int sum=0; + + sig_shift = mux(max_val < 8192, 1, 0); + sig_shift = mux(max_val < 4096, 2, sig_shift); + sig_shift = mux(max_val < 2048, 3, sig_shift); + +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i> 6; + } +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + COMPUTERMS16_STOP(); + return spx_sqrt(sum/len) << (3 - sig_shift); + } + } + +#else + { +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i16383) + { + register int sum = 0; +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i> 6; + } +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + COMPUTERMS16_STOP(); + return spx_sqrt(sum/len) << 4; + } else { + register int sig_shift; + register int sum=0; + + sig_shift = mux(max_val < 8192, 1, 0); + sig_shift = mux(max_val < 4096, 2, sig_shift); + sig_shift = mux(max_val < 2048, 3, sig_shift); + +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i> 6; + } +#if (TM_UNROLL && TM_UNROLL_COMPUTERMS16) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + COMPUTERMS16_STOP(); + return spx_sqrt(sum/len) << (3 - sig_shift); + } + } +#endif +} + +int normalize16_9(const Int32* restrict x, Int16 * restrict y, Int32 max_scale) +{ + register int x0, x1, x2, x3, x4, x5, x6, x7, x8; + register int max_val, m0, m1, m2, m3, m4; + register int sig_shift; + register int y10, y32, y54, y76; + + TMDEBUG_ALIGNMEM(x); + + x0 = ld32(x); + x1 = ld32x(x,1); x2 = ld32x(x,2); x3 = ld32x(x,3); x4 = ld32x(x,4); + x5 = ld32x(x,5); x6 = ld32x(x,6); x7 = ld32x(x,7); x8 = ld32x(x,8); + + m0 = imax(iabs(x0), iabs(x1)); + m1 = imax(iabs(x2), iabs(x3)); + m2 = imax(iabs(x4), iabs(x5)); + m3 = imax(iabs(x6), iabs(x7)); + m4 = imax(m0, iabs(x8)); + m1 = imax(m1, m2); + m3 = imax(m3, m4); + max_val = imax(1,imax(m1,m3)); + + sig_shift=0; + while (max_val>max_scale) + { sig_shift++; + max_val >>= 1; + } + + if ( sig_shift != 0 ) + { + y10 = pack16lsb(x1 >> sig_shift, x0 >> sig_shift); + y32 = pack16lsb(x3 >> sig_shift, x2 >> sig_shift); + y54 = pack16lsb(x5 >> sig_shift, x4 >> sig_shift); + y76 = pack16lsb(x7 >> sig_shift, x6 >> sig_shift); + + y[8] = x8 >> sig_shift; + st32(y,y10); + st32d(4,y,y32); + st32d(8,y,y54); + st32d(12,y,y76); + } + return sig_shift; +} + +int normalize16_mod8(const Int32 * restrict x, Int16 * restrict y, Int32 max_scale,int len) +{ + register int i, max_val, sig_shift; + + TMDEBUG_ALIGNMEM(x); + + max_val = 1; + + for ( i=0 ; imax_scale) + { sig_shift++; + max_val >>= 1; + } + + if ( sig_shift != 0 ) + { + for ( i=0 ; i> sig_shift, x0 >> sig_shift); + y32 = pack16lsb(x3 >> sig_shift, x2 >> sig_shift); + y54 = pack16lsb(x5 >> sig_shift, x4 >> sig_shift); + y76 = pack16lsb(x7 >> sig_shift, x6 >> sig_shift); + + st32(y,y10); + st32d(4,y,y32); + st32d(8,y,y54); + st32d(12,y,y76); + } + } + return sig_shift; +} + + +#define OVERRIDE_NORMALIZE16 +int normalize16(const Int32 *x, Int16 *y, Int32 max_scale, int len) +{ + TMDEBUG_ALIGNMEM(x); + TMDEBUG_ALIGNMEM(y); + + NORMALIZE16_START(); + + if ( len == 9 ) + { NORMALIZE16_STOP(); + return normalize16_9(x,y,max_scale); + } else + { NORMALIZE16_STOP(); + return normalize16_mod8(x,y,max_scale,len); + } +} + + +void filter_mem16_10(const Int16 *x, const Int16 *num, const Int16 *den, Int16 *y, int N, Int32 *mem) +{ + register int i; + register int c9, c8, c7, c6, c5; + register int c4, c3, c2, c1, c0; + register int input; + register int output_0, output_1, output_2, output_3, output_4; + register int output_5, output_6, output_7, output_8, output_9; + register Int16 xi, yi; + + c9 = pack16lsb(-den[9],num[9]); + c8 = pack16lsb(-den[8],num[8]); + c7 = pack16lsb(-den[7],num[7]); + c6 = pack16lsb(-den[6],num[6]); + c5 = pack16lsb(-den[5],num[5]); + c4 = pack16lsb(-den[4],num[4]); + c3 = pack16lsb(-den[3],num[3]); + c2 = pack16lsb(-den[2],num[2]); + c1 = pack16lsb(-den[1],num[1]); + c0 = pack16lsb(-den[0],num[0]); + + output_0 = mem[0]; + output_1 = mem[1]; + output_2 = mem[2]; + output_3 = mem[3]; + output_4 = mem[4]; + output_5 = mem[5]; + output_6 = mem[6]; + output_7 = mem[7]; + output_8 = mem[8]; + output_9 = mem[9]; + +#if (TM_UNROLL && TM_UNROLL_FILTER) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + + for ( i=0 ; i> 1; + + c67 = ld32x(num,3); + c45 = ld32x(num,2); + c23 = ld32x(num,1); + c01 = ld32x(num,0); + + c67 = funshift2(c67,c67); + c45 = funshift2(c45,c45); + c23 = funshift2(c23,c23); + c01 = funshift2(c01,c01); + + b3 = x76 = ld32x(x,N_2-1); + b2 = x54 = ld32x(x,N_2-2); + b1 = x32 = ld32x(x,N_2-3); + b0 = x10 = ld32x(x,N_2-4); + +#if (TM_UNROLL && TM_UNROLL_FILTER > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + + for ( i=N-1 ; i >= 8 ; --i ) + { + xi = asri(16,x76); + x76 = funshift2(x76, x54); + x54 = funshift2(x54, x32); + x32 = funshift2(x32, x10); + x10 = pack16lsb(x10, (int)x[i-8]); + + r2 = iadd(ifir16(x10,c67),ifir16(x32,c45)); + r3 = iadd(ifir16(x54,c23),ifir16(x76,c01)); + r1 = iadd(r2,r3); + + y[i] = iclipi(iadd(xi,PSHR32(r1,LPC_SHIFT)),32767); + } + for ( i=7, a=(Int16*)mem ; i>=0 ; --i ) + { + xi = asri(16,x76); + x76 = funshift2(x76, x54); + x54 = funshift2(x54, x32); + x32 = funshift2(x32, x10); + x10 = pack16lsb(x10, (int)a[i]); + + r2 = iadd(ifir16(x10,c67),ifir16(x32,c45)); + r3 = iadd(ifir16(x54,c23),ifir16(x76,c01)); + r1 = iadd(r2,r3); + + y[i] = iclipi(iadd(xi,PSHR32(r1,LPC_SHIFT)),32767); + } + +#if (TM_UNROLL && TM_UNROLL_FILTER > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + mem[0] = b0; + mem[1] = b1; + mem[2] = b2; + mem[3] = b3; +} + +void fir_mem16_10(const Int16 *x, const Int16 *num, Int16 *y, int N, Int32 *mem) +{ + register int N_2, i; + register int c89, c67, c45, c23, c01; + register int b0, b1, b2, b3, b4; + register int r1, r2, r3, r4, r5; + register int x10, x32, x54, x76, x98, xi; + register Int16 *a; + + N_2 = N >> 1; + + c89 = ld32x(num,4); + c67 = ld32x(num,3); + c45 = ld32x(num,2); + c23 = ld32x(num,1); + c01 = ld32x(num,0); + + c89 = funshift2(c89,c89); + c67 = funshift2(c67,c67); + c45 = funshift2(c45,c45); + c23 = funshift2(c23,c23); + c01 = funshift2(c01,c01); + + b4 = x98 = ld32x(x,N_2-1); + b3 = x76 = ld32x(x,N_2-2); + b2 = x54 = ld32x(x,N_2-3); + b1 = x32 = ld32x(x,N_2-4); + b0 = x10 = ld32x(x,N_2-5); + +#if (TM_UNROLL && TM_UNROLL_FIR > 0) +#pragma TCS_unroll=5 +#pragma TCS_unrollexact=1 +#endif + + for ( i=N-1 ; i >= 10 ; --i ) + { + xi = asri(16,x98); + x98 = funshift2(x98, x76); + x76 = funshift2(x76, x54); + x54 = funshift2(x54, x32); + x32 = funshift2(x32, x10); + x10 = pack16lsb(x10, (int)(x[i-10])); + + r2 = iadd(ifir16(x10,c89),ifir16(x32,c67)); + r3 = iadd(ifir16(x54,c45),ifir16(x76,c23)); + r4 = ifir16(x98,c01); + r5 = iadd(r2,r3); + r1 = iadd(r4,r5); + + y[i] = iclipi(iadd(xi,PSHR32(r1,LPC_SHIFT)),32767); + } + + for ( i=9,a =(Int16*)mem ; i>=0 ; --i ) + { + xi = asri(16,x98); + x98 = funshift2(x98, x76); + x76 = funshift2(x76, x54); + x54 = funshift2(x54, x32); + x32 = funshift2(x32, x10); + x10 = pack16lsb(x10, (int)(a[i])); + + r2 = iadd(ifir16(x10,c89),ifir16(x32,c67)); + r3 = iadd(ifir16(x54,c45),ifir16(x76,c23)); + r4 = ifir16(x98,c01); + r5 = iadd(r2,r3); + r1 = iadd(r4,r5); + + y[i] = iclipi(iadd(xi,PSHR32(r1,LPC_SHIFT)),32767); + } + +#if (TM_UNROLL && TM_UNROLL_FIR > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + mem[0] = b0; + mem[1] = b1; + mem[2] = b2; + mem[3] = b3; + mem[4] = b4; + + +} + +#define OVERRIDE_FIR_MEM16 +void fir_mem16(const spx_word16_t *x, const Int16 *num, spx_word16_t *y, int N, int ord, Int32 *mem, char *stack) +{ + TMDEBUG_ALIGNMEM(x); + TMDEBUG_ALIGNMEM(y); + TMDEBUG_ALIGNMEM(num); + + FIRMEM16_START(); + + if(ord==10) + fir_mem16_10(x, num, y, N, mem); + else if (ord==8) + fir_mem16_8(x, num, y, N, mem); + +#ifndef REMARK_ON + (void)stack; +#endif + + FIRMEM16_STOP(); +} + + + +#define OVERRIDE_SYN_PERCEP_ZERO16 +void syn_percep_zero16(const Int16 *xx, const Int16 *ak, const Int16 *awk1, const Int16 *awk2, Int16 *y, int N, int ord, char *stack) +{ + register int i,j; + VARDECL(Int32 *mem); + ALLOC(mem, ord, Int32); + + TMDEBUG_ALIGNMEM(mem); + + for ( i=0,j=0 ; i 0) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=24 ; i 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + y10 = y32 = y54 = y76 = y98 = 0; + awk_01 = ld32(awk2); + awk_23 = ld32x(awk2,1); + awk_45 = ld32x(awk2,2); + awk_67 = ld32x(awk2,3); + awk_89 = ld32x(awk2,4); + + awk_01 = funshift2(awk_01, awk_01); + awk_23 = funshift2(awk_23, awk_23); + awk_45 = funshift2(awk_45, awk_45); + awk_67 = funshift2(awk_67, awk_67); + awk_89 = funshift2(awk_89, awk_89); + +#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + y10 = y32 = y54 = y76 = y98 = 0; + awk_01 = ld32(ak); + awk_23 = ld32x(ak,1); + awk_45 = ld32x(ak,2); + awk_67 = ld32x(ak,3); + awk_89 = ld32x(ak,4); + awk_01 = funshift2(awk_01, awk_01); + awk_23 = funshift2(awk_23, awk_23); + awk_45 = funshift2(awk_45, awk_45); + awk_67 = funshift2(awk_67, awk_67); + awk_89 = funshift2(awk_89, awk_89); + +#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + +void compute_impulse_response_8(const Int16 *ak, const Int16 *awk1, const Int16 *awk2, Int16 *y, int N) +{ + register int awk_01, awk_23, awk_45, awk_67; + register int y10, y32, y54, y76, yi; + register int i, acc0, acc1, N_2; + + N_2 = N << 1; + + awk_01 = ld32(awk1); + awk_23 = ld32x(awk1,1); + awk_45 = ld32x(awk1,2); + awk_67 = ld32x(awk1,3); + + y10 = funshift2(awk_01, LPC_SCALING << 16); + st32d(0, y, y10); + y32 = funshift2(awk_23, awk_01); + st32d(4, y, y32); + y54 = funshift2(awk_45, awk_23); + st32d(8, y, y54); + y76 = funshift2(awk_67, awk_45); + st32d(12, y, y76); + y10 = funshift2(0, awk_67); + st32d(16, y, y10); + st32d(20, y, 0); + +#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=24 ; i 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + y10 = y32 = y54 = y76 = 0; + awk_01 = ld32(awk2); + awk_23 = ld32x(awk2,1); + awk_45 = ld32x(awk2,2); + awk_67 = ld32x(awk2,3); + + awk_01 = funshift2(awk_01, awk_01); + awk_23 = funshift2(awk_23, awk_23); + awk_45 = funshift2(awk_45, awk_45); + awk_67 = funshift2(awk_67, awk_67); +#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + y10 = y32 = y54 = y76 = 0; + awk_01 = ld32(ak); + awk_23 = ld32x(ak,1); + awk_45 = ld32x(ak,2); + awk_67 = ld32x(ak,3); + awk_01 = funshift2(awk_01, awk_01); + awk_23 = funshift2(awk_23, awk_23); + awk_45 = funshift2(awk_45, awk_45); + awk_67 = funshift2(awk_67, awk_67); +#if (TM_UNROLL && TM_UNROLL_COMPUTEIMPULSERESPONSE > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + + +#define OVERRIDE_COMPUTE_IMPULSE_RESPONSE +void compute_impulse_response(const Int16 *ak, const Int16 *awk1, const Int16 *awk2, Int16 *y, int N, int ord, char *stack) +{ + TMDEBUG_ALIGNMEM(ak); + TMDEBUG_ALIGNMEM(awk1); + TMDEBUG_ALIGNMEM(awk2); + TMDEBUG_ALIGNMEM(y); + + COMPUTEIMPULSERESPONSE_START(); + if ( ord == 10 ) + compute_impulse_response_10(ak,awk1,awk2,y,N); + else + compute_impulse_response_8(ak,awk1,awk2,y,N); + + (void)stack; + + COMPUTEIMPULSERESPONSE_STOP(); +} + + +#define OVERRIDE_QMFSYNTH +void qmf_synth(const Int16 *x1, const Int16 *x2, const Int16 *a, Int16 *y, int N, int M, Int32 *mem1, Int32 *mem2, char *stack) + /* assumptions: + all odd x[i] are zero -- well, actually they are left out of the array now + N and M are multiples of 4 */ +{ + register int i, j; + register int M2, N2; + VARDECL(int *x12); + M2 = M>>1; + N2 = N>>1; + ALLOC(x12, M2+N2, int); + + + TMDEBUG_ALIGNMEM(a); + TMDEBUG_ALIGNMEM(x12); + TMDEBUG_ALIGNMEM(mem1); + TMDEBUG_ALIGNMEM(mem2); + + QMFSYNTH_START(); + +#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + for (i = 0; i < N2; i += 2) + { + register int y0, y1, y2, y3; + register int x12_0; + + y0 = y1 = y2 = y3 = 0; + x12_0 = x12[N2-2-i]; + + for (j = 0; j < M2; j += 2) + { + register int x12_1; + register int a10, a11, a0_0; + register int _a10, _a11, _a0_0; + + a10 = ld32x(a,j); + a11 = pack16msb(a10,a10); + a0_0= pack16lsb(a10,ineg(sex16(a10))); + x12_1 = x12[N2-1+j-i]; + + y0 += ifir16(a0_0,x12_1); + y1 += ifir16(a11, x12_1); + y2 += ifir16(a0_0,x12_0); + y3 += ifir16(a11 ,x12_0); + + + _a10 = ld32x(a,j+1); + _a11 = pack16msb(_a10,_a10); + _a0_0 = pack16lsb(_a10,ineg(sex16(_a10))); + x12_0 = x12[N2+j-i]; + + y0 += ifir16(_a0_0,x12_0); + y1 += ifir16(_a11, x12_0); + y2 += ifir16(_a0_0,x12_1); + y3 += ifir16(_a11 ,x12_1); + + } + y[2*i] = EXTRACT16(SATURATE32(PSHR32(y0,15),32767)); + y[2*i+1] = EXTRACT16(SATURATE32(PSHR32(y1,15),32767)); + y[2*i+2] = EXTRACT16(SATURATE32(PSHR32(y2,15),32767)); + y[2*i+3] = EXTRACT16(SATURATE32(PSHR32(y3,15),32767)); + } + +#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for (i = 0; i < M2; ++i) + { mem1[2*i+1] = asri(16,x12[i]); + mem2[2*i+1] = sex16(x12[i]); + } +#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + QMFSYNTH_STOP(); +} + + +#define OVERRIDE_QMFDECOMP +void qmf_decomp(const Int16 *xx, const Int16 *aa, Int16 *y1, Int16 *y2, int N, int M, Int16 *mem, char *stack) +{ + VARDECL(int *_a); + VARDECL(int *_x); + register int i, j, k, MM, M2, N2; + register int _xx10, _mm10; + register int *_x2; + + M2=M>>1; + N2=N>>1; + MM=(M-2)<<1; + + ALLOC(_a, M2, int); + ALLOC(_x, N2+M2, int); + _x2 = _x + M2 - 1; + + TMDEBUG_ALIGNMEM(xx); + TMDEBUG_ALIGNMEM(aa); + TMDEBUG_ALIGNMEM(y1); + TMDEBUG_ALIGNMEM(y2); + TMDEBUG_ALIGNMEM(mem); + TMDEBUG_ALIGNMEM(_a); + TMDEBUG_ALIGNMEM(_x); + + QMFDECOMP_START(); + + _xx10 = ld32(xx); + _xx10 = dualasr(_xx10,1); + _mm10 = ld32(mem); + _x2[0] = pack16lsb(_xx10,_mm10); + +#if (TM_UNROLL && TM_UNROLL_QMFSYNTH > 0) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + mem[M-2] = xx[N-M+1] >> 1; + + + M2 >>= 1; + for ( i=0 ; i + + +#undef SATURATE +#undef SATURATE16 +#undef SATURATE32 +#define SATURATE(x,a) iclipi(x,a) +#define SATURATE16(x,a) iclipi(x,a) +#define SATURATE32(x,a) iclipi(x,a) + +#undef EXTEND32 +#define EXTEND32(x) sex16(x) + +#undef NEG16 +#undef NEG32 +#define NEG16(x) ineg((int)(x)) +#define NEG32(x) ineg(x) + +#undef ABS +#undef ABS16 +#undef ABS32 +#define ABS(x) iabs(x) +#define ABS32(x) iabs(x) +#define ABS16(x) iabs((int)(x)) + +#undef MIN16 +#undef MIN32 +#define MIN16(a,b) imin((int)(a),(int)(b)) +#define MIN32(a,b) imin(a,b) + +#undef MAX16 +#undef MAX32 +#define MAX16(a,b) imax((int)(a),(int)(b)) +#define MAX32(a,b) imax(a,b) + +#undef ADD16 +#undef SUB16 +#undef ADD32 +#undef SUB32 +#undef MULT16_16 +#undef MULT16_16_16 + +#define ADD16(a,b) ((int)(a) + (int)(b)) +#define SUB16(a,b) ((int)(a) - (int)(b)) +#define ADD32(a,b) ((int)(a) + (int)(b)) +#define SUB32(a,b) ((int)(a) - (int)(b)) +#define MULT16_16_16(a,b) ((int)(a) * (int)(b)) +#define MULT16_16(a,b) ((int)(a) * (int)(b)) + +#if TM_DEBUGMEM_ALIGNNMENT +#include +#define TMDEBUG_ALIGNMEM(x) \ + { if( ((int)(x) & (int)(0x00000003)) != 0 ) \ + { printf("memory not align. file: %s, line: %d\n", __FILE__, __LINE__); \ + } \ + } + +#else +#define TMDEBUG_ALIGNMEM(x) +#endif + +#endif + diff --git a/native/codec/libraries/speex/tmv/kiss_fft_tm.h b/native/codec/libraries/speex/tmv/kiss_fft_tm.h new file mode 100644 index 0000000..6f8b985 --- /dev/null +++ b/native/codec/libraries/speex/tmv/kiss_fft_tm.h @@ -0,0 +1,599 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file kiss_fft_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "_kiss_fft_guts_tm.h" + +#ifdef TM_ASM + +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define OVERRIDE_KFBFLY2 +static void kf_bfly2( + kiss_fft_cpx *Fout, + const int fstride, + const kiss_fft_cfg st, + int m + ) +{ + register int * restrict Fout2; + register int * restrict tw1 = (int*)st->twiddles; + register int i, j; + register int _inv = !st->inverse; + + Fout2 = (int*)Fout + m; + + for ( i=0,j=0 ; iinverse; + + tw3 = tw2 = tw1 = (int*)st->twiddles; + fstride2 = fstride << 1; + fstride3 = fstride * 3; + + Fout1 = (int*)Fout + m; + Fout2 = (int*)Fout + (m << 1); + Fout3 = (int*)Fout + (m * 3); + + + for ( i=0,j=0 ; iinverse; + + tw1 = tw2 = (int*)st->twiddles; + Fout1 = (int*)Fout + m; + Fout2 = (int*)Fout + (m << 1); + epi = tw1[fstride*m]; + epi = pack16lsb(epi,epi); + fstride2 = fstride << 1; + + for ( i=0,j=0 ; iinverse; + + + Fout1=(int*)Fout+m; + Fout2=(int*)Fout+(m<<1); + Fout3=(int*)Fout+(3 *m); + Fout4=(int*)Fout+(m<<2); + + tw1 = tw2 = tw3 = tw4 = (int*)st->twiddles; + + i = tw1[fstride*m]; + yab_lsb = tw1[fstride*(m<<1)]; + yab_msb = pack16msb(i, yab_lsb); + yab_lsb = pack16lsb(i, yab_lsb); + yba_msb = funshift2(-sex16(yab_msb), yab_msb); + yba_lsb = funshift2(yab_lsb, yab_lsb); + + fstride2 = fstride << 1; + fstride3 = fstride * 3; + fstride4 = fstride << 2; + + for ( i=0,j=0 ; iinverse; + register int i, j, k, l; + register int * restrict twiddles = (int*)st->twiddles; + register int Norig = st->nfft; + + CHECKBUF(scratchbuf,nscratchbuf,p); + + for ( i=0; i=Norig ) + { twidx -= Norig; + } + + sc = ld32x(scratchbuf,l); + tw = ld32x(twiddles,twidx); + + TM_MUL(sc, sc, tw); + TM_ADD(f10, f10, sc); + } + st32d(k<<2, Fout, f10); + } + } +} + +#else + +#define OVERRIDE_KFBFLY2 +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + register kiss_fft_cpx * restrict Fout2; + register kiss_fft_cpx * restrict tw1 = st->twiddles; + + Fout2 = Fout + m; + + do + { + register kiss_fft_cpx _fout2, _fout, t; + + _fout2 = *Fout2; + _fout = *Fout; + + C_MUL ( t, _fout2, *tw1); + C_SUB (_fout2, _fout, t); + C_ADD (_fout, _fout, t); + + *Fout2 = _fout2; + *Fout = _fout; + + tw1 += fstride; + ++Fout2; + ++Fout; + + } while ( --m ); +} + +#define OVERRIDE_KFBFLY4 +static void kf_bfly4( + kiss_fft_cpx * Fout, + const int fstride, + const kiss_fft_cfg st, + int m + ) +{ + register kiss_fft_cpx * restrict tw1,* restrict tw2,* restrict tw3; + register kiss_fft_cpx * restrict Fout1, * restrict Fout2, * restrict Fout3; + register int _inv = !st->inverse; + + tw3 = tw2 = tw1 = st->twiddles; + + Fout1 = Fout + m; + Fout2 = Fout + (m << 1); + Fout3 = Fout + (m * 3); + + do { + + register kiss_fft_cpx _fout; + register kiss_fft_cpx sc0, sc1, sc2, sc3, sc4, sc5; + + _fout = *Fout; + + C_MUL( sc0,*Fout1, *tw1); + C_MUL( sc1,*Fout2, *tw2); + C_MUL( sc2,*Fout3, *tw3); + C_SUB( sc5, _fout, sc1); + C_ADD( _fout, _fout, sc1); + C_ADD( sc3, sc0, sc2); + C_SUB( sc4, sc0, sc2); + C_SUB(*Fout2, _fout, sc3); + C_ADD( *Fout, _fout, sc3); + + tw1 += fstride; + tw2 += (fstride << 1); + tw3 += (fstride * 3); + + if ( _inv ) + { + Fout1->r = sc5.r + sc4.i; + Fout1->i = sc5.i - sc4.r; + Fout3->r = sc5.r - sc4.i; + Fout3->i = sc5.i + sc4.r; + } + else + { Fout1->r = sc5.r - sc4.i; + Fout1->i = sc5.i + sc4.r; + Fout3->r = sc5.r + sc4.i; + Fout3->i = sc5.i - sc4.r; + } + + + ++Fout; ++Fout1; ++Fout2; ++Fout3; + + } while(--m); +} + +#define OVERRIDE_KFBFLY3 +static void kf_bfly3( + kiss_fft_cpx * Fout, + const int fstride, + const kiss_fft_cfg st, + int m + ) +{ + register kiss_fft_cpx * restrict Fout1, * restrict Fout2; + register kiss_fft_cpx * restrict tw1,* restrict tw2; + register float epi; + + tw1 = tw2 = st->twiddles; + epi = st->twiddles[fstride*m].i; + Fout1 = Fout + m; + Fout2 = Fout + (m << 1); + + do { + + register kiss_fft_cpx _fout; + register kiss_fft_cpx sc0, sc1, sc2, sc3; + + _fout = *Fout; + + C_MUL( sc1, *Fout1, *tw1); + C_MUL( sc2, *Fout2, *tw2); + C_ADD( sc3, sc1, sc2); + C_SUB( sc0, sc1, sc2); + tw1 += fstride; + tw2 += (fstride << 1); + + sc1.r = _fout.r - HALF_OF(sc3.r); + sc1.i = _fout.i - HALF_OF(sc3.i); + + C_MULBYSCALAR(sc0, epi); + C_ADD(*Fout, _fout, sc3); + + Fout2->r = sc1.r + sc0.i; + Fout2->i = sc1.i - sc0.r; + + Fout1->r = sc1.i - sc0.i; + Fout1->i = sc1.r + sc0.r; + + ++Fout; ++Fout1; ++Fout2; + + } while(--m); +} + +#define OVERRIDE_KFBFLY5 +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + register kiss_fft_cpx * restrict Fout1,* restrict Fout2,* restrict Fout3,* restrict Fout4; + register int u; + register kiss_fft_cpx *tw; + register float yar, yai, ybr, ybi; + + Fout1=Fout+m; + Fout2=Fout+(m<<1); + Fout3=Fout+(m*3); + Fout4=Fout+(m<<2); + + tw = st->twiddles; + yar = tw[fstride*m].r; + yai = tw[fstride*m].i; + ybr = tw[fstride*2*m].r; + ybi = tw[fstride*2*m].i; + + for ( u=0; ur = sc0.r + sc7.r + sc8.r; + Fout->i = sc0.i + sc7.i + sc8.i; + + sc5.r = sc0.r + S_MUL(sc7.r,yar) + S_MUL(sc8.r,ybr); + sc5.i = sc0.i + S_MUL(sc7.i,yar) + S_MUL(sc8.i,ybr); + + sc6.r = S_MUL(sc10.i,yai) + S_MUL(sc9.i,ybi); + sc6.i = -S_MUL(sc10.r,yai) - S_MUL(sc9.r,ybi); + + C_SUB(*Fout1,sc5,sc6); + C_ADD(*Fout4,sc5,sc6); + + sc11.r = sc0.r + S_MUL(sc7.r,ybr) + S_MUL(sc8.r,yar); + sc11.i = sc0.i + S_MUL(sc7.i,ybr) + S_MUL(sc8.i,yar); + sc12.r = - S_MUL(sc10.i,ybi) + S_MUL(sc9.i,yai); + sc12.i = S_MUL(sc10.r,ybi) - S_MUL(sc9.r,yai); + C_ADD(*Fout2,sc11,sc12); + C_SUB(*Fout3,sc11,sc12); + + ++Fout1; ++Fout2; ++Fout3; ++Fout4; + } +} + + +#endif + +#endif diff --git a/native/codec/libraries/speex/tmv/kiss_fftr_tm.h b/native/codec/libraries/speex/tmv/kiss_fftr_tm.h new file mode 100644 index 0000000..8005b22 --- /dev/null +++ b/native/codec/libraries/speex/tmv/kiss_fftr_tm.h @@ -0,0 +1,235 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file kiss_fftr_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "_kiss_fft_guts_tm.h" + +#ifdef TM_ASM + +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define TM_NDIV(res,c,frac) \ + { register int c1, c0; \ + \ + c1 = -asri(16,(c)); \ + c0 = sex16((c)); \ + (res) = pack16lsb(sround(c1 * (32767/(frac))), sround(c0 * (32767/(frac))));\ + } + + +#define OVERRIDE_KISS_FFTR +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar * restrict timedata, kiss_fft_cpx * restrict freqdata) +{ + register int ncfft, ncfft2, k; + register int * restrict tmpbuf; + register int * restrict twiddles; + + ncfft = st->substate->nfft; + ncfft2 = ncfft >> 1; + tmpbuf = (int*)st->tmpbuf; + twiddles = (int*)st->super_twiddles; + + TMDEBUG_ALIGNMEM(timedata); + TMDEBUG_ALIGNMEM(freqdata); + TMDEBUG_ALIGNMEM(tmpbuf); + TMDEBUG_ALIGNMEM(twiddles); + + kiss_fft(st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf); + + { + register int tdcr, tdci; + tdcr = sround(st->tmpbuf[0].r * (32767/2)); + tdci = sround(st->tmpbuf[0].i * (32767/2)); + + freqdata[0].r = tdcr + tdci; + freqdata[ncfft].r = tdcr - tdci; + freqdata[ncfft].i = freqdata[0].i = 0; + } + + for ( k=1 ; k <= ncfft2 ; ++k ) + { + register int fpk, fpnk, i, tw, f1k, f2k; + register int fq1, fq2; + + i = ncfft-k; + + fpk = ld32x(tmpbuf,k); + tw = ld32x(twiddles,k); + fpnk = ld32x(tmpbuf,i); + + TM_DIV(fpk, fpk, 2); + TM_NDIV(fpnk,fpnk,2); + + TM_ADD( f1k, fpk , fpnk ); + TM_SUB( f2k, fpk , fpnk ); + TM_MUL( tw , f2k, tw ); + TM_ADD( fq1, f1k, tw ); + TM_SHR( fq1, fq1, 1 ); + TM_SUB( fq2, f1k, tw ); + TM_NEGMSB( fq2, fq2 ); + TM_SHR( fq2, fq2, 1 ); + + + st32d( k<<2, freqdata, fq1 ); + st32d( i<<2, freqdata, fq2 ); + } +} + +#define OVERRIDE_KISS_FFTRI +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx * restrict freqdata,kiss_fft_scalar * restrict timedata) +{ + register int k, ncfft, ncfft2; + register int * restrict tmpbuf; + register int * restrict twiddles; + + ncfft = st->substate->nfft; + ncfft2 = ncfft >> 1; + tmpbuf = (int*)st->tmpbuf; + twiddles = (int*)st->super_twiddles; + + TMDEBUG_ALIGNMEM(freqdata); + TMDEBUG_ALIGNMEM(timedata); + TMDEBUG_ALIGNMEM(tmpbuf); + TMDEBUG_ALIGNMEM(twiddles); + + { + register int fqr, fqnr; + + fqr = freqdata[0].r; + fqnr = freqdata[ncfft].r; + + st->tmpbuf[0].r = fqr + fqnr; + st->tmpbuf[0].i = fqr - fqnr; + } + + for ( k=1 ; k <= ncfft2 ; ++k ) + { + register int fk, fnkc, i, tw, fek, fok, tmp; + register int tbk, tbn; + + i = ncfft-k; + + fk = ld32x(freqdata,k); + tw = ld32x(twiddles,k); + fnkc = pack16lsb(-freqdata[i].i, freqdata[i].r); + + TM_ADD (fek, fk, fnkc); + TM_SUB (tmp, fk, fnkc); + TM_MUL (fok, tmp, tw ); + TM_ADD (tbk, fek, fok); + TM_SUB (tbn, fek, fok); + TM_NEGMSB(tbn, tbn); + + st32d(k<<2, tmpbuf, tbk); + st32d(i<<2, tmpbuf, tbn); + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} + +#else + +#define OVERRIDE_KISS_FFTR +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar * restrict timedata,kiss_fft_cpx * restrict freqdata) +{ + register kiss_fft_cpx fpnk, fpk, f1k, f2k, twk; + register int k, ncfft; + register kiss_fft_cpx * restrict tmpbuf, * restrict tw; + register float tdcr, tdci; + + ncfft = st->substate->nfft; + tmpbuf= st->tmpbuf; + tw = st->super_twiddles; + + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, tmpbuf ); + + tdcr = tmpbuf[0].r; + tdci = tmpbuf[0].i; + + freqdata[0].r = tdcr + tdci; + freqdata[ncfft].r = tdcr - tdci; + freqdata[ncfft].i = freqdata[0].i = 0; + + for ( k=1;k <= ncfft/2 ; ++k ) + { + fpk = tmpbuf[k]; + fpnk.r = tmpbuf[ncfft-k].r; + fpnk.i = -tmpbuf[ncfft-k].i; + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + C_MUL( twk, f2k , tw[k]); + + freqdata[k].r = HALF_OF(f1k.r + twk.r); + freqdata[k].i = HALF_OF(f1k.i + twk.i); + freqdata[ncfft-k].r = HALF_OF(f1k.r - twk.r); + freqdata[ncfft-k].i = HALF_OF(twk.i - f1k.i); + } +} + +#define OVERRIDE_KISS_FFTRI +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx * restrict freqdata,kiss_fft_scalar * restrict timedata) +{ + register int k, ncfft; + register kiss_fft_cpx * restrict tmpbuf, * restrict tw; + + + ncfft = st->substate->nfft; + tmpbuf= st->tmpbuf; + tw = st->super_twiddles; + + tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; + tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; + + for (k = 1; k <= ncfft / 2; ++k) + { + register kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk = freqdata[k]; + fnkc.r = freqdata[ncfft - k].r; + fnkc.i = -freqdata[ncfft - k].i; + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok,tmp,tw[k]); + C_ADD (tmpbuf[k],fek, fok); + C_SUB (tmp, fek, fok); + tmpbuf[ncfft - k].r = tmp.r; + tmpbuf[ncfft - k].i = -tmp.i; + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} + +#endif +#endif + diff --git a/native/codec/libraries/speex/tmv/lpc_tm.h b/native/codec/libraries/speex/tmv/lpc_tm.h new file mode 100644 index 0000000..05b0988 --- /dev/null +++ b/native/codec/libraries/speex/tmv/lpc_tm.h @@ -0,0 +1,150 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file lpc_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define OVERRIDE_SPEEX_AUTOCORR +void _spx_autocorr(const Int16 *x, Int16 *ac, int lag, int n) +{ + register int i, j; + register int shift, ac_shift; + register int n_2; + register int ac0; + + TMDEBUG_ALIGNMEM(x); + TMDEBUG_ALIGNMEM(ac); + + _SPX_AUTOCORR_START(); + + n_2 = n >> 1; + ac0 = n + 1; + +#if (TM_UNROLL && TM_UNROLL__SPXAUTOCORR) +#pragma TCS_unroll=5 +#pragma TCS_unrollexact=1 +#endif + for ( j=0 ; j> 8; + ac0 += ifir16(x32, x32) >> 8; + ac0 += ifir16(x54, x54) >> 8; + ac0 += ifir16(x76, x76) >> 8; + } +#if (TM_UNROLL && TM_UNROLL__SPXAUTOCORR) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + shift = 8; + while (shift && ac0<0x40000000) + { shift--; + ac0 <<= 1; + } + + ac_shift = 18; + while (ac_shift && ac0<0x40000000) + { ac_shift--; + ac0 <<= 1; + } + + if ( shift == 0 ) + { + for ( i=0 ; i> ac_shift; + } + } else + { + for ( i=0 ; i> shift; + } + + for ( k=16,l=8,m=16-i ; k> shift; + acc2 += ifir16(x32,y32) >> shift; + } + + ac[i] = (acc0 + acc1 + acc2) >> ac_shift; + } + } + + _SPX_AUTOCORR_STOP(); +} + +#endif diff --git a/native/codec/libraries/speex/tmv/lsp_tm.h b/native/codec/libraries/speex/tmv/lsp_tm.h new file mode 100644 index 0000000..879d37e --- /dev/null +++ b/native/codec/libraries/speex/tmv/lsp_tm.h @@ -0,0 +1,310 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file lsp_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "profile_tm.h" + + +#ifdef FIXED_POINT + +#define OVERRIDE_LSP_INTERPOLATE +void lsp_interpolate(Int16 *old_lsp, Int16 *new_lsp, Int16 *interp_lsp, int len, int subframe, int nb_subframes) +{ + register int tmp = DIV32_16(SHL32(EXTEND32(1 + subframe),14),nb_subframes); + register int tmp2 = 16384-tmp; + register int in_0, in_1, factor, out_1, out_2, olsp, nlsp, ilsp; + register int i; + + TMDEBUG_ALIGNMEM(old_lsp); + TMDEBUG_ALIGNMEM(new_lsp); + TMDEBUG_ALIGNMEM(interp_lsp); + + LSPINTERPOLATE_START(); + + factor = pack16lsb(tmp,tmp2); + + len >>= 1; + for ( i=0 ; i> 14, out_1 >> 14); + st32d(i << 2, interp_lsp, ilsp); + + } + + LSPINTERPOLATE_STOP(); +} + + +#define OVERRIDE_CHEB_POLY_EVA +static inline Int32 cheb_poly_eva(Int16 *coef, Int16 x, int m, char *stack) +{ + register int c10, c32, c54; + register int sum, b0, f0, f1, f2, f3; + register int xx, f32, f10; + + CHEBPOLYEVA_START(); + + xx = sex16(x); + b0 = iclipi(xx,16383); + +#if 0 + c10 = ld32(coef); + c32 = ld32x(coef,1); + c54 = ld32x(coef,2); +#else + c10 = pack16lsb(coef[1],coef[0]); + c32 = pack16lsb(coef[3],coef[2]); + c54 = pack16lsb(coef[5],coef[4]); +#endif + + f0 = ((xx * b0) >> 13) - 16384; + f1 = ((xx * f0) >> 13) - b0; + f2 = ((xx * f1) >> 13) - f0; + + if ( m == 4 ) + { sum = sex16(c54); + f32 = pack16lsb(xx,f0); + f10 = pack16lsb(f1,f2); + + } else + { sum = asri(16,c54); + sum += ((sex16(c54) * xx) + 8192) >> 14; + + f3 = ((xx * f2) >> 13) - f1; + f32 = pack16lsb(f0,f1); + f10 = pack16lsb(f2,f3); + } + + sum += (ifir16(c32,f32) + 8192) >> 14; + sum += (ifir16(c10,f10) + 8192) >> 14; + +#ifndef REMARK_ON + (void)stack; +#endif + + CHEBPOLYEVA_STOP(); + return sum; +} + + +#define OVERRIDE_LSP_ENFORCE_MARGIN +void lsp_enforce_margin(Int16 *lsp, int len, Int16 margin) +{ + register int i; + register int m = margin; + register int m2 = 25736-margin; + register int lsp0, lsp1, lsp2; + + TMDEBUG_ALIGNMEM(lsp); + + LSPENFORCEMARGIN_START(); + + lsp0 = ld32(lsp); + lsp1 = asri(16,lsp0); + lsp0 = sex16(lsp0); + lsp2 = lsp[len-1]; + + if ( lsp0 < m ) + { lsp0 = m; + lsp[0] = m; + } + + if ( lsp2 > m2 ) + { lsp2 = m2; + lsp[len-1] = m2; + } + + for ( i=1 ; i m2 ) + { lsp1 = (lsp1 >> 1) + (m2 >> 1); + lsp[i] = lsp1; + } + + lsp0 = lsp1; + lsp1 = lsp2; + } + + LSPENFORCEMARGIN_STOP(); +} + + +#define OVERRIDE_LSP_TO_LPC +void lsp_to_lpc(Int16 *freq, Int16 *ak,int lpcrdr, char *stack) +{ + VARDECL(Int16 *freqn); + VARDECL(int **xp); + VARDECL(int *xpmem); + VARDECL(int **xq); + VARDECL(int *xqmem); + + register int i, j, k; + register int xout1,xout2,xin; + register int m; + + LSPTOLPC_START(); + + m = lpcrdr>>1; + + /* + + Reconstruct P(z) and Q(z) by cascading second order polynomials + in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency. + In the time domain this is: + + y(n) = x(n) - 2cos(w)x(n-1) + x(n-2) + + This is what the ALLOCS below are trying to do: + + int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP + int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP + + These matrices store the output of each stage on each row. The + final (m-th) row has the output of the final (m-th) cascaded + 2nd order filter. The first row is the impulse input to the + system (not written as it is known). + + The version below takes advantage of the fact that a lot of the + outputs are zero or known, for example if we put an inpulse + into the first section the "clock" it 10 times only the first 3 + outputs samples are non-zero (it's an FIR filter). + */ + + ALLOC(xp, (m+1), int*); + ALLOC(xpmem, (m+1)*(lpcrdr+1+2), int); + + ALLOC(xq, (m+1), int*); + ALLOC(xqmem, (m+1)*(lpcrdr+1+2), int); + + for ( i=0; i<=m; i++ ) + { xp[i] = xpmem + i*(lpcrdr+1+2); + xq[i] = xqmem + i*(lpcrdr+1+2); + } + + /* work out 2cos terms in Q14 */ + + ALLOC(freqn, lpcrdr, Int16); + for ( j=0,k=0 ; j +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define OVERRIDE_INNER_PROD +Int32 inner_prod(const Int16 * restrict x, const Int16 * restrict y, int len) +{ + register int sum = 0; + + INNERPROD_START(); + + if ( (int)x & 0x03 == 0 && (int)y & 0x03 == 0 ) + { + register int i; + + len >>= 1; + for ( i=0 ; i> 6; + + x2 = ld32x(x,i+2); + y2 = ld32x(x,i+2); + x3 = ld32x(x,i+3); + y3 = ld32x(x,i+3); + sum += (ifir16(x2,y2) + ifir16(x3,y3)) >> 6; + + } + } else + { + len >>= 3; + while( len-- ) + { + register int x0, x1, x2, x3, y0, y1, y2, y3; + + x0 = pack16lsb(x[0],x[1]); + y0 = pack16lsb(y[0],y[1]); + x1 = pack16lsb(x[2],x[3]); + y1 = pack16lsb(y[2],y[3]); + sum += (ifir16(x0,y0) + ifir16(x1,y1)) >> 6; + + x2 = pack16lsb(x[4],x[5]); + y2 = pack16lsb(y[4],y[5]); + x3 = pack16lsb(x[6],x[7]); + y3 = pack16lsb(y[6],y[7]); + sum += (ifir16(x2,y2) + ifir16(x3,y3)) >> 6; + + x += 8; + y += 8; + } + } + + INNERPROD_STOP(); + return sum; +} + +#define OVERRIDE_PITCH_XCORR +void pitch_xcorr(const Int16 *_x, const Int16 *_y, Int32 *corr, int len, int nb_pitch, char *stack) +{ + register int sum_1, sum_2, sum_3, sum_4; + register int y10, y32, y54, y76, y21, y43, y65; + register int x10, x32; + register int i, j, k, limit; + + TMDEBUG_ALIGNMEM(_x); + TMDEBUG_ALIGNMEM(_y); + + PITCHXCORR_START(); + + limit = nb_pitch >> 1; + len >>= 1; + + for (i=0 ; i> 6; + sum_3 += (ifir16(x10,y32) + ifir16(x32,y54)) >> 6; + + y21 = funshift2(y32,y10); + y43 = funshift2(y54,y32); + y65 = funshift2(y76,y54); + + sum_2 += (ifir16(x10,y21) + ifir16(x32,y43)) >> 6; + sum_4 += (ifir16(x10,y43) + ifir16(x32,y65)) >> 6; + + y10 = y54; + y32 = y76; + + } + + k = i << 1; + corr[nb_pitch-1-k]=sum_1; + corr[nb_pitch-2-k]=sum_2; + corr[nb_pitch-3-k]=sum_3; + corr[nb_pitch-4-k]=sum_4; + } + +#ifndef REMARK_ON + (void)stack; +#endif + + PITCHXCORR_STOP(); +} + +#ifndef ttisim +#define OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ +static int pitch_gain_search_3tap_vq +( + const signed char *gain_cdbk, + int gain_cdbk_size, + Int16 *C16, + Int16 max_gain +) +{ + register int pp = 0x00400040, p=64; + register int g10, g2, g20, g21, g02, g22, g01; + register int cb0, cb1, cb2, cb5432; + register int C10, C32, C54, C76, C98, C83, C2; + register int acc0, acc1, acc2, acc3, sum, gsum, bsum=-VERY_LARGE32; + register int i, best_cdbk=0; + register Int16 tmp; + + TMDEBUG_ALIGNMEM(C16); + TMDEBUG_ALIGNMEM(gain_cdbk+2); + + PITCHGAINSEARCH3TAPVQ_START(); + + tmp = ild16(gain_cdbk); + C98 = ld32x(C16,4); + C32 = ld32x(C16,1); + C10 = ld32(C16); + C54 = ld32x(C16,2); + C76 = ld32x(C16,3); + + cb0 = sex8(tmp); + cb1 = sex8(tmp>>8); + C83 = funshift2(C98,C32); + C2 = sex16(C32); + gain_cdbk += 2; + + +#if (TM_UNROLL && TM_UNROLL_PITCHGAINSEARCH3TAPVQ > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0 ; i>8); + sum = 0; + + g10 = pack16lsb(cb1 + 32, cb0 + 32); + g2 = cb2 + 32; + g02 = pack16lsb(g10, g2); + acc0 = dspidualmul(g10,pp); + sum += ifir16(acc0,C10); + sum += p * g2 * C2; + + g22 = pack16lsb(g02, g02); + g01 = funshift2(g10, g10); + + acc1 = dspidualmul(g22, g01); + sum -= ifir16(acc1, C54); + acc2 = dspidualmul(g10, g10); + sum -= ifir16(acc2, C76); + + g20 = pack16lsb(g2, g10); + g21 = funshift2(g2, g10); + acc3 = dspidualmul(g20, g21); + sum -= ifir16(acc3, C83); + + + if ( sum>bsum && gsum<=max_gain ) + { bsum = sum; + best_cdbk=i; + } + + cb0 = sex8(cb5432 >> 16); + cb1 = asri(24,cb5432); + } +#if (TM_UNROLL && TM_UNROLL_PITCHGAINSEARCH3TAPVQ > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + + PITCHGAINSEARCH3TAPVQ_STOP(); + return best_cdbk; +} +#endif + +#define OVERRIDE_COMPUTE_PITCH_ERROR +#ifndef OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ +inline Int32 compute_pitch_error(Int16 *C, Int16 *g, Int16 pitch_control) +{ + register int c10, c32, c54, c76, c98, c83; + register int g10, g32, g02, g22, g01, g21, g20; + register int pp, tmp0, tmp1, tmp2, tmp3; + register int sum = 0; + + + COMPUTEPITCHERROR_START(); + + g10 = ld32(g); + g32 = ld32x(g,1); + pp = pack16lsb(pitch_control,pitch_control); + c10 = ld32(C); + c32 = ld32x(C,1); + g02 = pack16lsb(g10,g32); + g22 = pack16lsb(g32,g32); + g01 = funshift2(g10,g10); + tmp0 = dspidualmul(g10,pp); + sum += ifir16(tmp0, c10); + sum += pitch_control * sex16(g32) * sex16(c32); + c54 = ld32x(C,2); + c76 = ld32x(C,3); + c98 = ld32x(C,4); + tmp1 = dspidualmul(g22,g01); + sum -= ifir16(tmp1, c54); + tmp2 = dspidualmul(g10,g10); + sum -= ifir16(tmp2,c76); + c83 = funshift2(c98,c32); + g20 = funshift2(g02,g02); + g21 = funshift2(g02,g10); + tmp3 = dspidualmul(g20,g21); + sum -= ifir16(tmp3,c83); + + COMPUTEPITCHERROR_STOP(); + return sum; +} +#endif + +#define OVERRIDE_OPEN_LOOP_NBEST_PITCH +void open_loop_nbest_pitch(Int16 *sw, int start, int end, int len, int *pitch, Int16 *gain, int N, char *stack) +{ + VARDECL(int *best_score); + VARDECL(int *best_ener); + VARDECL(Int32 *corr); + VARDECL(Int16 *corr16); + VARDECL(Int16 *ener16); + register int i, j, k, l, N4, N2; + register int _sw10, _sw32, _s0, _s2, limit; + register int *energy; + register int cshift=0, eshift=0; + register int scaledown = 0; + register int e0, _energy0; + + ALLOC(corr16, end-start+1, Int16); + ALLOC(ener16, end-start+1, Int16); + ALLOC(corr, end-start+1, Int32); + ALLOC(best_score, N, int); + ALLOC(best_ener, N, int); + energy = corr; + N4 = N << 2; + N2 = N >> 1; + + TMDEBUG_ALIGNMEM(sw); + TMDEBUG_ALIGNMEM(pitch); + TMDEBUG_ALIGNMEM(gain); + TMDEBUG_ALIGNMEM(best_score); + TMDEBUG_ALIGNMEM(best_ener); + TMDEBUG_ALIGNMEM(corr16); + TMDEBUG_ALIGNMEM(ener16); + + OPENLOOPNBESTPITCH_START(); + + for ( i=0 ; i> 6)) - ((_s2 * _s2) >> 6); + _energy0 = imax(0,_energy1); + energy[i] = _energy0; + __sw10 = ld32x(sw,j); + __sw32 = ld32x(sw,k); + __s0 = asri(16,__sw10); + __s2 = asri(16,__sw32); + _energy1 = (_energy0 + ((__s0 * __s0) >> 6)) - ((__s2 * __s2) >> 6); + _energy0 = imax(0,_energy1); + energy[i+1] = _energy0; + _sw10 = __sw10; + _sw32 = __sw32; + } + + _s0 = sex16(_sw10); + _s2 = sex16(_sw32); + _energy0 = imax(0,(_energy0 + ((_s0 * _s0) >> 6)) - ((_s2 * _s2) >> 6)); + energy[i] = _energy0; + + + eshift = normalize16(energy, ener16, 32766, end-start+1); + /* In fixed-point, this actually overrites the energy array (aliased to corr) */ + pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack); + /* Normalize to 180 so we can square it and it still fits in 16 bits */ + cshift = normalize16(corr, corr16, 180, end-start+1); + /* If we scaled weighted input down, we need to scale it up again (OK, so we've just lost the LSB, who cares?) */ + + if ( scaledown ) + { + for ( j=asri(1,-end),k=asli(1,-end) ; j (best_score[N-1] * _e0) ) + { + best_score[N-1] = _c0; + best_ener[N-1] = _e0; + pitch[N-1] = i; + + for( j=0 ; j best_score[j] * _e0 ) + { for( k=N-1 ; k>j ; --k ) + { + best_score[k]=best_score[k-1]; + best_ener[k]=best_ener[k-1]; + pitch[k]=pitch[k-1]; + } + + best_score[j]=_c0; + best_ener[j]=_e0; + pitch[j]=i; + break; + } + } + } + + if ( (_c1 * best_ener[N-1]) > (best_score[N-1] * _e1) ) + { + best_score[N-1] = _c1; + best_ener[N-1] = _e1; + pitch[N-1] = i+1; + + for( j=0 ; j best_score[j] * _e1 ) + { for( k=N-1 ; k>j ; --k ) + { + best_score[k]=best_score[k-1]; + best_ener[k]=best_ener[k-1]; + pitch[k]=pitch[k-1]; + } + + best_score[j]=_c1; + best_ener[j]=_e1; + pitch[j]=i+1; + break; + } + } + } + } + + /* Compute open-loop gain if necessary */ + if (gain) + { + for (j=0;j + + +#if TM_PROFILE +int __profile_begin; +int __profile_end; +#endif + +#define OVERRIDE_SPEEX_ALLOC +void *speex_alloc (int size) +{ + void *ptr; + + if ( tmmlMalloc(0, size, (pVoid*)&ptr, tmmlMallocCacheAligned | tmmlMallocCleared) != TM_OK ) + { return NULL; + } + + return ptr; +} + + +#define OVERRIDE_SPEEX_ALLOC_SCRATCH +void *speex_alloc_scratch (int size) +{ + void *ptr; + + if ( tmmlMalloc(0, size, (pVoid*)&ptr, tmmlMallocCacheAligned | tmmlMallocCleared) != TM_OK ) + { return NULL; + } + + return ptr; +} + + +#define OVERRIDE_SPEEX_REALLOC +void *speex_realloc (void *ptr, int size) +{ + if ( tmmlRealloc(0, size, (pVoid)ptr, (pVoid*)&ptr, tmmlMallocCacheAligned | tmmlMallocCleared) != TM_OK ) + { return NULL; + } + + return ptr; +} + + +#define OVERRIDE_SPEEX_FREE +void speex_free (void *ptr) +{ + tmmlFree(ptr); +} + + +#define OVERRIDE_SPEEX_FREE_SCRATCH +void speex_free_scratch (void *ptr) +{ + tmmlFree(ptr); +} + diff --git a/native/codec/libraries/speex/tmv/profile_tm.h b/native/codec/libraries/speex/tmv/profile_tm.h new file mode 100644 index 0000000..2ecafb7 --- /dev/null +++ b/native/codec/libraries/speex/tmv/profile_tm.h @@ -0,0 +1,407 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file profile_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/** +* @remarks This file provide some capabilities to measure clock cycles. +* Use this if unable to compile with TriMedia profile options +*/ + +extern int __profile_begin; +extern int __profile_end; + +#if TM_PROFILE +#define PROFILE_START() \ + { \ + __profile_begin = cycles(); \ + } \ + +#define PROFILE_STOP() \ + { \ + __profile_end = cycles(); \ + printf("%s\t%d\n", __FUNCTION__, end - begin); \ + } \ + +#else +#define PROFILE_START() +#define PROFILE_STOP() +#endif + +#if TM_PROFILE_SPXAUTOCORR +#define _SPX_AUTOCORR_START() PROFILE_START() +#define _SPX_AUTOCORR_STOP() PROFILE_STOP() +#else +#define _SPX_AUTOCORR_START() +#define _SPX_AUTOCORR_STOP() +#endif + +#if TM_PROFILE_INNERPROD +#define INNERPROD_START() PROFILE_START() +#define INNERPROD_STOP() PROFILE_STOP() +#else +#define INNERPROD_START() +#define INNERPROD_STOP() +#endif + +#if TM_PROFILE_PITCHXCORR +#define PITCHXCORR_START() PROFILE_START() +#define PITCHXCORR_STOP() PROFILE_STOP() +#else +#define PITCHXCORR_START() +#define PITCHXCORR_STOP() +#endif + +#if TM_PROFILE_COMPUTEPITCHERROR +#define COMPUTEPITCHERROR_START() PROFILE_START() +#define COMPUTEPITCHERROR_STOP() PROFILE_STOP() +#else +#define COMPUTEPITCHERROR_START() +#define COMPUTEPITCHERROR_STOP() +#endif + +#if TM_PROFILE_PITCHGAINSEARCH3TAPVQ +#define PITCHGAINSEARCH3TAPVQ_START() PROFILE_START() +#define PITCHGAINSEARCH3TAPVQ_STOP() PROFILE_STOP() +#else +#define PITCHGAINSEARCH3TAPVQ_START() +#define PITCHGAINSEARCH3TAPVQ_STOP() +#endif + +#if TM_PROFILE_OPENLOOPNBESTPITCH +#define OPENLOOPNBESTPITCH_START() PROFILE_START() +#define OPENLOOPNBESTPITCH_STOP() PROFILE_STOP() +#else +#define OPENLOOPNBESTPITCH_START() +#define OPENLOOPNBESTPITCH_STOP() +#endif + + +#if TM_PROFILE_LSP_INTERPOLATE +#define LSPINTERPOLATE_START() PROFILE_START() +#define LSPINTERPOLATE_STOP() PROFILE_STOP() +#else +#define LSPINTERPOLATE_START() +#define LSPINTERPOLATE_STOP() +#endif + +#if TM_PROFILE_CHEBPOLYEVA +#define CHEBPOLYEVA_START() PROFILE_START() +#define CHEBPOLYEVA_STOP() PROFILE_STOP() +#else +#define CHEBPOLYEVA_START() +#define CHEBPOLYEVA_STOP() +#endif + + +#if TM_PROFILE_COMPUTEQUANTWEIGHTS +#define COMPUTEQUANTWEIGHTS_START() PROFILE_START() +#define COMPUTEQUANTWEIGHTS_STOP() PROFILE_STOP() +#else +#define COMPUTEQUANTWEIGHTS_START() +#define COMPUTEQUANTWEIGHTS_STOP() +#endif + +#if TM_PROFILE_LSPQUANT +#define LSPQUANT_START() PROFILE_START() +#define LSPQUANT_STOP() PROFILE_STOP() +#else +#define LSPQUANT_START() +#define LSPQUANT_STOP() +#endif + +#if TM_PROFILE_LSPWEIGHTQUANT +#define LSPWEIGHTQUANT_START() PROFILE_START() +#define LSPWEIGHTQUANT_STOP() PROFILE_STOP() +#else +#define LSPWEIGHTQUANT_START() +#define LSPWEIGHTQUANT_STOP() +#endif + +#if TM_PROFILE_FIRMEM16 +#define FIRMEM16_START() PROFILE_START() +#define FIRMEM16_STOP() PROFILE_STOP() +#else +#define FIRMEM16_START() +#define FIRMEM16_STOP() +#endif + +#if TM_PROFILE_IIRMEM16 +#define IIRMEM16_START() PROFILE_START() +#define IIRMEM16_STOP() PROFILE_STOP() +#else +#define IIRMEM16_START() +#define IIRMEM16_STOP() +#endif + +#if TM_PROFILE_FILTERMEM16 +#define FILTERMEM16_START() PROFILE_START() +#define FILTERMEM16_STOP() PROFILE_STOP() +#else +#define FILTERMEM16_START() +#define FILTERMEM16_STOP() +#endif + +#if TM_PROFILE_COMPUTERMS16 +#define COMPUTERMS16_START() PROFILE_START() +#define COMPUTERMS16_STOP() PROFILE_STOP() +#else +#define COMPUTERMS16_START() +#define COMPUTERMS16_STOP() +#endif + +#if TM_PROFILE_NORMALIZE16 +#define NORMALIZE16_START() PROFILE_START() +#define NORMALIZE16_STOP() PROFILE_STOP() +#else +#define NORMALIZE16_START() +#define NORMALIZE16_STOP() +#endif + +#if TM_PROFILE_BWLPC +#define BWLPC_START() PROFILE_START() +#define BWLPC_STOP() PROFILE_STOP() +#else +#define BWLPC_START() +#define BWLPC_STOP() +#endif + +#if TM_PROFILE_HIGHPASS +#define HIGHPASS_START() PROFILE_START() +#define HIGHPASS_STOP() PROFILE_STOP() +#else +#define HIGHPASS_START() +#define HIGHPASS_STOP() +#endif + +#if TM_PROFILE_SIGNALMUL +#define SIGNALMUL_START() PROFILE_START() +#define SIGNALMUL_STOP() PROFILE_STOP() +#else +#define SIGNALMUL_START() +#define SIGNALMUL_STOP() +#endif + +#if TM_PROFILE_SIGNALDIV +#define SIGNALDIV_START() PROFILE_START() +#define SIGNALDIV_STOP() PROFILE_STOP() +#else +#define SIGNALDIV_START() +#define SIGNALDIV_STOP() +#endif + +#if TM_PROFILE_COMPUTEIMPULSERESPONSE +#define COMPUTEIMPULSERESPONSE_START() PROFILE_START() +#define COMPUTEIMPULSERESPONSE_STOP() PROFILE_STOP() +#else +#define COMPUTEIMPULSERESPONSE_START() +#define COMPUTEIMPULSERESPONSE_STOP() +#endif + +#if TM_PROFILE_COMPUTEWEIGHTEDCODEBOOK +#define COMPUTEWEIGHTEDCODEBOOK_START() PROFILE_START() +#define COMPUTEWEIGHTEDCODEBOOK_STOP() PROFILE_STOP() +#else +#define COMPUTEWEIGHTEDCODEBOOK_START() +#define COMPUTEWEIGHTEDCODEBOOK_STOP() +#endif + +#if TM_PROFILE_TARGETUPDATE +#define TARGETUPDATE_START() PROFILE_START() +#define TARGETUPDATE_STOP() PROFILE_STOP() +#else +#define TARGETUPDATE_START() +#define TARGETUPDATE_STOP() +#endif + + +#if TM_PROFILE_VQNBEST +#define VQNBEST_START() PROFILE_START() +#define VQNBEST_STOP() PROFILE_STOP() +#else +#define VQNBEST_START() +#define VQNBEST_STOP() +#endif + +#if TM_PROFILE_VQNBESTSIGN +#define VQNBESTSIGN_START() PROFILE_START() +#define VQNBESTSIGN_STOP() PROFILE_STOP() +#else +#define VQNBESTSIGN_START() +#define VQNBESTSIGN_STOP() +#endif + +#if TM_PROFILE_PREPROCESSANALYSIS +#define PREPROCESSANAYLSIS_START() PROFILE_START() +#define PREPROCESSANAYLSIS_STOP() PROFILE_STOP() +#else +#define PREPROCESSANAYLSIS_START() +#define PREPROCESSANAYLSIS_STOP() +#endif + +#if TM_PROFILE_UPDATENOISEPROB +#define UPDATENOISEPROB_START() PROFILE_START() +#define UPDATENOISEPROB_STOP() PROFILE_STOP() +#else +#define UPDATENOISEPROB_START() +#define UPDATENOISEPROB_STOP() +#endif + +#if TM_PROFILE_COMPUTEGAINFLOOR +#define COMPUTEGAINFLOOR_START() PROFILE_START() +#define COMPUTEGAINFLOOR_STOP() PROFILE_STOP() +#else +#define COMPUTEGAINFLOOR_START() +#define COMPUTEGAINFLOOR_STOP() +#endif + +#if TM_PROFILE_FILTERDCNOTCH16 +#define FILTERDCNOTCH16_START() PROFILE_START() +#define FILTERDCNOTCH16_STOP() PROFILE_STOP() +#else +#define FILTERDCNOTCH16_START() +#define FILTERDCNOTCH16_STOP() +#endif + +#if TM_PROFILE_MDFINNERPROD +#define MDFINNERPROD_START() PROFILE_START() +#define MDFINNERPROD_STOP() PROFILE_STOP() +#else +#define MDFINNERPROD_START() +#define MDFINNERPROD_STOP() +#endif + +#if TM_PROFILE_SPECTRALMULACCUM +#define SPECTRALMULACCUM_START() PROFILE_START() +#define SPECTRALMULACCUM_STOP() PROFILE_STOP() +#else +#define SPECTRALMULACCUM_START() +#define SPECTRALMULACCUM_STOP() +#endif + +#if TM_PROFILE_WEIGHTEDSPECTRALMULCONJ +#define WEIGHTEDSPECTRALMULCONJ_START() PROFILE_START() +#define WEIGHTEDSPECTRALMULCONJ_STOP() PROFILE_STOP() +#else +#define WEIGHTEDSPECTRALMULCONJ_START() +#define WEIGHTEDSPECTRALMULCONJ_STOP() +#endif + +#if TM_PROFILE_MDFADJUSTPROP +#define MDFADJUSTPROP_START() PROFILE_START() +#define MDFADJUSTPROP_STOP() PROFILE_STOP() +#else +#define MDFADJUSTPROP_START() +#define MDFADJUSTPROP_STOP() +#endif + +#if TM_PROFILE_SPEEXECHOGETRESIDUAL +#define SPEEXECHOGETRESIDUAL_START() PROFILE_START() +#define SPEEXECHOGETRESIDUAL_STOP() PROFILE_STOP() +#else +#define SPEEXECHOGETRESIDUAL_START() +#define SPEEXECHOGETRESIDUAL_STOP() +#endif + +#if TM_PROFILE_LSPENFORCEMARGIN +#define LSPENFORCEMARGIN_START() PROFILE_START() +#define LSPENFORCEMARGIN_STOP() PROFILE_STOP() +#else +#define LSPENFORCEMARGIN_START() +#define LSPENFORCEMARGIN_STOP() +#endif + +#if TM_PROFILE_LSPTOLPC +#define LSPTOLPC_START() PROFILE_START() +#define LSPTOLPC_STOP() PROFILE_STOP() +#else +#define LSPTOLPC_START() +#define LSPTOLPC_STOP() +#endif + +#if TM_PROFILE_MAXIMIZERANGE +#define MAXIMIZERANGE_START() PROFILE_START() +#define MAXIMIZERANGE_STOP() PROFILE_STOP() +#else +#define MAXIMIZERANGE_START() +#define MAXIMIZERANGE_STOP() +#endif + +#if TM_PROFILE_RENORMRANGE +#define RENORMRANGE_START() PROFILE_START() +#define RENORMRANGE_STOP() PROFILE_STOP() +#else +#define RENORMRANGE_START() +#define RENORMRANGE_STOP() +#endif + +#if TM_PROFILE_POWERSPECTRUM +#define POWERSPECTRUM_START() PROFILE_START() +#define POWERSPECTRUM_STOP() PROFILE_STOP() +#else +#define POWERSPECTRUM_START() +#define POWERSPECTRUM_STOP() +#endif + +#if TM_PROFILE_QMFSYNTH +#define QMFSYNTH_START() PROFILE_START() +#define QMFSYNTH_STOP() PROFILE_STOP() +#else +#define QMFSYNTH_START() +#define QMFSYNTH_STOP() +#endif + +#if TM_PROFILE_QMFDECOMP +#define QMFDECOMP_START() PROFILE_START() +#define QMFDECOMP_STOP() PROFILE_STOP() +#else +#define QMFDECOMP_START() +#define QMFDECOMP_STOP() +#endif + +#if TM_PROFILE_FILTERBANKCOMPUTEBANK32 +#define FILTERBANKCOMPUTEBANK32_START() PROFILE_START() +#define FILTERBANKCOMPUTEBANK32_STOP() PROFILE_STOP() +#else +#define FILTERBANKCOMPUTEBANK32_START() +#define FILTERBANKCOMPUTEBANK32_STOP() +#endif + +#if TM_PROFILE_FILTERBANKCOMPUTEPSD16 +#define FILTERBANKCOMPUTEPSD16_START() PROFILE_START() +#define FILTERBANKCOMPUTEPSD16_STOP() PROFILE_STOP() +#else +#define FILTERBANKCOMPUTEPSD16_START() +#define FILTERBANKCOMPUTEPSD16_STOP() +#endif + + diff --git a/native/codec/libraries/speex/tmv/quant_lsp_tm.h b/native/codec/libraries/speex/tmv/quant_lsp_tm.h new file mode 100644 index 0000000..9f49fca --- /dev/null +++ b/native/codec/libraries/speex/tmv/quant_lsp_tm.h @@ -0,0 +1,448 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file quant_lsp_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include "profile_tm.h" + +#ifdef FIXED_POINT + +#define OVERRIDE_COMPUTE_QUANT_WEIGHTS +static void compute_quant_weights(Int16 *qlsp, Int16 *qw, int order) +{ + int qlspi, qlspii; + int w1, w2; + int i; + + TMDEBUG_ALIGNMEM(qlsp); + TMDEBUG_ALIGNMEM(qw); + + COMPUTEQUANTWEIGHTS_START(); + + --order; + + qlspi = (int)qlsp[0]; + qlspii = (int)qlsp[1]; + w1 = qlspi; + w2 = qlspii - qlspi; + + qw[0] = 81920 / (300 + imin(w1,w2)); + + for ( i=1 ; i>1); + cb0 = pack16lsb((int)ptr[1], (int)ptr[0]); + cb0 = dualasl(cb0,five); + cb0 = dspidualsub(xx,cb0); + dt0 += ifir16(cb0,cb0); + + cb1 = pack16lsb((int)ptr[nbDim+1], (int)ptr[nbDim]); + cb1 = dualasl(cb1,five); + cb1 = dspidualsub(xx,cb1); + dt1 += ifir16(cb1, cb1); + + cb2 = pack16lsb((int)ptr[nbDim*2+1], (int)ptr[nbDim*2]); + cb2 = dualasl(cb2,five); + cb2 = dspidualsub(xx,cb2); + dt2 += ifir16(cb2, cb2); + + cb3 = pack16lsb((int)ptr[nbDim*3+1], (int)ptr[nbDim*3]); + cb3 = dualasl(cb3,five); + cb3 = dspidualsub(xx,cb3); + dt3 += ifir16(cb3, cb3); + + ptr += 2; + } + + if ( dt0>1); + cb0 = pack16lsb((int)ptr[j+1], (int)ptr[j]); + cb0 = dualasl(cb0,five); + dt0 = dspidualsub(xx,cb0); + st32d(j<<1, x, dt0); + } + + LSPQUANT_STOP(); + return best_id; +} + + +#define OVERRIDE_LSP_WEIGHT_QUANT +static int lsp_weight_quant(Int16 *x, Int16 *weight, const signed char *cdbk, int nbVec, int nbDim) +{ + register int best_dist=VERY_LARGE32; + register int best_id=0; + register int i, j; + register int dt1, dt2, dt3, dt4; + register int cb1, cb2, cb3, cb4, wt, xx; + register int ptr_inc = nbDim * 3; + const signed char *ptr; + + LSPWEIGHTQUANT_START(); + + for ( i=0, ptr=cdbk ; i> 15)) + ((wt * (cb1 & 0x7fff)) >> 15); + dt2 += (wt * (cb2 >> 15)) + ((wt * (cb2 & 0x7fff)) >> 15); + dt3 += (wt * (cb3 >> 15)) + ((wt * (cb3 & 0x7fff)) >> 15); + dt4 += (wt * (cb4 >> 15)) + ((wt * (cb4 & 0x7fff)) >> 15); + + } + + if ( dt1 tmp2 ? tmp1 : tmp2; + }*/ + + for (i=0;i + + + +typedef Int16 spx_int16_t; +typedef UInt16 spx_uint16_t; +typedef Int32 spx_int32_t; +typedef UInt32 spx_uint32_t; + +#ifdef FIXED_POINT +#define VMUX(a,b,c) mux((a),(b),(c)) +#define VABS(a) iabs((a)) +#define VMAX(a,b) imax((a),(b)) +#define VMIN(a,b) imin((a),(b)) +#else +#define VMUX(a,b,c) fmux((a),(b),(c)) +#define VABS(a) fabs((a)) +#define VMAX(a,b) fmax((a),(b)) +#define VMIN(a,b) fmin((a),(b)) +#endif + +#endif + + +#endif + diff --git a/native/codec/libraries/speex/tmv/vq_tm.h b/native/codec/libraries/speex/tmv/vq_tm.h new file mode 100644 index 0000000..4f0e886 --- /dev/null +++ b/native/codec/libraries/speex/tmv/vq_tm.h @@ -0,0 +1,494 @@ +/* Copyright (C) 2007 Hong Zhiqian */ +/** + @file vq_tm.h + @author Hong Zhiqian + @brief Various compatibility routines for Speex (TriMedia version) +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include "profile_tm.h" + +#ifdef FIXED_POINT + +inline void vq_nbest_dist(int i, int N, int dist, int *used, int *nbest, Int32 *best_dist) +{ + register int k; + + if (i= 1) && (k > *used || dist < best_dist[k-1]); k--) + { best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + + best_dist[k]=dist; + nbest[k]=i; + *used++; + } +} + +void vq_nbest_5(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist) +{ + register int i, j; + register int in10, in32, in4; + int used = 0; + + in10 = pack16lsb(in[1],in[0]); /* Note: memory is not align here */ + in32 = pack16lsb(in[3],in[2]); + in4 = sex16(in[4]); + +#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + + for ( i=0,j=0 ; i> 1) - dist1; + + cb65 = funshift2(cb76,cb54); + cb87 = funshift2(cb98,cb76); + dist2 = asri(16,cb98) * in4; + dist2 += ifir16(in10,cb65) + ifir16(in32,cb87); + dist2 = (E[i+1] >> 1) - dist2; + + vq_nbest_dist(i,N,dist1,&used,nbest,best_dist); + vq_nbest_dist(i+1,N,dist2,&used,nbest,best_dist); + } + +#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + + +void vq_nbest_8(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist) +{ + register int i, j; + register int in10, in32, in54, in76; + int used = 0; + + in10 = pack16lsb(in[1],in[0]); /* Note: memory is not align here */ + in32 = pack16lsb(in[3],in[2]); + in54 = pack16lsb(in[5],in[4]); + in76 = pack16lsb(in[7],in[6]); + +#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0,j=0 ; i> 1) - dist; + + vq_nbest_dist(i,N,dist,&used,nbest,best_dist); + } +#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif + +} + + +void vq_nbest_10(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist) +{ + register int i, j; + register int in10, in32, in54, in76, in98; + int used = 0; + + in10 = pack16lsb(in[1],in[0]); + in32 = pack16lsb(in[3],in[2]); + in54 = pack16lsb(in[5],in[4]); + in76 = pack16lsb(in[7],in[6]); + in98 = pack16lsb(in[9],in[8]); + +#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0,j=0 ; i> 1) - dist; + + vq_nbest_dist(i,N,dist,&used,nbest,best_dist); + } +#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + +void vq_nbest_20(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist) +{ + register int i, j; + register int in10, in32, in54, in76, in98, in_10, in_32, in_54, in_76, in_98; + int used = 0; + + in10 = pack16lsb(in[1],in[0]); /* Note: memory is not align here */ + in32 = pack16lsb(in[3],in[2]); + in54 = pack16lsb(in[5],in[4]); + in76 = pack16lsb(in[6],in[6]); + in98 = pack16lsb(in[9],in[8]); + in_10 = pack16lsb(in[11],in[10]); + in_32 = pack16lsb(in[13],in[12]); + in_54 = pack16lsb(in[15],in[14]); + in_76 = pack16lsb(in[17],in[16]); + in_98 = pack16lsb(in[19],in[18]); + +#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0,j=0 ; i> 1) - dist; + vq_nbest_dist(i,N,dist,&used,nbest,best_dist); + } +#if (TM_UNROLL && TM_UNROLL_VQNBEST > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + + +#define OVERRIDE_VQ_NBEST +void vq_nbest (Int16 *in, const Int16 *codebook, int len, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist, char *stack) +{ + TMDEBUG_ALIGNMEM(codebook); + + VQNBEST_START(); + if( len==5 ) + vq_nbest_5(in,codebook,entries,E,N,nbest,best_dist); + else if ( len==8 ) + vq_nbest_8(in,codebook,entries,E,N,nbest,best_dist); + else if ( len==10 ) + vq_nbest_10(in,codebook,entries,E,N,nbest,best_dist); + else if ( len==20 ) + vq_nbest_20(in,codebook,entries,E,N,nbest,best_dist); + +#ifndef REMARK_ON + (void)stack; +#endif + + VQNBEST_STOP(); +} + +inline void vq_nbest_sign_dist(int i, int N, int dist, int sign, int entries, int *used, int *nbest, Int32 *best_dist) +{ + register int k; + + if (i= 1) && (k > *used || dist < best_dist[k-1]); k--) + { + best_dist[k]=best_dist[k-1]; + nbest[k] = nbest[k-1]; + } + + if ( sign ) i += entries; + best_dist[k]=dist; + *used++; + nbest[k] = i; + } +} + +void vq_nbest_sign_5(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist) +{ + register int i, j; + register int in10, in32, in4; + int used = 0; + + in10 = ld32(in); + in32 = ld32x(in,1); + in4 = sex16(in[4]); + +#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + + for ( i=0,j=0 ; i0,0,1); + dist1 = iflip(dist1>0,dist1); + dist1 = (E[i] >> 1) + dist1; + + cb65 = funshift2(cb76,cb54); + cb87 = funshift2(cb98,cb76); + dist2 = asri(16,cb98) * in4; + dist2 += ifir16(in10,cb65) + ifir16(in32,cb87); + + sign2 = mux(dist2>0,0,1); + dist2 = iflip(dist2>0,dist2); + dist2 = (E[i] >> 1) + dist2; + + vq_nbest_sign_dist(i,N,dist1,sign1,entries,&used,nbest,best_dist); + vq_nbest_sign_dist(i+1,N,dist2,sign2,entries,&used,nbest,best_dist); + } +#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + +void vq_nbest_sign_8(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist) +{ + register int i, j; + register int sign; + register int in10, in32, in54, in76; + int used = 0; + + in10 = ld32(in); + in32 = ld32x(in,1); + in54 = ld32x(in,2); + in76 = ld32x(in,3); + +#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + + for ( i=0,j=0 ; i0,0,1); + dist = iflip(dist>0,dist); + dist = (E[i] >> 1) + dist; + + vq_nbest_sign_dist(i,N,dist,sign,entries,&used,nbest,best_dist); + } +#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + +void vq_nbest_sign_10(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist) +{ + register int i, j; + register int sign; + register int in10, in32, in54, in76, in98; + int used = 0; + + in10 = ld32(in); + in32 = ld32x(in,1); + in54 = ld32x(in,2); + in76 = ld32x(in,3); + in98 = ld32x(in,4); + +#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0) +#pragma TCS_unroll=4 +#pragma TCS_unrollexact=1 +#endif + for ( i=0,j=0 ; i0,0,1); + dist = iflip(dist>0,dist); + dist = (E[i] >> 1) + dist; + + vq_nbest_sign_dist(i,N,dist,sign,entries,&used,nbest,best_dist); + } +#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + +void vq_nbest_sign_20(Int16 *in, const Int16 *codebook, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist) +{ + register int i, j; + register int sign; + register int in10, in32, in54, in76, in98, in_10, in_32, in_54, in_76, in_98; + int used = 0; + + in10 = ld32(in); + in32 = ld32x(in,1); + in54 = ld32x(in,2); + in76 = ld32x(in,3); + in98 = ld32x(in,4); + in_10 = ld32x(in,5); + in_32 = ld32x(in,6); + in_54 = ld32x(in,7); + in_76 = ld32x(in,8); + in_98 = ld32x(in,9); + +#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0) +#pragma TCS_unroll=2 +#pragma TCS_unrollexact=1 +#endif + for ( i=0,j=0 ; i0,0,1); + dist = iflip(dist>0,dist); + dist = (E[i] >> 1) + dist; + + vq_nbest_sign_dist(i,N,dist,sign,entries,&used,nbest,best_dist); + } +#if (TM_UNROLL && TM_UNROLL_VQSIGNNBEST > 0) +#pragma TCS_unrollexact=0 +#pragma TCS_unroll=0 +#endif +} + +#define OVERRIDE_VQ_NBEST_SIGN +void vq_nbest_sign (Int16 *in, const Int16 *codebook, int len, int entries, Int32 *E, int N, int *nbest, Int32 *best_dist, char *stack) +{ + TMDEBUG_ALIGNMEM(in); + TMDEBUG_ALIGNMEM(codebook); + + VQNBESTSIGN_START(); + + if( len==5 ) + vq_nbest_sign_5(in,codebook,entries,E,N,nbest,best_dist); + else if ( len==8 ) + vq_nbest_sign_8(in,codebook,entries,E,N,nbest,best_dist); + else if ( len==10 ) + vq_nbest_sign_10(in,codebook,entries,E,N,nbest,best_dist); + else if ( len==20 ) + vq_nbest_sign_20(in,codebook,entries,E,N,nbest,best_dist); + +#ifndef REMARK_ON + (void)stack; +#endif + + VQNBESTSIGN_STOP(); +} + +#endif + diff --git a/native/codec/libraries/speex/win32/Makefile.am b/native/codec/libraries/speex/win32/Makefile.am new file mode 100644 index 0000000..fa96e49 --- /dev/null +++ b/native/codec/libraries/speex/win32/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +SUBDIRS = libspeex speexenc speexdec VS2003 VS2005 VS2008 + +EXTRA_DIST = speex.iss config.h libspeex.def diff --git a/native/codec/libraries/speex/win32/VS2003/Makefile.am b/native/codec/libraries/speex/win32/VS2003/Makefile.am new file mode 100644 index 0000000..bdec96f --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +SUBDIRS = libspeex speexenc speexdec tests + +EXTRA_DIST = libspeex.sln diff --git a/native/codec/libraries/speex/win32/VS2003/libspeex.sln b/native/codec/libraries/speex/win32/VS2003/libspeex.sln new file mode 100644 index 0000000..c309f27 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/libspeex.sln @@ -0,0 +1,146 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libspeex\libspeex.vcproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdec", "speexdec\speexdec.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexenc", "speexenc\speexenc.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testdenoise", "tests\testdenoise.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testecho", "tests\testecho.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc", "tests\testenc.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc_uwb", "tests\testenc_uwb.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc_wb", "tests\testenc_wb.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testresample", "tests\testresample.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeexdsp", "libspeexdsp\libspeexdsp.vcproj", "{03207781-0D1C-4DB3-A71D-45C608F28DBD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + Release_Dynamic_SSE = Release_Dynamic_SSE + Release_Static_SSE = Release_Static_SSE + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug.ActiveCfg = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug.Build.0 = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release.ActiveCfg = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release.Build.0 = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE.ActiveCfg = Release_Dynamic_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE.Build.0 = Release_Dynamic_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE.ActiveCfg = Release_Static_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE.Build.0 = Release_Static_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE.Build.0 = Release_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug.ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug.Build.0 = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release.Build.0 = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic_SSE.ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic_SSE.Build.0 = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Static_SSE.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Static_SSE.Build.0 = Release_Static_SSE|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/native/codec/libraries/speex/win32/VS2003/libspeex/Makefile.am b/native/codec/libraries/speex/win32/VS2003/libspeex/Makefile.am new file mode 100644 index 0000000..1ab1201 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/libspeex/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = libspeex.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2003/libspeex/libspeex.vcproj b/native/codec/libraries/speex/win32/VS2003/libspeex/libspeex.vcproj new file mode 100644 index 0000000..f940bd9 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/libspeex/libspeex.vcproj @@ -0,0 +1,421 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2003/speexdec/Makefile.am b/native/codec/libraries/speex/win32/VS2003/speexdec/Makefile.am new file mode 100644 index 0000000..c32b355 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/speexdec/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexdec.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2003/speexdec/speexdec.vcproj b/native/codec/libraries/speex/win32/VS2003/speexdec/speexdec.vcproj new file mode 100644 index 0000000..c27dc71 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/speexdec/speexdec.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2003/speexenc/Makefile.am b/native/codec/libraries/speex/win32/VS2003/speexenc/Makefile.am new file mode 100644 index 0000000..13530a7 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/speexenc/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexenc.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2003/speexenc/speexenc.vcproj b/native/codec/libraries/speex/win32/VS2003/speexenc/speexenc.vcproj new file mode 100644 index 0000000..a591621 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/speexenc/speexenc.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2003/tests/Makefile.am b/native/codec/libraries/speex/win32/VS2003/tests/Makefile.am new file mode 100644 index 0000000..b44ac43 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/tests/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = testenc.vcproj testenc_uwb.vcproj testenc_wb.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2003/tests/testenc.vcproj b/native/codec/libraries/speex/win32/VS2003/tests/testenc.vcproj new file mode 100644 index 0000000..5e4c9d1 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/tests/testenc.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2003/tests/testenc_uwb.vcproj b/native/codec/libraries/speex/win32/VS2003/tests/testenc_uwb.vcproj new file mode 100644 index 0000000..5d46551 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/tests/testenc_uwb.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2003/tests/testenc_wb.vcproj b/native/codec/libraries/speex/win32/VS2003/tests/testenc_wb.vcproj new file mode 100644 index 0000000..9501d8c --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2003/tests/testenc_wb.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2005/Makefile.am b/native/codec/libraries/speex/win32/VS2005/Makefile.am new file mode 100644 index 0000000..bdec96f --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +SUBDIRS = libspeex speexenc speexdec tests + +EXTRA_DIST = libspeex.sln diff --git a/native/codec/libraries/speex/win32/VS2005/libspeex.sln b/native/codec/libraries/speex/win32/VS2005/libspeex.sln new file mode 100644 index 0000000..c3668fb --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/libspeex.sln @@ -0,0 +1,259 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libspeex\libspeex.vcproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeexdsp", "libspeexdsp\libspeexdsp.vcproj", "{E42FDC95-7243-4219-9EA4-ACCE4AB97197}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdec", "speexdec\speexdec.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexenc", "speexenc\speexenc.vcproj", "{CD6043D1-D5E7-46D0-854F-00BB1BC308FC}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + {E42FDC95-7243-4219-9EA4-ACCE4AB97197} = {E42FDC95-7243-4219-9EA4-ACCE4AB97197} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testdenoise", "tests\testdenoise.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}" + ProjectSection(ProjectDependencies) = postProject + {E42FDC95-7243-4219-9EA4-ACCE4AB97197} = {E42FDC95-7243-4219-9EA4-ACCE4AB97197} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testecho", "tests\testecho.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}" + ProjectSection(ProjectDependencies) = postProject + {E42FDC95-7243-4219-9EA4-ACCE4AB97197} = {E42FDC95-7243-4219-9EA4-ACCE4AB97197} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc", "tests\testenc.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc_uwb", "tests\testenc_uwb.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc_wb", "tests\testenc_wb.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testresample", "tests\testresample.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}" + ProjectSection(ProjectDependencies) = postProject + {E42FDC95-7243-4219-9EA4-ACCE4AB97197} = {E42FDC95-7243-4219-9EA4-ACCE4AB97197} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_RTL_dll|Win32 = Debug_RTL_dll|Win32 + Debug_WM5_PPC_ARM|Win32 = Debug_WM5_PPC_ARM|Win32 + Debug|Win32 = Debug|Win32 + Release_Dynamic_SSE|Win32 = Release_Dynamic_SSE|Win32 + Release_Dynamic|Win32 = Release_Dynamic|Win32 + Release_RTL_dll|Win32 = Release_RTL_dll|Win32 + Release_SSE|Win32 = Release_SSE|Win32 + Release_SSE2|Win32 = Release_SSE2|Win32 + Release_WM5_PPC_ARM|Win32 = Release_WM5_PPC_ARM|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Win32.ActiveCfg = Debug_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Win32.Build.0 = Debug_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.ActiveCfg = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.Build.0 = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_Dynamic_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Win32.Build.0 = Release_Dynamic_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Win32.ActiveCfg = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Win32.Build.0 = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Win32.ActiveCfg = Release_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Win32.Build.0 = Release_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Win32.ActiveCfg = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Win32.Build.0 = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.ActiveCfg = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.Build.0 = Release|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Debug_RTL_dll|Win32.ActiveCfg = Debug_RTL_dll|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Debug_RTL_dll|Win32.Build.0 = Debug_RTL_dll|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug_WM5_PPC_ARM|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug_WM5_PPC_ARM|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Debug|Win32.ActiveCfg = Debug|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Debug|Win32.Build.0 = Debug|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_Dynamic_SSE|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_Dynamic_SSE|Win32.Build.0 = Release_Dynamic_SSE|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_Dynamic|Win32.ActiveCfg = Release_Dynamic|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_Dynamic|Win32.Build.0 = Release_Dynamic|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_RTL_dll|Win32.ActiveCfg = Release_RTL_dll|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_RTL_dll|Win32.Build.0 = Release_RTL_dll|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_SSE2|Win32.ActiveCfg = Release_SSE2|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_SSE2|Win32.Build.0 = Release_SSE2|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release_WM5_PPC_ARM|Win32.Build.0 = Release|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release|Win32.ActiveCfg = Release|Win32 + {E42FDC95-7243-4219-9EA4-ACCE4AB97197}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Win32.Build.0 = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug|Win32.Build.0 = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|Win32.ActiveCfg = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|Win32.Build.0 = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|Win32.ActiveCfg = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|Win32.Build.0 = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release|Win32.ActiveCfg = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native/codec/libraries/speex/win32/VS2005/libspeex/Makefile.am b/native/codec/libraries/speex/win32/VS2005/libspeex/Makefile.am new file mode 100644 index 0000000..1ab1201 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/libspeex/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = libspeex.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2005/libspeex/libspeex.vcproj b/native/codec/libraries/speex/win32/VS2005/libspeex/libspeex.vcproj new file mode 100644 index 0000000..4629353 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/libspeex/libspeex.vcproj @@ -0,0 +1,1732 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2005/speexdec/Makefile.am b/native/codec/libraries/speex/win32/VS2005/speexdec/Makefile.am new file mode 100644 index 0000000..c32b355 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/speexdec/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexdec.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2005/speexdec/speexdec.vcproj b/native/codec/libraries/speex/win32/VS2005/speexdec/speexdec.vcproj new file mode 100644 index 0000000..fd162ff --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/speexdec/speexdec.vcproj @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2005/speexenc/Makefile.am b/native/codec/libraries/speex/win32/VS2005/speexenc/Makefile.am new file mode 100644 index 0000000..13530a7 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/speexenc/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexenc.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2005/speexenc/speexenc.vcproj b/native/codec/libraries/speex/win32/VS2005/speexenc/speexenc.vcproj new file mode 100644 index 0000000..287a6b9 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/speexenc/speexenc.vcproj @@ -0,0 +1,347 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2005/tests/Makefile.am b/native/codec/libraries/speex/win32/VS2005/tests/Makefile.am new file mode 100644 index 0000000..b44ac43 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/tests/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = testenc.vcproj testenc_uwb.vcproj testenc_wb.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2005/tests/testenc.vcproj b/native/codec/libraries/speex/win32/VS2005/tests/testenc.vcproj new file mode 100644 index 0000000..575ab86 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/tests/testenc.vcproj @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2005/tests/testenc_uwb.vcproj b/native/codec/libraries/speex/win32/VS2005/tests/testenc_uwb.vcproj new file mode 100644 index 0000000..83e1b48 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/tests/testenc_uwb.vcproj @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2005/tests/testenc_wb.vcproj b/native/codec/libraries/speex/win32/VS2005/tests/testenc_wb.vcproj new file mode 100644 index 0000000..45ce288 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2005/tests/testenc_wb.vcproj @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2008/Makefile.am b/native/codec/libraries/speex/win32/VS2008/Makefile.am new file mode 100644 index 0000000..bdec96f --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +SUBDIRS = libspeex speexenc speexdec tests + +EXTRA_DIST = libspeex.sln diff --git a/native/codec/libraries/speex/win32/VS2008/libspeex.sln b/native/codec/libraries/speex/win32/VS2008/libspeex.sln new file mode 100644 index 0000000..399a927 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/libspeex.sln @@ -0,0 +1,439 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libspeex\libspeex.vcproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdec", "speexdec\speexdec.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexenc", "speexenc\speexenc.vcproj", "{CD6043D1-D5E7-46D0-854F-00BB1BC308FC}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testdenoise", "tests\testdenoise.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testecho", "tests\testecho.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc", "tests\testenc.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc_uwb", "tests\testenc_uwb.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc_wb", "tests\testenc_wb.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}" + ProjectSection(ProjectDependencies) = postProject + {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testresample", "tests\testresample.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeexdsp", "libspeexdsp\libspeexdsp.vcproj", "{03207781-0D1C-4DB3-A71D-45C608F28DBD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_RTL_dll|Win32 = Debug_RTL_dll|Win32 + Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Debug_WM5_PPC_ARM|Win32 = Debug_WM5_PPC_ARM|Win32 + Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Debug|Win32 = Debug|Win32 + Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_Dynamic_SSE|Win32 = Release_Dynamic_SSE|Win32 + Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_Dynamic|Win32 = Release_Dynamic|Win32 + Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_RTL_dll|Win32 = Release_RTL_dll|Win32 + Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_SSE|Win32 = Release_SSE|Win32 + Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_SSE2|Win32 = Release_SSE2|Win32 + Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_Static_SSE|Win32 = Release_Static_SSE|Win32 + Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_WM5_PPC_ARM|Win32 = Release_WM5_PPC_ARM|Win32 + Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release|Win32 = Release|Win32 + Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Win32.ActiveCfg = Debug_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Win32.Build.0 = Debug_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.ActiveCfg = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.Build.0 = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_Dynamic_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Win32.Build.0 = Release_Dynamic_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Dynamic_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_Dynamic_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Win32.ActiveCfg = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Win32.Build.0 = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Win32.ActiveCfg = Release_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Win32.Build.0 = Release_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Win32.ActiveCfg = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Win32.Build.0 = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|Win32.ActiveCfg = Release_Static_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|Win32.Build.0 = Release_Static_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_Static_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.ActiveCfg = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.Build.0 = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|Win32.ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|Win32.Build.0 = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|Win32.Build.0 = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|Win32.ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|Win32.Build.0 = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|Win32.Build.0 = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|Win32.Build.0 = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|Win32.Build.0 = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release|Win32.ActiveCfg = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Win32.ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic|Win32.ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_RTL_dll|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE2|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Static_SSE|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Win32.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native/codec/libraries/speex/win32/VS2008/libspeex/Makefile.am b/native/codec/libraries/speex/win32/VS2008/libspeex/Makefile.am new file mode 100644 index 0000000..1ab1201 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/libspeex/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = libspeex.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2008/libspeex/libspeex.vcproj b/native/codec/libraries/speex/win32/VS2008/libspeex/libspeex.vcproj new file mode 100644 index 0000000..36a0588 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/libspeex/libspeex.vcproj @@ -0,0 +1,1676 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2008/speexdec/Makefile.am b/native/codec/libraries/speex/win32/VS2008/speexdec/Makefile.am new file mode 100644 index 0000000..c32b355 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/speexdec/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexdec.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2008/speexdec/speexdec.vcproj b/native/codec/libraries/speex/win32/VS2008/speexdec/speexdec.vcproj new file mode 100644 index 0000000..7882dd0 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/speexdec/speexdec.vcproj @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2008/speexenc/Makefile.am b/native/codec/libraries/speex/win32/VS2008/speexenc/Makefile.am new file mode 100644 index 0000000..13530a7 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/speexenc/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexenc.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2008/speexenc/speexenc.vcproj b/native/codec/libraries/speex/win32/VS2008/speexenc/speexenc.vcproj new file mode 100644 index 0000000..714034f --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/speexenc/speexenc.vcproj @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2008/tests/Makefile.am b/native/codec/libraries/speex/win32/VS2008/tests/Makefile.am new file mode 100644 index 0000000..b44ac43 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/tests/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = testenc.vcproj testenc_uwb.vcproj testenc_wb.vcproj + + diff --git a/native/codec/libraries/speex/win32/VS2008/tests/testenc.vcproj b/native/codec/libraries/speex/win32/VS2008/tests/testenc.vcproj new file mode 100644 index 0000000..3475647 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/tests/testenc.vcproj @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2008/tests/testenc_uwb.vcproj b/native/codec/libraries/speex/win32/VS2008/tests/testenc_uwb.vcproj new file mode 100644 index 0000000..98589e2 --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/tests/testenc_uwb.vcproj @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/VS2008/tests/testenc_wb.vcproj b/native/codec/libraries/speex/win32/VS2008/tests/testenc_wb.vcproj new file mode 100644 index 0000000..0ddb11c --- /dev/null +++ b/native/codec/libraries/speex/win32/VS2008/tests/testenc_wb.vcproj @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/speex/win32/libspeex.def b/native/codec/libraries/speex/win32/libspeex.def new file mode 100644 index 0000000..eab200b --- /dev/null +++ b/native/codec/libraries/speex/win32/libspeex.def @@ -0,0 +1,76 @@ +LIBRARY libspeex +EXPORTS + + +; +; speex.h +; +speex_encoder_init +speex_encoder_destroy +speex_encode +speex_encode_int +speex_encoder_ctl +speex_decoder_init +speex_decoder_destroy +speex_decode +speex_decode_int +speex_decoder_ctl +speex_mode_query +speex_lib_ctl +speex_lib_get_mode + +; +; speex_bits.h +; +speex_bits_init +speex_bits_init_buffer +speex_bits_set_bit_buffer +speex_bits_destroy +speex_bits_reset +speex_bits_rewind +speex_bits_read_from +speex_bits_read_whole_bytes +speex_bits_write +speex_bits_write_whole_bytes +speex_bits_pack +speex_bits_unpack_signed +speex_bits_unpack_unsigned +speex_bits_nbytes +speex_bits_peek_unsigned +speex_bits_peek +speex_bits_advance +speex_bits_remaining +speex_bits_insert_terminator + +; +; speex_callbacks.h +; +speex_inband_handler +speex_std_mode_request_handler +speex_std_high_mode_request_handler +speex_std_char_handler +speex_default_user_handler +speex_std_low_mode_request_handler +speex_std_vbr_request_handler +speex_std_enh_request_handler +speex_std_vbr_quality_request_handler + +; +; speex_header.h +; +speex_init_header +speex_header_to_packet +speex_packet_to_header +speex_header_free + +; +; speex_stereo.h +; +speex_stereo_state_init +speex_stereo_state_reset +speex_stereo_state_destroy +speex_encode_stereo +speex_encode_stereo_int +speex_decode_stereo +speex_decode_stereo_int +speex_std_stereo_request_handler diff --git a/native/codec/libraries/speex/win32/libspeex/Makefile.am b/native/codec/libraries/speex/win32/libspeex/Makefile.am new file mode 100644 index 0000000..4d95004 --- /dev/null +++ b/native/codec/libraries/speex/win32/libspeex/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = libspeex.dsw libspeex.dsp libspeex_dynamic.dsp diff --git a/native/codec/libraries/speex/win32/libspeex/libspeex.dsp b/native/codec/libraries/speex/win32/libspeex/libspeex.dsp new file mode 100644 index 0000000..363de13 --- /dev/null +++ b/native/codec/libraries/speex/win32/libspeex/libspeex.dsp @@ -0,0 +1,332 @@ +# Microsoft Developer Studio Project File - Name="libspeex" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libspeex - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libspeex.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libspeex.mak" CFG="libspeex - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libspeex - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libspeex - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "Perforce Project" +# PROP Scc_LocalPath "..\.." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libspeex - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +F90=df.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /GX- /O2 /Ob2 /I "../../include" /I "../" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_LIB" /D "HAVE_CONFIG_H" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\lib\libspeex.lib" + +!ELSEIF "$(CFG)" == "libspeex - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +F90=df.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX- /Zi /Od /Ob2 /I "../../include" /I "../" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_LIB" /D "HAVE_CONFIG_H" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\lib\libspeex.lib" + +!ENDIF + +# Begin Target + +# Name "libspeex - Win32 Release" +# Name "libspeex - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\libspeex\bits.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\cb_search.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_10_16_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_10_32_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_20_32_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_5_256_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_5_64_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_8_128_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\filters.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\gain_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\gain_table_lbr.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\hexc_10_32_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\hexc_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\high_lsp_tables.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lpc.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lsp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lsp_tables_nb.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\ltp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\modes.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\modes_wb.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\nb_celp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\quant_lsp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\sb_celp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\speex.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\speex_callbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\speex_header.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\stereo.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vbr.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vq.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\window.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\libspeex\arch.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\cb_search.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\cb_search_sse.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\filters.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\filters_sse.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\fixed_debug.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\fixed_generic.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lpc.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lsp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\ltp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\ltp_sse.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\math_approx.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\modes.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\nb_celp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\os_support.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\quant_lsp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\sb_celp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\stack_alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vbr.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vq.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vq_sse.h +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "*.h" +# Begin Source File + +SOURCE=..\..\include\speex\speex.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_bits.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_callbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_header.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_stereo.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_types.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\config.h +# End Source File +# End Target +# End Project diff --git a/native/codec/libraries/speex/win32/libspeex/libspeex.dsw b/native/codec/libraries/speex/win32/libspeex/libspeex.dsw new file mode 100644 index 0000000..5ebad53 --- /dev/null +++ b/native/codec/libraries/speex/win32/libspeex/libspeex.dsw @@ -0,0 +1,65 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "libspeex"=.\libspeex.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libspeex_dynamic"=.\libspeex_dynamic.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libspeexdsp"=.\libspeexdsp.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libspeexdsp_dynamic"=.\libspeexdsp_dynamic.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/native/codec/libraries/speex/win32/libspeex/libspeex_dynamic.dsp b/native/codec/libraries/speex/win32/libspeex/libspeex_dynamic.dsp new file mode 100644 index 0000000..baca7c3 --- /dev/null +++ b/native/codec/libraries/speex/win32/libspeex/libspeex_dynamic.dsp @@ -0,0 +1,341 @@ +# Microsoft Developer Studio Project File - Name="libspeex_dynamic" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=libspeex_dynamic - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libspeex_dynamic.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libspeex_dynamic.mak" CFG="libspeex_dynamic - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libspeex_dynamic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libspeex_dynamic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libspeex_dynamic - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "libspeex_dynamic___Win32_Release" +# PROP BASE Intermediate_Dir "libspeex_dynamic___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Dynamic_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBSPEEX_DYNAMIC_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HAVE_CONFIG_H" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\bin\libspeex.dll" /implib:"..\..\lib\libspeex.lib" + +!ELSEIF "$(CFG)" == "libspeex_dynamic - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "libspeex_dynamic___Win32_Debug" +# PROP BASE Intermediate_Dir "libspeex_dynamic___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Dynamic_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBSPEEX_DYNAMIC_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../include" /I "../" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HAVE_CONFIG_H" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\bin\libspeex.dll" /implib:"..\..\lib\libspeex.lib" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "libspeex_dynamic - Win32 Release" +# Name "libspeex_dynamic - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\libspeex\bits.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\cb_search.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_10_16_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_10_32_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_20_32_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_5_256_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_5_64_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\exc_8_128_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\filters.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\gain_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\gain_table_lbr.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\hexc_10_32_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\hexc_table.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\high_lsp_tables.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lpc.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lsp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lsp_tables_nb.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\ltp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\modes.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\modes_wb.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\nb_celp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\quant_lsp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\sb_celp.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\speex.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\speex_callbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\speex_header.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\stereo.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vbr.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vq.c +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\window.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\libspeex\arch.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\cb_search.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\cb_search_sse.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\filters.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\filters_sse.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\fixed_debug.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\fixed_generic.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lpc.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\lsp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\ltp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\ltp_sse.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\math_approx.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\modes.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\nb_celp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\os_support.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\quant_lsp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\sb_celp.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\stack_alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vbr.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vq.h +# End Source File +# Begin Source File + +SOURCE=..\..\libspeex\vq_sse.h +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "*.h" +# Begin Source File + +SOURCE=..\..\include\speex\speex.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_bits.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_callbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_header.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_stereo.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\speex\speex_types.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\config.h +# End Source File +# Begin Source File + +SOURCE=..\libspeex.def +# End Source File +# End Target +# End Project diff --git a/native/codec/libraries/speex/win32/speex.iss b/native/codec/libraries/speex/win32/speex.iss new file mode 100644 index 0000000..998559b --- /dev/null +++ b/native/codec/libraries/speex/win32/speex.iss @@ -0,0 +1,44 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=Speex +AppVerName=Speex V1.1.6 +AppPublisherURL=http://www.speex.org +AppSupportURL=http://www.speex.org +AppUpdatesURL=http://www.speex.org +DefaultDirName={pf}\Speex +DefaultGroupName=Speex +AllowNoIcons=yes +LicenseFile=..\COPYING +InfoAfterFile=..\README +OutputDir=. +OutputBaseFilename=speex_win32_1.1.6_setup +; uncomment the following line if you want your installation to run on NT 3.51 too. +; MinVersion=4,3.51 + +[Tasks] +;Name: "desktopicon"; Description: "Create a &desktop icon"; GroupDescription: "Additional icons:"; MinVersion: 4,4 + +[Dirs] +Name: "{app}" +Name: "{app}\doc" +Name: "{app}\html" +Name: "{app}\libspeex" +Name: "{app}\libspeex\include" + +[Files] +Source: "speexdec\Release\speexdec.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "speexenc\Release\speexenc.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "libspeex\Release\libspeex.lib"; DestDir: "{app}\libspeex"; Flags: ignoreversion +Source: "libspeex\Release\libspeex.exp"; DestDir: "{app}\libspeex"; Flags: ignoreversion +Source: "libspeex\Release\libspeex.dll"; DestDir: "{app}\libspeex"; Flags: ignoreversion +Source: "..\include\speex\speex.h"; DestDir: "{app}\libspeex\include"; Flags: ignoreversion +Source: "..\include\speex\speex_bits.h"; DestDir: "{app}\libspeex\include"; Flags: ignoreversion +Source: "..\include\speex\speex_callbacks.h"; DestDir: "{app}\libspeex\include"; Flags: ignoreversion +Source: "..\include\speex\speex_header.h"; DestDir: "{app}\libspeex\include"; Flags: ignoreversion +Source: "..\include\speex\speex_stereo.h"; DestDir: "{app}\libspeex\include"; Flags: ignoreversion +Source: "..\doc\manual.pdf"; DestDir: "{app}\doc"; Flags: ignoreversion + +[Run] + diff --git a/native/codec/libraries/speex/win32/speexdec/Makefile.am b/native/codec/libraries/speex/win32/speexdec/Makefile.am new file mode 100644 index 0000000..7c47922 --- /dev/null +++ b/native/codec/libraries/speex/win32/speexdec/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexdec.dsp speexdec.dsw diff --git a/native/codec/libraries/speex/win32/speexdec/speexdec.dsp b/native/codec/libraries/speex/win32/speexdec/speexdec.dsp new file mode 100644 index 0000000..ed66a54 --- /dev/null +++ b/native/codec/libraries/speex/win32/speexdec/speexdec.dsp @@ -0,0 +1,130 @@ +# Microsoft Developer Studio Project File - Name="speexdec" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=speexdec - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "speexdec.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "speexdec.mak" CFG="speexdec - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "speexdec - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "speexdec - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "speexdec - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "../../../libogg/include" /I "../../include" /I "../" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBCMT.lib" /out:"../../bin/speexdec.exe" + +!ELSEIF "$(CFG)" == "speexdec - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../libogg/include" /I "../../include" /I "../" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../bin/speexdec.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "speexdec - Win32 Release" +# Name "speexdec - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\src\getopt.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\getopt1.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\speexdec.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\wav_io.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\wave_out.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\src\getopt_win.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\wav_io.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\wave_out.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/native/codec/libraries/speex/win32/speexdec/speexdec.dsw b/native/codec/libraries/speex/win32/speexdec/speexdec.dsw new file mode 100644 index 0000000..1b7e319 --- /dev/null +++ b/native/codec/libraries/speex/win32/speexdec/speexdec.dsw @@ -0,0 +1,59 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "libspeex"=..\libspeex\libspeex.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ogg_static"="..\..\..\libogg\win32\ogg_static.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "speexdec"=.\speexdec.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libspeex + End Project Dependency + Begin Project Dependency + Project_Dep_Name ogg_static + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/native/codec/libraries/speex/win32/speexenc/Makefile.am b/native/codec/libraries/speex/win32/speexenc/Makefile.am new file mode 100644 index 0000000..c15584f --- /dev/null +++ b/native/codec/libraries/speex/win32/speexenc/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexenc.dsp speexenc.dsw diff --git a/native/codec/libraries/speex/win32/speexenc/speexenc.dsp b/native/codec/libraries/speex/win32/speexenc/speexenc.dsp new file mode 100644 index 0000000..736a802 --- /dev/null +++ b/native/codec/libraries/speex/win32/speexenc/speexenc.dsp @@ -0,0 +1,130 @@ +# Microsoft Developer Studio Project File - Name="speexenc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=speexenc - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "speexenc.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "speexenc.mak" CFG="speexenc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "speexenc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "speexenc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "speexenc - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /GX /Ox /Ot /Og /Oi /Ob2 /I "../" /I "../../include" /I "../../../libogg/include" /D "HAVE_CONFIG_H" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBCMT.lib" /out:"../../bin/speexenc.exe" + +!ELSEIF "$(CFG)" == "speexenc - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../" /I "../../include" /I "../../../libogg/include" /D "HAVE_CONFIG_H" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../bin/speexenc.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "speexenc - Win32 Release" +# Name "speexenc - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\src\getopt.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\getopt1.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\skeleton.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\speexenc.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\wav_io.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\src\getopt_win.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\skeleton.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\wav_io.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/native/codec/libraries/speex/win32/speexenc/speexenc.dsw b/native/codec/libraries/speex/win32/speexenc/speexenc.dsw new file mode 100644 index 0000000..183f291 --- /dev/null +++ b/native/codec/libraries/speex/win32/speexenc/speexenc.dsw @@ -0,0 +1,74 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "libspeex"=..\libspeex\libspeex.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libspeexdsp"=..\libspeex\libspeexdsp.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ogg_static"=..\..\..\libogg\win32\ogg_static.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "speexenc"=.\speexenc.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libspeex + End Project Dependency + Begin Project Dependency + Project_Dep_Name ogg_static + End Project Dependency + Begin Project Dependency + Project_Dep_Name libspeexdsp + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/native/codec/libraries/template/speex_VS2015/Makefile.am b/native/codec/libraries/template/speex_VS2015/Makefile.am new file mode 100644 index 0000000..bdec96f --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +SUBDIRS = libspeex speexenc speexdec tests + +EXTRA_DIST = libspeex.sln diff --git a/native/codec/libraries/template/speex_VS2015/UpgradeLog.htm b/native/codec/libraries/template/speex_VS2015/UpgradeLog.htm new file mode 100644 index 0000000..60099d7 Binary files /dev/null and b/native/codec/libraries/template/speex_VS2015/UpgradeLog.htm differ diff --git a/native/codec/libraries/template/speex_VS2015/libspeex.sln b/native/codec/libraries/template/speex_VS2015/libspeex.sln new file mode 100644 index 0000000..ad3f77b --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/libspeex.sln @@ -0,0 +1,595 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2035 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libspeex\libspeex.vcxproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdec", "speexdec\speexdec.vcxproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexenc", "speexenc\speexenc.vcxproj", "{CD6043D1-D5E7-46D0-854F-00BB1BC308FC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testdenoise", "tests\testdenoise.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testecho", "tests\testecho.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc", "tests\testenc.vcxproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc_uwb", "tests\testenc_uwb.vcxproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testenc_wb", "tests\testenc_wb.vcxproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testresample", "tests\testresample.vcproj", "{961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}" + ProjectSection(ProjectDependencies) = postProject + {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeexdsp", "libspeexdsp\libspeexdsp.vcproj", "{03207781-0D1C-4DB3-A71D-45C608F28DBD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_RTL_dll|Win32 = Debug_RTL_dll|Win32 + Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Debug_RTL_dll|x64 = Debug_RTL_dll|x64 + Debug_WM5_PPC_ARM|Win32 = Debug_WM5_PPC_ARM|Win32 + Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Debug_WM5_PPC_ARM|x64 = Debug_WM5_PPC_ARM|x64 + Debug|Win32 = Debug|Win32 + Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Debug|x64 = Debug|x64 + Release_Dynamic_SSE|Win32 = Release_Dynamic_SSE|Win32 + Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_Dynamic_SSE|x64 = Release_Dynamic_SSE|x64 + Release_Dynamic|Win32 = Release_Dynamic|Win32 + Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_Dynamic|x64 = Release_Dynamic|x64 + Release_RTL_dll|Win32 = Release_RTL_dll|Win32 + Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_RTL_dll|x64 = Release_RTL_dll|x64 + Release_SSE|Win32 = Release_SSE|Win32 + Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_SSE|x64 = Release_SSE|x64 + Release_SSE2|Win32 = Release_SSE2|Win32 + Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_SSE2|x64 = Release_SSE2|x64 + Release_Static_SSE|Win32 = Release_Static_SSE|Win32 + Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_Static_SSE|x64 = Release_Static_SSE|x64 + Release_WM5_PPC_ARM|Win32 = Release_WM5_PPC_ARM|Win32 + Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release_WM5_PPC_ARM|x64 = Release_WM5_PPC_ARM|x64 + Release|Win32 = Release|Win32 + Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Win32.ActiveCfg = Debug_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Win32.Build.0 = Debug_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|x64.ActiveCfg = Debug_RTL_dll|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_RTL_dll|x64.Build.0 = Debug_RTL_dll|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Debug_WM5_PPC_ARM|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug_WM5_PPC_ARM|x64.Build.0 = Debug_WM5_PPC_ARM|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.ActiveCfg = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.Build.0 = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64.ActiveCfg = Debug|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64.Build.0 = Debug|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Win32.Build.0 = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|x64.ActiveCfg = Release_Dynamic|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic_SSE|x64.Build.0 = Release_Dynamic|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Win32.ActiveCfg = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Win32.Build.0 = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Dynamic|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|x64.ActiveCfg = Release_Dynamic|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Dynamic|x64.Build.0 = Release_Dynamic|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Win32.ActiveCfg = Release_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Win32.Build.0 = Release_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_RTL_dll|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|x64.ActiveCfg = Release_RTL_dll|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_RTL_dll|x64.Build.0 = Release_RTL_dll|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|x64.ActiveCfg = Release_SSE|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE|x64.Build.0 = Release_SSE|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Win32.ActiveCfg = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Win32.Build.0 = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|x64.ActiveCfg = Release_SSE2|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_SSE2|x64.Build.0 = Release_SSE2|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|Win32.Build.0 = Release_SSE2|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|x64.ActiveCfg = Release_SSE2|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_Static_SSE|x64.Build.0 = Release_SSE2|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_WM5_PPC_ARM|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release_WM5_PPC_ARM|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release_WM5_PPC_ARM|x64.Build.0 = Release_WM5_PPC_ARM|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.ActiveCfg = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.Build.0 = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64.ActiveCfg = Release|x64 + {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64.Build.0 = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_RTL_dll|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug_WM5_PPC_ARM|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Debug|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|x64.ActiveCfg = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic_SSE|x64.Build.0 = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|Win32.ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|Win32.Build.0 = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|x64.ActiveCfg = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Dynamic|x64.Build.0 = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|Win32.Build.0 = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|x64.ActiveCfg = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_RTL_dll|x64.Build.0 = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|Win32.ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|Win32.Build.0 = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|x64.ActiveCfg = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_SSE2|x64.Build.0 = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|x64.ActiveCfg = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_Static_SSE|x64.Build.0 = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release_WM5_PPC_ARM|x64.Build.0 = Release_SSE2|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|x64.ActiveCfg = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8}.Release|x64.Build.0 = Release|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|x64.ActiveCfg = Debug|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_RTL_dll|x64.Build.0 = Debug|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Debug|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug_WM5_PPC_ARM|x64.Build.0 = Debug|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug|Win32.ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Debug|x64.ActiveCfg = Debug|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic_SSE|x64.ActiveCfg = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic_SSE|x64.Build.0 = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|Win32.Build.0 = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|x64.ActiveCfg = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Dynamic|x64.Build.0 = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|Win32.Build.0 = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|x64.ActiveCfg = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_RTL_dll|x64.Build.0 = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE|x64.ActiveCfg = Release_SSE|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|Win32.Build.0 = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_SSE2|x64.ActiveCfg = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Static_SSE|x64.ActiveCfg = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_Static_SSE|x64.Build.0 = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE2|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release_WM5_PPC_ARM|x64.Build.0 = Release_SSE2|x64 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release|Win32.ActiveCfg = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC}.Release|x64.ActiveCfg = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_RTL_dll|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Debug|x64.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic_SSE|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Dynamic|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_RTL_dll|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE|x64.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_SSE2|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_Static_SSE|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA9}.Release|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_RTL_dll|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Debug|x64.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic_SSE|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Dynamic|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_RTL_dll|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE|x64.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_SSE2|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_Static_SSE|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAA}.Release|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_RTL_dll|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug_WM5_PPC_ARM|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Debug|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Dynamic|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_RTL_dll|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_SSE2|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_Static_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release_WM5_PPC_ARM|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|x64.ActiveCfg = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE}.Release|x64.Build.0 = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_RTL_dll|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug_WM5_PPC_ARM|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Debug|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Dynamic|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_RTL_dll|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_SSE2|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_Static_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release_WM5_PPC_ARM|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|x64.ActiveCfg = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC}.Release|x64.Build.0 = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_RTL_dll|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug_WM5_PPC_ARM|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|x64.ActiveCfg = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Debug|x64.Build.0 = Debug|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Dynamic|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_RTL_dll|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_SSE2|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_Static_SSE|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release_WM5_PPC_ARM|x64.Build.0 = Release_SSE|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|x64.ActiveCfg = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD}.Release|x64.Build.0 = Release|x64 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_RTL_dll|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_WM5_PPC_ARM|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Win32.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Win32.Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Debug|x64.ActiveCfg = Debug|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic_SSE|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Dynamic|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_RTL_dll|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE|x64.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_SSE2|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_Static_SSE|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|Win32.Build.0 = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_SSE|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Win32.ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Win32.Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Win32 + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAB}.Release|x64.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_RTL_dll|Win32.ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_RTL_dll|x64.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_WM5_PPC_ARM|Win32.ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug_WM5_PPC_ARM|x64.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Win32.ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x64.ActiveCfg = Debug|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic_SSE|Win32.ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic_SSE|x64.ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic|Win32.ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Dynamic_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Dynamic|x64.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_RTL_dll|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_RTL_dll|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_RTL_dll|x64.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE|x64.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE2|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE2|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_SSE2|x64.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Static_SSE|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Static_SSE|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_Static_SSE|x64.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_WM5_PPC_ARM|Win32.ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_WM5_PPC_ARM|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release_Static_SSE|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release_WM5_PPC_ARM|x64.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Win32.ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32 + {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C2EC4768-385B-4D25-8726-62B6B4FDDDAA} + EndGlobalSection +EndGlobal diff --git a/native/codec/libraries/template/speex_VS2015/libspeex/Makefile.am b/native/codec/libraries/template/speex_VS2015/libspeex/Makefile.am new file mode 100644 index 0000000..1ab1201 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/libspeex/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = libspeex.vcproj + + diff --git a/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcproj b/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcproj new file mode 100644 index 0000000..36a0588 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcproj @@ -0,0 +1,1676 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj b/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj new file mode 100644 index 0000000..611cef2 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj @@ -0,0 +1,767 @@ + + + + + Debug_RTL_dll + Win32 + + + Debug_RTL_dll + x64 + + + Debug_WM5_PPC_ARM + Win32 + + + Debug_WM5_PPC_ARM + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release_Dynamic + Win32 + + + Release_Dynamic + x64 + + + Release_RTL_dll + Win32 + + + Release_RTL_dll + x64 + + + Release_SSE2 + Win32 + + + Release_SSE2 + x64 + + + Release_SSE + Win32 + + + Release_SSE + x64 + + + Release_WM5_PPC_ARM + Win32 + + + Release_WM5_PPC_ARM + x64 + + + Release + Win32 + + + Release + x64 + + + + {E972C52F-9E85-4D65-B19C-031E511E9DB4} + libspeex + Win32Proj + + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + + + StaticLibrary + v141 + MultiByte + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + + + StaticLibrary + v141 + MultiByte + + + DynamicLibrary + v141 + MultiByte + true + + + DynamicLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + true + + + StaticLibrary + v141 + MultiByte + + + StaticLibrary + v141 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>15.0.27625.0 + + + $(SolutionDir)$(Configuration)\ + Debug\ + + + + $(SolutionDir)$(Configuration)\ + Release\ + + + $(Configuration)\ + $(Configuration)\ + + + $(Configuration)\ + $(Configuration)\ + + + $(Configuration)\ + $(Configuration)\ + + + $(Configuration)\ + $(Configuration)\ + + + $(Configuration)\ + $(Configuration)\ + + + $(Configuration)\ + $(Configuration)\ + + + $(Configuration)\ + $(Configuration)\ + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level4 + EditAndContinue + CompileAsC + + + $(OutDir)libspeex.lib + + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level4 + ProgramDatabase + CompileAsC + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + StreamingSIMDExtensions + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + StreamingSIMDExtensions + + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + StreamingSIMDExtensions2 + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + StreamingSIMDExtensions2 + + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + libspeex.def + true + true + false + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + libspeex.def + true + true + false + + + + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + CompileAsC + + + $(OutDir)libspeex.lib + + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + CompileAsC + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreadedDLL + false + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + EditAndContinue + CompileAsC + + + $(OutDir)libspeex.lib + + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + CompileAsC + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreadedDLL + false + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + + + Level4 + ProgramDatabase + CompileAsC + 4244;4305;4311;4100;4127;%(DisableSpecificWarnings) + + + $(OutDir)libspeex.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj.filters b/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj.filters new file mode 100644 index 0000000..7650bbf --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj.filters @@ -0,0 +1,215 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj.user b/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/libspeex/libspeex.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/speexdec/Makefile.am b/native/codec/libraries/template/speex_VS2015/speexdec/Makefile.am new file mode 100644 index 0000000..c32b355 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexdec/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexdec.vcproj + + diff --git a/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcproj b/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcproj new file mode 100644 index 0000000..7882dd0 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcproj @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj b/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj new file mode 100644 index 0000000..fcac0bd --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj @@ -0,0 +1,415 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release_SSE2 + Win32 + + + Release_SSE2 + x64 + + + Release_SSE + Win32 + + + Release_SSE + x64 + + + Release + Win32 + + + Release + x64 + + + + {961B8359-1393-4EF7-B8E0-67B6FE1C6DA8} + speexdec + Win32Proj + + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + + + Application + v141 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>15.0.27625.0 + + + $(SolutionDir)$(Configuration)\ + Debug\ + true + + + true + + + $(SolutionDir)$(Configuration)\ + Release\ + false + + + false + + + $(Configuration)\ + $(Configuration)\ + false + + + false + + + $(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexdec.exe + true + $(OutDir)speexenc.pdb + Console + false + + MachineX86 + + + + + Disabled + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexdec.exe + true + $(OutDir)speexenc.pdb + Console + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexdec.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexdec.exe + true + Console + true + true + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + StreamingSIMDExtensions + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexdec.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + StreamingSIMDExtensions + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexdec.exe + true + Console + true + true + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + StreamingSIMDExtensions2 + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexdec.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + StreamingSIMDExtensions2 + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexdec.exe + true + Console + true + true + false + + + + + + + + + + + + + + + + + + + + + {e972c52f-9e85-4d65-b19c-031e511e9db4} + false + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj.filters b/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj.filters new file mode 100644 index 0000000..31ca84f --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj.user b/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexdec/speexdec.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/speexenc/Makefile.am b/native/codec/libraries/template/speex_VS2015/speexenc/Makefile.am new file mode 100644 index 0000000..13530a7 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexenc/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = speexenc.vcproj + + diff --git a/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcproj b/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcproj new file mode 100644 index 0000000..714034f --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcproj @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj b/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj new file mode 100644 index 0000000..c1196ce --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj @@ -0,0 +1,415 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release_SSE2 + Win32 + + + Release_SSE2 + x64 + + + Release_SSE + Win32 + + + Release_SSE + x64 + + + Release + Win32 + + + Release + x64 + + + + {CD6043D1-D5E7-46D0-854F-00BB1BC308FC} + speexenc + Win32Proj + + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + + + Application + v141 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>15.0.27625.0 + + + $(SolutionDir)$(Configuration)\ + Debug\ + true + + + true + + + $(SolutionDir)$(Configuration)\ + Release\ + false + + + false + + + $(Configuration)\ + $(Configuration)\ + false + + + false + + + $(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexenc.exe + true + $(OutDir)speexenc.pdb + Console + false + + MachineX86 + + + + + Disabled + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexenc.exe + true + $(OutDir)speexenc.pdb + Console + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexenc.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexenc.exe + true + Console + true + true + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + StreamingSIMDExtensions + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexenc.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + StreamingSIMDExtensions + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexenc.exe + true + Console + true + true + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreaded + false + StreamingSIMDExtensions2 + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexenc.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..\..\..\libogg\include;..\..\..\libspeex;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + StreamingSIMDExtensions2 + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + $(OutDir)speexenc.exe + true + Console + true + true + false + + + + + + + + + + + + + + + + + + + + + {e972c52f-9e85-4d65-b19c-031e511e9db4} + false + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj.filters b/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj.filters new file mode 100644 index 0000000..039b4f6 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj.user b/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/speexenc/speexenc.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/Makefile.am b/native/codec/libraries/template/speex_VS2015/tests/Makefile.am new file mode 100644 index 0000000..b44ac43 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in. -*-Makefile-*- + +# Disable automatic dependency tracking if using other tools than gcc and gmake +#AUTOMAKE_OPTIONS = no-dependencies + +EXTRA_DIST = testenc.vcproj testenc_uwb.vcproj testenc_wb.vcproj + + diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc.vcproj b/native/codec/libraries/template/speex_VS2015/tests/testenc.vcproj new file mode 100644 index 0000000..3475647 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc.vcproj @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj b/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj new file mode 100644 index 0000000..051acd7 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj @@ -0,0 +1,305 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release_SSE + Win32 + + + Release_SSE + x64 + + + Release + Win32 + + + Release + x64 + + + + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAE} + Win32Proj + + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + + + Application + v141 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>15.0.27625.0 + + + Debug\ + Debug\ + true + + + true + + + Release\ + Release\ + false + + + false + + + $(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc.exe + true + $(OutDir)speexenc.pdb + Console + false + + MachineX86 + + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc.exe + true + $(OutDir)speexenc.pdb + Console + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreadedDLL + false + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc.exe + true + Console + true + true + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreadedDLL + false + StreamingSIMDExtensions + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + StreamingSIMDExtensions + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc.exe + true + Console + true + true + false + + + + + + + + + + {e972c52f-9e85-4d65-b19c-031e511e9db4} + false + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj.filters b/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj.filters new file mode 100644 index 0000000..aadac65 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + Source Files + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj.user b/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcproj b/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcproj new file mode 100644 index 0000000..98589e2 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcproj @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj b/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj new file mode 100644 index 0000000..09e0f08 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj @@ -0,0 +1,305 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release_SSE + Win32 + + + Release_SSE + x64 + + + Release + Win32 + + + Release + x64 + + + + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAC} + Win32Proj + + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + + + Application + v141 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>15.0.27625.0 + + + Debug\ + Debug\ + true + + + true + + + Release\ + Release\ + false + + + false + + + $(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_uwb.exe + true + $(OutDir)speexenc.pdb + Console + false + + MachineX86 + + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_uwb.exe + true + $(OutDir)speexenc.pdb + Console + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreadedDLL + false + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_uwb.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_uwb.exe + true + Console + true + true + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreadedDLL + false + StreamingSIMDExtensions + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_uwb.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + StreamingSIMDExtensions + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_uwb.exe + true + Console + true + true + false + + + + + + + + + + {e972c52f-9e85-4d65-b19c-031e511e9db4} + false + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj.filters b/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj.filters new file mode 100644 index 0000000..9c30fde --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + Source Files + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj.user b/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc_uwb.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcproj b/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcproj new file mode 100644 index 0000000..0ddb11c --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcproj @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj b/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj new file mode 100644 index 0000000..7becf0d --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj @@ -0,0 +1,305 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release_SSE + Win32 + + + Release_SSE + x64 + + + Release + Win32 + + + Release + x64 + + + + {961B8359-1393-4EF7-B8E0-67B6FE1C6DAD} + Win32Proj + + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + true + + + Application + v141 + MultiByte + + + Application + v141 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>15.0.27625.0 + + + Debug\ + Debug\ + true + + + true + + + Release\ + Release\ + false + + + false + + + $(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_wb.exe + true + $(OutDir)speexenc.pdb + Console + false + + MachineX86 + + + + + Disabled + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_wb.exe + true + $(OutDir)speexenc.pdb + Console + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreadedDLL + false + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_wb.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_wb.exe + true + Console + true + true + false + + + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + MultiThreadedDLL + false + StreamingSIMDExtensions + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_wb.exe + true + Console + true + true + false + + MachineX86 + + + + + Full + AnySuitable + true + Speed + ..\..\..\include;..\..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + StreamingSIMDExtensions + + + Level3 + ProgramDatabase + CompileAsC + + + winmm.lib;%(AdditionalDependencies) + ../../../bin/testenc_wb.exe + true + Console + true + true + false + + + + + + + + + + {e972c52f-9e85-4d65-b19c-031e511e9db4} + false + + + + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj.filters b/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj.filters new file mode 100644 index 0000000..25ec3cd --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + Source Files + + + \ No newline at end of file diff --git a/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj.user b/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/native/codec/libraries/template/speex_VS2015/tests/testenc_wb.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/native/codec/trace.h b/native/codec/trace.h new file mode 100644 index 0000000..9f68968 --- /dev/null +++ b/native/codec/trace.h @@ -0,0 +1,93 @@ +// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/ +// published under the WTFPL v2.0 + +#ifndef _STACKTRACE_H_ +#define _STACKTRACE_H_ + +#include +#include +#include +#include + +/** Print a demangled stack backtrace of the caller function to FILE* out. */ +static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63) +{ + fprintf(out, "stack trace:\n"); + + // storage array for stack trace address data + void* addrlist[max_frames+1]; + + // retrieve current stack addresses + int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*)); + + if (addrlen == 0) { + fprintf(out, " \n"); + return; + } + + // resolve addresses into strings containing "filename(function+address)", + // this array must be free()-ed + char** symbollist = backtrace_symbols(addrlist, addrlen); + + // allocate string which will be filled with the demangled function name + size_t funcnamesize = 256; + char* funcname = (char*)malloc(funcnamesize); + + // iterate over the returned symbol lines. skip the first, it is the + // address of this function. + for (int i = 1; i < addrlen; i++) + { + char *begin_name = 0, *begin_offset = 0, *end_offset = 0; + + // find parentheses and +address offset surrounding the mangled name: + // ./module(function+0x15c) [0x8048a6d] + for (char *p = symbollist[i]; *p; ++p) + { + if (*p == '(') + begin_name = p; + else if (*p == '+') + begin_offset = p; + else if (*p == ')' && begin_offset) { + end_offset = p; + break; + } + } + + if (begin_name && begin_offset && end_offset + && begin_name < begin_offset) + { + *begin_name++ = '\0'; + *begin_offset++ = '\0'; + *end_offset = '\0'; + + // mangled name is now in [begin_name, begin_offset) and caller + // offset in [begin_offset, end_offset). now apply + // __cxa_demangle(): + + int status; + char* ret = abi::__cxa_demangle(begin_name, + funcname, &funcnamesize, &status); + if (status == 0) { + funcname = ret; // use possibly realloc()-ed string + fprintf(out, " %s : %s+%s\n", + symbollist[i], funcname, begin_offset); + } + else { + // demangling failed. Output function name as a C function with + // no arguments. + fprintf(out, " %s : %s()+%s\n", + symbollist[i], begin_name, begin_offset); + } + } + else + { + // couldn't parse the line? print the whole line. + fprintf(out, " %s\n", symbollist[i]); + } + } + + free(funcname); + free(symbollist); +} + +#endif // _STACKTRACE_H_ \ No newline at end of file diff --git a/native/crash_handler/.gitignore b/native/crash_handler/.gitignore new file mode 100644 index 0000000..dbb958a --- /dev/null +++ b/native/crash_handler/.gitignore @@ -0,0 +1,3 @@ +.idea/ +cmake-build-* +!exports/*.d.ts \ No newline at end of file diff --git a/native/crash_handler/CMakeLists.txt b/native/crash_handler/CMakeLists.txt new file mode 100644 index 0000000..fb74c7f --- /dev/null +++ b/native/crash_handler/CMakeLists.txt @@ -0,0 +1,17 @@ +set(MODULE_NAME "teaclient_crash_handler") + +set(SOURCE_FILES ${SOURCE_FILES} src/crash_handler.cpp) +if (MSVC) + set(SOURCE_FILES ${SOURCE_FILES} src/win_crash_generator.cpp) +else() + include_directories(/usr/local/include/breakpad) + resolve_library(LIBRARY_PATH_BREAKPAD OFF "${LIBRARY_PATH}/breakpad/build/src/client/linux/libbreakpad_client.a") + + set(REQUIRED_LIBRARIES + ${LIBRARY_PATH_BREAKPAD} + libstdc++fs.a + ) +endif() + +add_nodejs_module(${MODULE_NAME} binding.cc ${SOURCE_FILES}) +target_link_libraries(${MODULE_NAME} ${REQUIRED_LIBRARIES}) diff --git a/native/crash_handler/binding.cc b/native/crash_handler/binding.cc new file mode 100644 index 0000000..cd58be0 --- /dev/null +++ b/native/crash_handler/binding.cc @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +using namespace std; + +#include "NanException.h" +#include "NanEventCallback.h" +#include "src/crash_handler.h" + +#include + +NAN_METHOD(setup_crash_handler) { + if(info.Length() != 4) { + Nan::ThrowError("invalid argument count"); + return; + } + + if(!info[0]->IsString() || !info[1]->IsString() || !info[2]->IsString() || !info[3]->IsString()) { + Nan::ThrowError("invalid argument types"); + return; + } + + if(tc::signal::active()) { + Nan::ThrowError("crash handler has already been initialized!"); + return; + } + + auto context = make_unique(); + context->component_name = *Nan::Utf8String(info[0]); + context->crash_dump_folder = *Nan::Utf8String(info[1]); + context->success_command_line = *Nan::Utf8String(info[2]); + context->error_command_line = *Nan::Utf8String(info[3]); + tc::signal::setup(context); +} + +NAN_METHOD(crash_handler_active) { + info.GetReturnValue().Set(tc::signal::active()); +} + +NAN_METHOD(finalize) { + tc::signal::finalize(); +} + +#include +namespace fs = std::experimental::filesystem; + +NAN_METHOD(crash) { + std::thread([] { + while (true) { + this_thread::sleep_for(chrono::milliseconds(100)); + cout << "crash bg thread" << endl; + } + }).detach(); + + *(int*) (nullptr) = 0; +} + +NAN_MODULE_INIT(init) { + NAN_EXPORT(target, setup_crash_handler); + NAN_EXPORT(target, crash_handler_active); + NAN_EXPORT(target, finalize); + NAN_EXPORT(target, crash); +} + +NODE_MODULE(MODULE_NAME, init) \ No newline at end of file diff --git a/native/crash_handler/exports/exports.d.ts b/native/crash_handler/exports/exports.d.ts new file mode 100644 index 0000000..7595a43 --- /dev/null +++ b/native/crash_handler/exports/exports.d.ts @@ -0,0 +1,12 @@ +declare module "teaclient_crash_handler" { + export function setup_crash_handler( + component_name: string, + crash_dump_folder: string, + success_command_line: string, /* %crash_path% for crash dump path */ + error_command_line: string /* %error_message% for the error message */ + ); + export function finalize(); + export function crash_handler_active() : boolean; + + export function crash(); +} \ No newline at end of file diff --git a/native/crash_handler/src/base64.h b/native/crash_handler/src/base64.h new file mode 100644 index 0000000..01708a4 --- /dev/null +++ b/native/crash_handler/src/base64.h @@ -0,0 +1,90 @@ +#include + +namespace base64 { + inline std::string encode(const std::string data) { + static constexpr char sEncodingTable[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + }; + + size_t in_len = data.size(); + size_t out_len = 4 * ((in_len + 2) / 3); + std::string ret(out_len, '\0'); + size_t i; + char *p = const_cast(ret.c_str()); + + for (i = 0; i < in_len - 2; i += 3) { + *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; + *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; + *p++ = sEncodingTable[data[i + 2] & 0x3F]; + } + if (i < in_len) { + *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; + if (i == (in_len - 1)) { + *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; + *p++ = '='; + } + else { + *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + + return ret; + } + + inline std::string decode(const std::string& input, std::string& out) { + static constexpr unsigned char kDecodingTable[] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + + size_t in_len = input.size(); + if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; + + size_t out_len = in_len / 4 * 3; + if (input[in_len - 1] == '=') out_len--; + if (input[in_len - 2] == '=') out_len--; + + out.resize(out_len); + + for (size_t i = 0, j = 0; i < in_len;) { + uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + + uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); + + if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; + if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; + if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; + } + + return ""; + } + + +} \ No newline at end of file diff --git a/native/crash_handler/src/crash_handler.cpp b/native/crash_handler/src/crash_handler.cpp new file mode 100644 index 0000000..e4d2cb9 --- /dev/null +++ b/native/crash_handler/src/crash_handler.cpp @@ -0,0 +1,181 @@ +#include "crash_handler.h" + +#ifdef WIN32 + #include +#else + #include +#endif + +#include +#include +#include +#include "base64.h" + +using namespace std; +using namespace tc; +using namespace tc::signal; +namespace fs = std::experimental::filesystem; + +#ifndef WIN32 +unique_ptr global_crash_handler; +#else +PVOID global_crash_handler = nullptr; +#endif +unique_ptr crash_context; + +bool crash_callback(const fs::path&, CrashContext*, const std::string&, bool); +std::string replace_all(std::string data, const std::string& needle, const std::string& replacement) { + size_t pos = data.find(needle); + while(pos != std::string::npos) { + data.replace(pos, needle.size(), replacement); + pos = data.find(needle, pos + replacement.size()); + } + + return data; +} + +/* taken from the updater */ +bool rename_or_move(const fs::path& source, const fs::path& target, std::string& error) { + try { + fs::rename(source, target); + return true; + } catch(const fs::filesystem_error& ex) { +#ifndef WIN32 + if(ex.code() == errc::cross_device_link) { + /* try with move command */ + char buffer[2048]; + auto length = snprintf(buffer, 2048, R"(%s "%s" "%s")", "mv", source.c_str(), target.c_str()); /* build the move command */ + if(length < 1 || length >= 2049) { + error = "failed to prepare move command!"; + return false; + } + auto code = system(buffer); + if(code != 0) { + error = "move command resulted in " + to_string(code); + return false; + } + return true; + } +#endif + error = "rename returned error code " + to_string(ex.code().value()) + " (" + ex.code().message() + ")"; + return false; + } +} + +void crash_execute_detached(const std::string& command_line) { + cout << "Exec command " << command_line << endl; + #ifdef WIN32 + STARTUPINFO si; + PROCESS_INFORMATION pi; + + // set the size of the structures + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + // start the program up + auto result = CreateProcess(nullptr, // the path + (LPSTR) command_line.c_str(), // Command line + nullptr, // Process handle not inheritable + nullptr, // Thread handle not inheritable + FALSE, // Set handle inheritance to FALSE + CREATE_NEW_CONSOLE , // No creation flags + nullptr, // Use parent's environment block + nullptr, // Use parent's starting directory + &si, // Pointer to STARTUPINFO structure + &pi // Pointer to PROCESS_INFORMATION structure (removed extra parentheses) + ); + // Close process and thread handles. + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + #else + auto full_command_line = command_line + "&"; + system(full_command_line.c_str()); + std::cout << "Executed crash command " << full_command_line << std::endl; + #endif +} + +#ifndef WIN32 +/* we want to prevent allocations while we're within a crash */ +const static std::string _message_fail = "failed write crash dump"; +const static std::string _message_success; +bool breakpad_crash_callback(const google_breakpad::MinidumpDescriptor& descriptor, void* _context, bool succeeded) { + return crash_callback(descriptor.path(), &*crash_context, succeeded ? _message_success : _message_fail, succeeded); +} +#else +extern LONG WINAPI unhandled_handler(struct _EXCEPTION_POINTERS* apExceptionInfo); +void win_crash_callback(const fs::path& source_file, const std::string& error, bool success) { + crash_callback(source_file, &*crash_context, error, success); +} +#endif + +bool crash_callback(const fs::path& source_file, CrashContext* context, const std::string& error_message, bool succeeded) { + if(!succeeded) { + /* crash dump error handling xD */ + + crash_execute_detached(replace_all( + context->error_command_line, + "%error_message%", + error_message + )); + } else { + /* "normal" crash handling */ + auto target_directory = fs::u8path(context->crash_dump_folder); + if(!fs::exists(target_directory)) { + try { + fs::create_directories(target_directory); + } catch(const fs::filesystem_error& error) { + crash_execute_detached(replace_all( + context->error_command_line, + "%error_message%", + base64::encode("failed write move crash dump (" + source_file.string() + "): Target directory could not be created: " + error.what()) + )); + return succeeded; + } + } + auto target_file = target_directory / ("crash_dump_" + context->component_name + "_" + source_file.filename().string()); + string error; + if(!rename_or_move(source_file, target_file, error)) { + crash_execute_detached(replace_all( + context->error_command_line, + "%error_message%", + base64::encode("failed write move crash dump (" + source_file.string() + "): " + error) + )); + return succeeded; + } + crash_execute_detached(replace_all( + context->success_command_line, + "%crash_path%", + base64::encode(target_file.string()) + )); + } + return succeeded; +} + +extern void create_minidump(struct _EXCEPTION_POINTERS* apExceptionInfo); + +bool signal::setup(std::unique_ptr& context) { +#ifndef WIN32 + global_crash_handler = make_unique(google_breakpad::MinidumpDescriptor("/tmp"), nullptr, breakpad_crash_callback, nullptr, true, -1); +#else + global_crash_handler = AddVectoredExceptionHandler(0, unhandled_handler); /* this only works! */ +#endif + crash_context = move(context); + return true; +} + +bool signal::active() { + return !!crash_context; +} + +void signal::finalize() { +#ifndef WIN32 + global_crash_handler.reset(); +#else + if(global_crash_handler) + RemoveVectoredExceptionHandler(global_crash_handler); + + global_crash_handler = nullptr; +#endif + crash_context.reset(); +} \ No newline at end of file diff --git a/native/crash_handler/src/crash_handler.h b/native/crash_handler/src/crash_handler.h new file mode 100644 index 0000000..eb0ae8a --- /dev/null +++ b/native/crash_handler/src/crash_handler.h @@ -0,0 +1,21 @@ +#pragma once + + +#include +#include + +namespace tc { + namespace signal { + struct CrashContext { + std::string component_name; + std::string crash_dump_folder; + + std::string success_command_line; /* %crash_path% for crash dumps */ + std::string error_command_line; /* %error_message% for the error message */ + }; + + extern bool active(); + extern bool setup(std::unique_ptr& /* crash context (will be moved) */); + extern void finalize(); + } +} \ No newline at end of file diff --git a/native/crash_handler/src/win_crash_generator.cpp b/native/crash_handler/src/win_crash_generator.cpp new file mode 100644 index 0000000..4cb30b2 --- /dev/null +++ b/native/crash_handler/src/win_crash_generator.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +namespace fs = std::experimental::filesystem; + +using namespace std; +extern void win_crash_callback(const fs::path& source_file, const std::string& error, bool success); + +typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)( + HANDLE hProcess, + DWORD dwPid, + HANDLE hFile, + MINIDUMP_TYPE DumpType, + CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam +); + +fs::path generate_temp_file(std::string& error) { + WCHAR szPath[MAX_PATH]; + WCHAR szFileName[MAX_PATH]; + DWORD dwBufferSize = MAX_PATH; + SYSTEMTIME stLocalTime; + + GetLocalTime( &stLocalTime ); + GetTempPathW( dwBufferSize, szPath ); + + CreateDirectoryW( szFileName, nullptr ); + StringCchPrintfW(szFileName, MAX_PATH, L"%s\\%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp", + szPath, + stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, + stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, + GetCurrentProcessId(), GetCurrentThreadId()); + return fs::path(szFileName); +} + +void create_minidump(struct _EXCEPTION_POINTERS* apExceptionInfo) +{ + string error; + HANDLE hDumpFile = nullptr; + fs::path file_path; + HMODULE mhLib = ::LoadLibrary(_T("dbghelp.dll")); + if(!mhLib) { + error = "failed to file dbghelp.dll"; + goto error_handling; + } + + auto pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(mhLib, "MiniDumpWriteDump"); + if(!pDump) { + error = "failed to file find MiniDumpWriteDump handle"; + goto error_handling; + } + + file_path = generate_temp_file(error); + hDumpFile = CreateFileW(file_path.wstring().c_str(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, nullptr, CREATE_ALWAYS, 0, nullptr); + if(!hDumpFile) { + error = "failed to open file"; + goto error_handling; + } + + _MINIDUMP_EXCEPTION_INFORMATION ExInfo{}; + ExInfo.ThreadId = ::GetCurrentThreadId(); + ExInfo.ExceptionPointers = apExceptionInfo; + ExInfo.ClientPointers = FALSE; + + if(!pDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &ExInfo, nullptr, nullptr)) { + error = "failed to generate dump file"; + goto error_handling; + } + ::CloseHandle(hDumpFile); + win_crash_callback(file_path, error, true); + return; + + error_handling: + if(hDumpFile) { + ::CloseHandle(hDumpFile); + } + win_crash_callback(file_path, error, false); +} + +LONG WINAPI unhandled_handler(struct _EXCEPTION_POINTERS* apExceptionInfo) { + auto code = apExceptionInfo->ExceptionRecord->ExceptionCode; + auto crash = false; + switch(code) { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_STACK_OVERFLOW: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_IN_PAGE_ERROR: + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + crash = true; + break; + default: + crash = false; + } + + if(!crash) + return EXCEPTION_CONTINUE_SEARCH; + + create_minidump(apExceptionInfo); + exit(1); + return EXCEPTION_EXECUTE_HANDLER; +} diff --git a/native/crash_handler/test/crash_test.cpp b/native/crash_handler/test/crash_test.cpp new file mode 100644 index 0000000..3756147 --- /dev/null +++ b/native/crash_handler/test/crash_test.cpp @@ -0,0 +1,5 @@ +// +// Created by wolverindev on 29.05.19. +// + +int main(int argc, char **argv) {} \ No newline at end of file diff --git a/native/crash_handler/test/crash_test.ts b/native/crash_handler/test/crash_test.ts new file mode 100644 index 0000000..50311b6 --- /dev/null +++ b/native/crash_handler/test/crash_test.ts @@ -0,0 +1,31 @@ +//__filename + +module.paths.push("../../build/linux_x64"); +module.paths.push("../../build/win32_64"); + +const electron = require("electron"); +const crash_handler = require("teaclient_crash_handler"); + +if(process.argv.length != 3) { + electron.app.on('ready', () => { + console.log("SHow dialog"); + electron.dialog.showMessageBox({ + message: "Arguments: " + JSON.stringify(process.argv) + }); + electron.app.exit(); + }); +} else { + crash_handler.setup_crash_handler( + "test", + __dirname + "/test_crash/", + process.argv[0] + " " + __filename + " X app-success %crash_path%", + process.argv[0] + " " + __filename + " X app-error %error_message%", + ); + console.log(process.argv[0] + " " + __filename + " X app-success %crash_path%"); + console.log("Setup!"); + console.log("Crash!"); + crash_handler.crash(); +} + + +export {}; \ No newline at end of file diff --git a/native/crash_handler/test/test_crash/crash_dump_test_381fc65c-2a4a-46d9-e59385b6-64cd1080.dmp b/native/crash_handler/test/test_crash/crash_dump_test_381fc65c-2a4a-46d9-e59385b6-64cd1080.dmp new file mode 100644 index 0000000..ef7a41c Binary files /dev/null and b/native/crash_handler/test/test_crash/crash_dump_test_381fc65c-2a4a-46d9-e59385b6-64cd1080.dmp differ diff --git a/native/create_symbols.sh b/native/create_symbols.sh new file mode 100755 index 0000000..de7294e --- /dev/null +++ b/native/create_symbols.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +cd $(dirname $0) + +SYMBOL_ROOT="build/symbols" +BINARY_PATHS=("build/linux_x64/teaclient_connection.node" "build/linux_x64/teaclient_crash_handler.node" "build/linux_x64/teaclient_dns.node" "build/linux_x64/teaclient_ppt.node" "build/exe/update-installer") + +echo "Created dump symbols!" +for file in ${BINARY_PATHS[@]}; do + if [[ ! -e ${file} ]]; then + echo "Missing binary ${file}. Skipping file" + continue + fi + + echo "Generating symbols for ${file}" + symbols="$(dump_syms ${file} 2>&1)" + if [[ $? -ne 0 ]]; then + echo "Failed to dump symbols for ${file}. Skipping file. Output:" + echo "${symbols}" + continue; + fi + + symbol_info=$(echo "${symbols}" | head -n1) + symbol_info_array=($symbol_info) + echo "Symbol dump id: ${symbol_info_array[3]}; Dump name: ${symbol_info_array[4]}" + symbol_path="${SYMBOL_ROOT}/${symbol_info_array[4]}/${symbol_info_array[3]}" + symbol_file="${symbol_info_array[4]}.sym" + echo "Saving symbols to ${symbol_path}/${symbol_file}" + mkdir -p ${symbol_path} + [[ $? -ne 0 ]] && { + echo "Failed to create target dump path! Skipping file" + continue + } + echo "${symbols}" > "${symbol_path}/${symbol_file}" +done +echo "All symbols have been created" + diff --git a/native/dist/ext_nan/CMakeLists.txt b/native/dist/ext_nan/CMakeLists.txt new file mode 100644 index 0000000..130e454 --- /dev/null +++ b/native/dist/ext_nan/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.1) + +project(nan_ext VERSION 1.0.0) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") + +add_add_executable(test test/main.cpp) \ No newline at end of file diff --git a/native/dist/ext_nan/NanEventCallback.h b/native/dist/ext_nan/NanEventCallback.h new file mode 100644 index 0000000..1c511ee --- /dev/null +++ b/native/dist/ext_nan/NanEventCallback.h @@ -0,0 +1,216 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Nan { + namespace async_helper { + template + struct callback_wrap; + + template + struct lambda_type; + + template + struct lambda_type { + + using void_function = std::function; + using result = callback_wrap; + + inline static void_function wrap(const std::shared_ptr& lam) { + return [lam](Args&&... args) { (*lam)(std::forward(args)...); }; + } + }; + + template + struct lambda_type { + using void_function = std::function; + using result = callback_wrap; + + inline static void_function wrap(const std::shared_ptr& lam) { + return [lam](Args&&... args) { (*lam)(std::forward(args)...); }; + } + }; + + // helper class + template class Params, typename... Args, std::size_t... I> + inline R call_helper(std::function const& func, Params const& params, std::index_sequence) { + return func(std::forward((Args&&) std::get(params))...); + } + + template + struct callback_args { + uv_async_t handle{}; + bool flag_execute = false; + bool destroy_only = false; + bool option_destroy_run = false; /* execute the callback, even if the haven had been destoryed */ + std::mutex destroy_lock; + + std::function callback; + std::tuple arguments; + }; + + template + struct _or_ { + constexpr static bool value = false; + }; + + template + struct _or_ { + constexpr static bool value = T || _or_::value; + }; + + + template + struct callback_scoped { + callback_args* handle; + std::function callback; + std::function destroy; + + callback_scoped( + callback_args* handle, + const std::function &callback, + std::function destroy + ) : callback(callback), destroy(std::move(destroy)), handle(handle) {} + + ~callback_scoped() { destroy(); } + }; + + template + struct callback_wrap { + std::shared_ptr> handle; + + void call_cpy(Args... args, bool no_throw = false) { + if(!this->handle) { + if(no_throw) + return; + throw std::bad_function_call(); + } + handle->callback(std::forward(args)...); + } + + void call(Args&&... args, bool no_throw = false) { + if(!this->handle) { + if(no_throw) + return; + throw std::bad_function_call(); + } + handle->callback(std::forward(args)...); + } + + void operator()(Args&&... args) { + if(!this->handle) + throw std::bad_function_call(); + handle->callback(std::forward(args)...); + } + void operator()(Args&&... args) const { + if(!this->handle) + throw std::bad_function_call(); + handle->callback(std::forward(args)...); + } + + callback_wrap& operator=(const callback_wrap& other) { + this->handle = other.handle; + + return *this; + } + + operator bool() const { + return this->handle != nullptr; + } + + callback_wrap& operator=(nullptr_t) { + this->handle = nullptr; + return *this; + } + + /** + * @returns true if the callback will be called even + * if the handle has been destroyed + */ + bool option_destroyed_execute() const { + if(!this->handle) + std::__throw_logic_error("missing handle"); + return this->handle->handle->option_destroy_run; + } + + /** + * @param flag + * If true then the callback will be called event + * if the handle has already been destroyed + * @return this + */ + callback_wrap& option_destroyed_execute(bool flag) { + if(!this->handle) + throw std::logic_error("missing handle"); + this->handle->handle->option_destroy_run = flag; + return *this; + } + }; + }; + template + using callback_t = async_helper::callback_wrap; + + template ::value...>::value> + inline async_helper::callback_wrap async_callback(std::function callback) { + static_assert(!referenced_args, "Argument references aren't allowed"); + + using callback_t = std::function; + using callback_args = async_helper::callback_args; + + auto args = new callback_args{}; + args->callback = std::move(callback); + args->destroy_only = false; + memset(&args->handle, 0, sizeof(args->handle)); + args->handle.data = args; + + uv_async_init(Nan::GetCurrentEventLoop(), &args->handle, [](uv_async_t* async) { + auto _args = (callback_args*) async->data; + std::unique_lock destroy_lock(_args->destroy_lock); //This may changed after calling the function (deleted while invoking is an example) + if(!_args->destroy_only || (_args->option_destroy_run && _args->flag_execute)) { + _args->flag_execute = false; + auto arguments = std::move(_args->arguments); //Move the tuple now before it get overridden :) + destroy_lock.unlock(); + async_helper::call_helper(_args->callback, arguments, std::index_sequence_for{}); + destroy_lock.lock(); + } + + if(_args->destroy_only) { + uv_close((uv_handle_t*) (void*) async, [](uv_handle_t* handle) { + delete (callback_args*) handle->data; + }); + } + + }); + + return { + std::make_shared>( + args, + [args](Args&&... invoker_args) { + std::lock_guard lock(args->destroy_lock); + args->flag_execute = true; + args->arguments = std::tuple{std::forward(invoker_args)...}; + uv_async_send(&args->handle); + }, + [args]{ + std::lock_guard lock(args->destroy_lock); + args->destroy_only = true; + uv_async_send(&args->handle); + } + ) + }; + } + + /* lambda edition */ + template , + typename result = typename lambda_info::result> + inline result async_callback(lambda&& lam) { + auto handle = std::make_shared(std::forward(lam)); + return async_callback(lambda_info::wrap(handle)); + } +} \ No newline at end of file diff --git a/native/dist/ext_nan/NanException.h b/native/dist/ext_nan/NanException.h new file mode 100644 index 0000000..61ad480 --- /dev/null +++ b/native/dist/ext_nan/NanException.h @@ -0,0 +1,9 @@ +#pragma once + +#define NAN_THROW_EXCEPTION(type, message) \ +do { \ + auto isolate = Nan::GetCurrentContext()->GetIsolate(); \ + auto exception = v8::Exception::type(v8::String::NewFromUtf8(isolate, message, v8::NewStringType::kNormal).ToLocalChecked()); \ + isolate->ThrowException(exception); \ +} while(0) + diff --git a/native/dist/ext_nan/test/main.cpp b/native/dist/ext_nan/test/main.cpp new file mode 100644 index 0000000..58d1f56 --- /dev/null +++ b/native/dist/ext_nan/test/main.cpp @@ -0,0 +1,2 @@ +#include "../NanEventCallback.h" +#include "../NanException.h" \ No newline at end of file diff --git a/native/dns/.gitignore b/native/dns/.gitignore new file mode 100644 index 0000000..dbb958a --- /dev/null +++ b/native/dns/.gitignore @@ -0,0 +1,3 @@ +.idea/ +cmake-build-* +!exports/*.d.ts \ No newline at end of file diff --git a/native/dns/CMakeLists.txt b/native/dns/CMakeLists.txt new file mode 100644 index 0000000..8ff2ab1 --- /dev/null +++ b/native/dns/CMakeLists.txt @@ -0,0 +1,26 @@ +set(MODULE_NAME "teaclient_dns") + +set(SOURCE_FILES ${SOURCE_FILES} src/resolver.cpp src/types.cpp src/response.cpp utils.cpp) +if (WIN32) + set(SOURCE_FILES ${SOURCE_FILES} src/resolver_windows.cpp) +else() + set(SOURCE_FILES ${SOURCE_FILES} src/resolver_linux.cpp) +endif() + +find_package(Libevent REQUIRED) +include_directories(${LIBEVENT_INCLUDE_DIRS}) + +if(NOT WIN32) + find_package(unbound REQUIRED) +endif() + +add_nodejs_module(${MODULE_NAME} binding.cc ${SOURCE_FILES}) +add_executable(DNS-Test ${SOURCE_FILES} test/main.cpp) + +if (WIN32) + target_link_libraries(${MODULE_NAME} ${LIBEVENT_STATIC_LIBRARIES} Ws2_32.lib Ntdll.lib Dnsapi.lib) + target_link_libraries(DNS-Test ${LIBEVENT_STATIC_LIBRARIES} Ws2_32.lib Ntdll.lib Dnsapi.lib) +else() + target_link_libraries(${MODULE_NAME} unbound::static ${LIBEVENT_STATIC_LIBRARIES} pthread) + target_link_libraries(DNS-Test unbound::static ssl crypto ${LIBEVENT_STATIC_LIBRARIES} pthread) +endif() \ No newline at end of file diff --git a/native/dns/binding.cc b/native/dns/binding.cc new file mode 100644 index 0000000..eb4b385 --- /dev/null +++ b/native/dns/binding.cc @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include + +#include "./src/resolver.h" +#include "./utils.h" + +using namespace std; + +#include "NanException.h" +#include "NanEventCallback.h" + +std::unique_ptr resolver{nullptr}; + +NAN_METHOD(initialize) { + if(resolver) { + Nan::ThrowError("already initialized"); + return; + } + +#ifdef WIN32 + evthread_use_windows_threads(); +#else + evthread_use_pthreads(); +#endif + resolver = make_unique(); + + string error; + if(!resolver->initialize(error, true, true)) { + Nan::ThrowError(error.c_str()); + return; + } +} + +NAN_METHOD(query_connect_address) { + if(!resolver) { + Nan::ThrowError("initialize resolver first!"); + return; + } + + if(info.Length() != 3 || !info[0]->IsString() || !info[1]->IsNumber() || !info[2]->IsFunction()) { + Nan::ThrowError("invalid arguments"); + return; + } + + auto host = Nan::Utf8String{info[0]->ToString()}; + auto port = info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->NumberValue(); + + auto js_callback = make_unique(info[2].As()); + auto begin = chrono::system_clock::now(); + auto callback = Nan::async_callback([js_callback = std::move(js_callback), begin] (bool success, std::string message, tc::dns::ServerAddress response) { + Nan::HandleScope scope{}; + auto isolate = Nan::GetCurrentContext()->GetIsolate(); + + v8::Local argv[1]; + if(!success) { + argv[0] = v8::String::NewFromOneByte(isolate, (uint8_t*) message.c_str()).ToLocalChecked(); + } else { + auto js_data = Nan::New(); + Nan::Set(js_data, + v8::String::NewFromUtf8(isolate, "host").ToLocalChecked(), + v8::String::NewFromUtf8(isolate, response.host.c_str()).ToLocalChecked() + ); + Nan::Set(js_data, + v8::String::NewFromUtf8(isolate, "port").ToLocalChecked(), + Nan::New(response.port) + ); + Nan::Set(js_data, + v8::String::NewFromUtf8(isolate, "timing").ToLocalChecked(), + Nan::New(chrono::floor(chrono::system_clock::now() - begin).count()) + ); + + argv[0] = js_data; + } + js_callback->Call(1, argv); + }).option_destroyed_execute(true); + + tc::dns::cr(*resolver, + tc::dns::ServerAddress{ *host, (uint16_t) port }, + [callback = std::move(callback)] (bool success, std::variant data) mutable { + callback.call_cpy(success, success ? "" : std::get(data), !success ? tc::dns::ServerAddress{"", 0} : std::get(data), false); + }); +} + +#ifndef WIN32 +__attribute__((visibility("default"))) +#endif +NAN_MODULE_INIT(init) { + Nan::Set(target, + v8::String::NewFromUtf8(Nan::GetCurrentContext()->GetIsolate(), "resolve_cr").ToLocalChecked(), + Nan::GetFunction(Nan::New(query_connect_address)).ToLocalChecked() + ); + + Nan::Set(target, + v8::String::NewFromUtf8(Nan::GetCurrentContext()->GetIsolate(), "initialize").ToLocalChecked(), + Nan::GetFunction(Nan::New(initialize)).ToLocalChecked() + ); +} + +NODE_MODULE(MODULE_NAME, init) \ No newline at end of file diff --git a/native/dns/exports/exports.d.ts b/native/dns/exports/exports.d.ts new file mode 100644 index 0000000..80b69a6 --- /dev/null +++ b/native/dns/exports/exports.d.ts @@ -0,0 +1,4 @@ +declare module "teaclient_dns" { + export function resolve_cr(host: string, port: number, callback: (result: string | {host: string, port: number}) => any); + export function initialize(); +} \ No newline at end of file diff --git a/native/dns/src/resolver.cpp b/native/dns/src/resolver.cpp new file mode 100644 index 0000000..227a8ac --- /dev/null +++ b/native/dns/src/resolver.cpp @@ -0,0 +1,328 @@ +#include "./resolver.h" +#include "./response.h" + +#include +#include +#include +#include +#include +#include + +#include /* for TSDNS */ +#ifdef WIN32 + #include + #define SOCK_NONBLOCK (0) + #define MSG_DONTWAIT (0) +#else + #include + #include + #include + #include +#endif + +using namespace std; +using namespace tc::dns; + +Resolver::Resolver() { } + +Resolver::~Resolver() { + this->finalize(); +} + + +bool Resolver::initialize(std::string &error, bool hosts, bool resolv) { + if(this->event.loop_active) + this->finalize(); + + this->event.loop_active = true; + this->event.base = event_base_new(); + if(!this->event.base) { + error = "failed to allcoate event base"; + return false; + } + this->event.loop = std::thread(std::bind(&Resolver::event_loop_runner, this)); + + return this->initialize_platform(error, hosts, resolv); +} + +void Resolver::finalize() { + this->event.loop_active = false; + if(this->event.base) { + auto ret = event_base_loopexit(this->event.base, nullptr); + if(ret != 0) { + cerr << "Failed to exit event base loop: " << ret << endl; + } + } + + { + this->event.condition.notify_one(); + if(this->event.loop.joinable()) + this->event.loop.join(); + } + + { + unique_lock lock(this->request_lock); + auto dns_list = std::move(this->dns_requests); + auto tsdns_list = std::move(this->tsdns_requests); + + for(auto entry : dns_list) { + entry->callback(ResultState::ABORT, 0, nullptr); + this->destroy_dns_request(entry); + } + + for(auto entry : tsdns_list) { + entry->callback(ResultState::ABORT, 0, ""); + this->destroy_tsdns_request(entry); + } + lock.unlock(); + } + + this->finalize_platform(); /* keep the event base allocated until platform depend finalize has been done */ + if(this->event.base) { + event_base_free(this->event.base); + this->event.base = nullptr; + } +} + +void Resolver::event_loop_runner() { + while(true) { + { + unique_lock lock{this->event.lock}; + if(!this->event.loop_active) + break; + + this->event.condition.wait(lock); + if(!this->event.loop_active) + break; + } + + event_base_loop(this->event.base, 0); + } +} + +void Resolver::destroy_tsdns_request(Resolver::tsdns_request *request) { + assert(this_thread::get_id() == this->event.loop.get_id() || !this->event.loop_active); + + { + lock_guard lock{this->request_lock}; + this->tsdns_requests.erase(std::find(this->tsdns_requests.begin(), this->tsdns_requests.end(), request), this->tsdns_requests.end()); + } + + if(request->event_read) { + event_del_noblock(request->event_read); + event_free(request->event_read); + request->event_read = nullptr; + } + + if(request->event_write) { + event_del_noblock(request->event_write); + event_free(request->event_write); + request->event_write = nullptr; + } + + if(request->timeout_event) { + event_del_noblock(request->timeout_event); + event_free(request->timeout_event); + request->timeout_event = nullptr; + } + + if(request->socket > 0) { +#ifndef WIN32 + ::shutdown(request->socket, SHUT_RDWR); + ::close(request->socket); +#else + closesocket(request->socket); +#endif + request->socket = 0; + } + + delete request; +} + +//---------------------- TSDNS +void Resolver::resolve_tsdns(const char *query, const sockaddr_storage& server_address, const std::chrono::microseconds& timeout, const tc::dns::Resolver::tsdns_callback_t &callback) { + /* create the socket */ + auto socket = ::socket(server_address.ss_family, SOCK_STREAM | SOCK_NONBLOCK, 0); + if(socket <= 0) { +#ifdef WIN32 + char buf[1024]; + strerror_s(buf, errno); + std::string strerr{buf}; +#else + std::string strerr{strerror(errno)}; +#endif + callback(ResultState::INITIALISATION_FAILED, -1, "failed to allocate socket: " + to_string(errno) + "/" + strerr); + return; + } + +#ifdef WIN32 + u_long enabled = 0; + auto non_block_rs = ioctlsocket(socket, FIONBIO, &enabled); + if (non_block_rs != NO_ERROR) { +#ifdef WIN32 + char buf[1024]; + strerror_s(buf, errno); + std::string strerr{buf}; +#else + std::string strerr{strerror(errno)}; +#endif + closesocket(socket); + callback(ResultState::INITIALISATION_FAILED, -2, "failed to enable nonblock: " + to_string(errno) + "/" + strerr); + return; + } +#else + int opt = 1; + setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)); +#endif + + auto request = new tsdns_request{}; + + request->resolver = this; + request->callback = callback; + request->socket = (int) socket; + request->timeout_event = evtimer_new(this->event.base, [](evutil_socket_t, short, void *_request) { + auto request = static_cast(_request); + request->resolver->evtimer_tsdns_callback(request); + }, request); + + request->event_read = event_new(this->event.base, socket, EV_READ | EV_PERSIST, [](evutil_socket_t, short, void *_request){ + auto request = static_cast(_request); + request->resolver->event_tsdns_read(request); + }, request); + request->event_write = event_new(this->event.base, socket, EV_WRITE, [](evutil_socket_t, short, void *_request){ + auto request = static_cast(_request); + request->resolver->event_tsdns_write(request); + }, request); + + if(!request->timeout_event || !request->event_write || !request->event_read) { + callback(ResultState::INITIALISATION_FAILED, -3, ""); + this->destroy_tsdns_request(request); + return; + } + + request->write_buffer = query; + request->write_buffer += "\n\r\r\r\n"; + + int result = ::connect(socket, reinterpret_cast (&server_address), sizeof(server_address)); + if (result < 0) { +#ifdef WIN32 + auto error = WSAGetLastError(); + + if(error != WSAEWOULDBLOCK) { + char* s = nullptr; + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &s, + 0, + nullptr + ); + + std::string message{s}; + LocalFree(s); + + callback(ResultState::TSDNS_CONNECTION_FAIL, -1, "Failed to connect: " + message); + this->destroy_tsdns_request(request); + } +#else + if(errno != EINPROGRESS) { + callback(ResultState::TSDNS_CONNECTION_FAIL, -1, "Failed to connect with code: " + to_string(errno) + "/" + strerror(errno)); + this->destroy_tsdns_request(request); + return; + } +#endif + } + + event_add(request->event_write, nullptr); + event_add(request->event_read, nullptr); + + { + auto seconds = chrono::floor(timeout); + auto microseconds = chrono::ceil(timeout - seconds); + + timeval tv{(long) seconds.count(), (long) microseconds.count()}; + auto errc = event_add(request->timeout_event, &tv); + + //TODO: Check for error + } + + { + lock_guard lock{this->request_lock}; + this->tsdns_requests.push_back(request); + } + + /* Activate the event loop */ + this->event.condition.notify_one(); +} + +void Resolver::evtimer_tsdns_callback(Resolver::tsdns_request *request) { + request->callback(ResultState::DNS_TIMEOUT, 0, ""); + this->destroy_tsdns_request(request); +} + +void Resolver::event_tsdns_read(Resolver::tsdns_request *request) { + int64_t buffer_length = 1024; + char buffer[1024]; + + buffer_length = recv(request->socket, buffer, (int) buffer_length, MSG_DONTWAIT); + if(buffer_length < 0) { +#ifdef WIN32 + auto error = WSAGetLastError(); + if(error != WSAEWOULDBLOCK) + return; + request->callback(ResultState::TSDNS_CONNECTION_FAIL, -2, "read failed: " + to_string(error)); +#else + if(errno == EAGAIN) + return; + request->callback(ResultState::TSDNS_CONNECTION_FAIL, -2, "read failed: " + to_string(errno) + "/" + strerror(errno)); +#endif + this->destroy_tsdns_request(request); + return; + } else if(buffer_length == 0) { + if(request->read_buffer.empty()) { + request->callback(ResultState::TSDNS_EMPTY_RESPONSE, 0, ""); + } else { + request->callback(ResultState::SUCCESS, 0, request->read_buffer); + } + this->destroy_tsdns_request(request); + return; + } + + lock_guard lock{request->buffer_lock}; + request->read_buffer.append(buffer, buffer_length); +} + +void Resolver::event_tsdns_write(Resolver::tsdns_request *request) { + lock_guard lock{request->buffer_lock}; + if(request->write_buffer.empty()) + return; + + auto written = send(request->socket, request->write_buffer.data(), (int) min(request->write_buffer.size(), 1024UL), MSG_DONTWAIT); + if(written < 0) { +#ifdef WIN32 + auto error = WSAGetLastError(); + if(error != WSAEWOULDBLOCK) + return; + request->callback(ResultState::TSDNS_CONNECTION_FAIL, -4, "write failed: " + to_string(error)); +#else + if(errno == EAGAIN) + return; + request->callback(ResultState::TSDNS_CONNECTION_FAIL, -4, "write failed: " + to_string(errno) + "/" + strerror(errno)); +#endif + this->destroy_tsdns_request(request); + return; + } else if(written == 0) { + request->callback(ResultState::TSDNS_CONNECTION_FAIL, -5, "remote peer hang up"); + this->destroy_tsdns_request(request); + return; + } + + if(written == request->write_buffer.size()) + request->write_buffer.clear(); + else { + request->write_buffer = request->write_buffer.substr(written); + event_add(request->event_write, nullptr); + } +} \ No newline at end of file diff --git a/native/dns/src/resolver.h b/native/dns/src/resolver.h new file mode 100644 index 0000000..30274a9 --- /dev/null +++ b/native/dns/src/resolver.h @@ -0,0 +1,223 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "./types.h" +#ifdef WIN32 + #include +#else + struct ub_ctx; +#endif + +namespace tc::dns { + namespace response { + class DNSHeader; + class DNSQuery; + class DNSResourceRecords; + } + + struct DNSResponseData { +#ifdef WIN32 + bool wide_string{false}; + DNS_QUERY_RESULT data; +#else + uint8_t* buffer{nullptr}; + size_t length{0}; + + std::string parse_dns_dn(std::string& /* error */, size_t& /* index */, bool /* compression allowed */); +#endif + + ~DNSResponseData(); + }; + + class Resolver; + class DNSResponse { + friend class Resolver; + public: + typedef std::vector> rr_list_t; + typedef std::vector> q_list_t; + + DNSResponse(const DNSResponse&) = delete; + DNSResponse(DNSResponse&&) = delete; + + bool parse(std::string& /* error */); + +#ifndef WIN32 + [[nodiscard]] inline const std::string why_bogus() const { return this->bogus; } + + [[nodiscard]] inline const uint8_t* packet_data() const { return this->data->buffer; } + [[nodiscard]] inline size_t packet_length() const { return this->data->length; } + + [[nodiscard]] inline bool is_secure() const { return this->secure_state > 0; } + [[nodiscard]] inline bool is_secure_dnssec() const { return this->secure_state == 2; } + + [[nodiscard]] response::DNSHeader header() const; +#endif + [[nodiscard]] q_list_t queries() const { return this->parsed_queries; } + [[nodiscard]] rr_list_t answers() const { return this->parsed_answers; } + [[nodiscard]] rr_list_t authorities() const { return this->parsed_authorities; } + [[nodiscard]] rr_list_t additionals() const { return this->parsed_additionals; } + private: +#ifndef WIN32 + DNSResponse(uint8_t /* secure state */, const char* /* bogus */, void* /* packet */, size_t /* length */); + + std::shared_ptr parse_rr(std::string& /* error */, size_t& index, bool /* compression allowed dn */); + + std::string bogus; + uint8_t secure_state{0}; +#else + DNSResponse(std::shared_ptr); +#endif + std::shared_ptr data{nullptr}; + + bool is_parsed{false}; + std::string parse_error{}; + + q_list_t parsed_queries; + rr_list_t parsed_answers; + rr_list_t parsed_authorities; + rr_list_t parsed_additionals; + }; + + class Resolver { + public: + struct ResultState { + enum value : uint8_t { + SUCCESS = 0, + + INITIALISATION_FAILED = 0x01, + + DNS_TIMEOUT = 0x10, + DNS_FAIL = 0x11, /* error detail is a DNS error code */ + DNS_API_FAIL = 0x12, + + TSDNS_CONNECTION_FAIL = 0x20, + TSDNS_EMPTY_RESPONSE = 0x21, + + ABORT = 0xFF /* request has been aborted */ + }; + }; + + typedef std::function /* response */)> dns_callback_t; + typedef std::function tsdns_callback_t; + + Resolver(); + virtual ~Resolver(); + + bool initialize(std::string& /* error */, bool /* use hosts */, bool /* use resolv */); + void finalize(); + + void resolve_dns(const char* /* name */, const rrtype::value& /* rrtype */, const rrclass::value& /* rrclass */, const std::chrono::microseconds& /* timeout */, const dns_callback_t& /* callback */); + void resolve_tsdns(const char* /* name */, const sockaddr_storage& /* server */, const std::chrono::microseconds& /* timeout */, const tsdns_callback_t& /* callback */); + private: +#ifdef WIN32 + struct dns_request; + struct dns_old_request_data { + /* request might me nullptr if its beeing timeouted */ + struct dns_request* request{nullptr}; /* protected by lock */ + std::mutex* lock{nullptr}; + }; + + struct { + HMODULE libhandle{nullptr}; + + DNS_STATUS (*DnsQueryEx)( + _In_ PDNS_QUERY_REQUEST pQueryRequest, + _Inout_ PDNS_QUERY_RESULT pQueryResults, + _Inout_opt_ PDNS_QUERY_CANCEL pCancelHandle + ) = nullptr; + + DNS_STATUS (*DnsCancelQuery)( + _In_ PDNS_QUERY_CANCEL pCancelHandle + ) = nullptr; + } dnsapi; +#endif + + struct dns_request { + Resolver* resolver{nullptr}; + + std::string host; + dns::rrtype::value rrtype{dns::rrtype::Unassigned}; + dns::rrclass::value rrclass{dns::rrclass::IN}; + + dns_callback_t callback{}; +#ifdef WIN32 + std::wstring whost; + + /* windows 8 or newer */ + DNS_QUERY_REQUEST dns_query; + DNS_QUERY_RESULT dns_result; + DNS_QUERY_CANCEL dns_cancel; + + /* for old stuff */ + //std::thread resolve_thread; + std::mutex* threaded_lock{nullptr}; + struct dns_old_request_data* thread_data{nullptr}; /* protected by threaded_lock */ +#else + + int ub_id{0}; + struct ::event* register_event{nullptr}; +#endif + struct ::event* timeout_event{nullptr}; + struct ::event* processed_event{nullptr}; + }; + +#ifndef WIN32 + struct ub_ctx* ub_ctx = nullptr; +#endif + struct tsdns_request { + Resolver* resolver{nullptr}; + + int socket{0}; + + struct ::event* timeout_event{nullptr}; + struct ::event* event_read{nullptr}; + struct ::event* event_write{nullptr}; + + std::mutex buffer_lock{}; + std::string write_buffer{}; + std::string read_buffer{}; + + tsdns_callback_t callback{}; + }; + + struct { + bool loop_active{false}; + std::condition_variable condition{}; + std::mutex lock{}; + std::thread loop{}; + event_base* base = nullptr; + } event; + + + std::vector tsdns_requests{}; + std::vector dns_requests{}; + std::recursive_mutex request_lock{}; /* this is recursive because due to the instance callback resolve_dns could be called recursively */ + + bool initialize_platform(std::string& /* error */, bool /* use hosts */, bool /* use resolv */); + void finalize_platform(); + + void destroy_dns_request(dns_request*); + void destroy_tsdns_request(tsdns_request*); + + void event_loop_runner(); + + void evtimer_dns_callback(dns_request* /* request */); +#ifndef WIN32 + void ub_callback(dns_request* /* request */, int /* rcode */, void* /* packet */, int /* packet_len */, int /* sec */, char* /* why_bogus */); +#else + void dns_callback(dns_request* /* request */); +#endif + + void evtimer_tsdns_callback(tsdns_request* /* request */); + void event_tsdns_write(tsdns_request* /* request */); + void event_tsdns_read(tsdns_request* /* request */); + + }; +} \ No newline at end of file diff --git a/native/dns/src/resolver_linux.cpp b/native/dns/src/resolver_linux.cpp new file mode 100644 index 0000000..5df85c8 --- /dev/null +++ b/native/dns/src/resolver_linux.cpp @@ -0,0 +1,387 @@ +#include "./resolver.h" +#include "./response.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* for TSDNS */ +#include + +using namespace std; +using namespace tc::dns; + +bool Resolver::initialize_platform(std::string &error, bool hosts, bool resolv) { + this->ub_ctx = ub_ctx_create_event(this->event.base); + if(!this->ub_ctx) { + this->finalize(); + error = "failed to create ub context"; + return false; + } + + /* Add /etc/hosts */ + auto err = !hosts ? 0 : ub_ctx_hosts((struct ub_ctx*) this->ub_ctx, nullptr); + if(err != 0) { + cerr << "Failed to add hosts file: " << ub_strerror(err) << endl; + } + + /* Add resolv.conf */ + err = !resolv ? 0 : ub_ctx_resolvconf((struct ub_ctx*) this->ub_ctx, nullptr); + if(err != 0) { + cerr << "Failed to add hosts file: " << ub_strerror(err) << endl; + } + + return true; +} + +void Resolver::finalize_platform() { + ub_ctx_delete((struct ub_ctx*) this->ub_ctx); + this->ub_ctx = nullptr; +} + +//Call only within the event loop! +void Resolver::destroy_dns_request(Resolver::dns_request *request) { + assert(this_thread::get_id() == this->event.loop.get_id() || !this->event.loop_active); + + { + lock_guard lock{this->request_lock}; + this->dns_requests.erase(std::find(this->dns_requests.begin(), this->dns_requests.end(), request), this->dns_requests.end()); + } + + if(!this->event.loop_active) + ub_cancel(this->ub_ctx, request->ub_id); + + if(request->register_event) { + event_del_noblock(request->register_event); + event_free(request->register_event); + request->register_event = nullptr; + } + + if(request->timeout_event) { + event_del_noblock(request->timeout_event); + event_free(request->timeout_event); + request->timeout_event = nullptr; + } + delete request; +} + +//--------------- DNS +void Resolver::resolve_dns(const char *name, const rrtype::value &rrtype, const rrclass::value &rrclass, const std::chrono::microseconds& timeout, const dns_callback_t& callback) { + if(!this->event.loop_active) { + callback(ResultState::INITIALISATION_FAILED, 3, nullptr); + return; + } + + auto request = new dns_request{}; + request->resolver = this; + + request->callback = callback; + request->host = name; + request->rrtype = rrtype; + request->rrclass = rrclass; + + request->timeout_event = evtimer_new(this->event.base, [](evutil_socket_t, short, void *_request) { + auto request = static_cast(_request); + request->resolver->evtimer_dns_callback(request); + }, request); + + request->register_event = evuser_new(this->event.base, [](evutil_socket_t, short, void *_request) { + auto request = static_cast(_request); + + auto errc = ub_resolve_event(request->resolver->ub_ctx, request->host.c_str(), (int) request->rrtype, (int) request->rrclass, (void*) request, [](void* _request, int a, void* b, int c, int d, char* e) { + auto request = static_cast(_request); + request->resolver->ub_callback(request, a, b, c, d, e); + }, &request->ub_id); + + if(errc != 0) { + request->callback(ResultState::INITIALISATION_FAILED, errc, nullptr); + request->resolver->destroy_dns_request(request); + } + }, request); + + if(!request->timeout_event || !request->register_event) { + callback(ResultState::INITIALISATION_FAILED, 2, nullptr); + + if(request->timeout_event) + event_free(request->timeout_event); + + if(request->register_event) + event_free(request->register_event); + + delete request; + return; + } + + /* + * Lock here all requests so the event loop cant already delete the request + */ + unique_lock rlock{this->request_lock}; + + { + auto errc = event_add(request->timeout_event, nullptr); + //TODO: Check for error + + evuser_trigger(request->register_event); + } + + { + auto seconds = chrono::floor(timeout); + auto microseconds = chrono::ceil(timeout - seconds); + + timeval tv{seconds.count(), microseconds.count()}; + auto errc = event_add(request->timeout_event, &tv); + + //TODO: Check for error + } + + this->dns_requests.push_back(request); + rlock.unlock(); + + /* Activate the event loop */ + this->event.condition.notify_one(); +} + +void Resolver::evtimer_dns_callback(tc::dns::Resolver::dns_request *request) { + if(request->ub_id > 0) { + auto errc = ub_cancel(this->ub_ctx, request->ub_id); + if(errc != 0) { + cerr << "Failed to cancel DNS request " << request->ub_id << " after timeout (" << errc << "/" << ub_strerror(errc) << ")!" << endl; + } + } + + request->callback(ResultState::DNS_TIMEOUT, 0, nullptr); + this->destroy_dns_request(request); +} + +void Resolver::ub_callback(dns_request* request, int rcode, void *packet, int packet_length, int sec, char *why_bogus) { + if(rcode != 0) { + request->callback(ResultState::DNS_FAIL, rcode, nullptr); + } else { + auto callback = request->callback; + auto data = std::unique_ptr(new DNSResponse{(uint8_t) sec, why_bogus, packet, (size_t) packet_length}); + callback(ResultState::SUCCESS, 0, std::move(data)); + } + + this->destroy_dns_request(request); +} + +thread_local std::vector visited_links; +std::string DNSResponseData::parse_dns_dn(std::string &error, size_t &index, bool allow_compression) { + if(allow_compression) { + visited_links.clear(); + visited_links.reserve(8); + + if(std::find(visited_links.begin(), visited_links.end(), index) != visited_links.end()) { + error = "circular link detected"; + return ""; + } + visited_links.push_back(index); + } + + error.clear(); + + string result; + result.reserve(256); //Max length is 253 + + while(true) { + if(index + 1 > this->length) { + error = "truncated data (missing code)"; + goto exit; + } + + auto code = this->buffer[index++]; + if(code == 0) break; + + if((code >> 6U) == 3) { + if(!allow_compression) { + error = "found link, but links are not allowed"; + goto exit; + } + + auto lower_addr = this->buffer[index++]; + if(index + 1 > this->length) { + error = "truncated data (missing lower link address)"; + goto exit; + } + + size_t addr = ((code & 0x3FU) << 8U) | lower_addr; + if(addr >= this->length) { + error = "invalid link address"; + goto exit; + } + auto tail = this->parse_dns_dn(error, addr, true); + if(!error.empty()) + goto exit; + + if(!result.empty()) + result += "." + tail; + else + result = tail; + break; + } else { + if(code > 63) { + error = "max domain label length is 63 characters"; + goto exit; + } + + if(!result.empty()) + result += "."; + + if(index + code >= this->length) { + error = "truncated data (domain label)"; + goto exit; + } + + result.append((const char*) (this->buffer + index), code); + index += code; + } + } + + exit: + if(allow_compression) visited_links.pop_back(); + return result; +} + +DNSResponseData::~DNSResponseData() { + ::free(this->buffer); +} + +DNSResponse::DNSResponse(uint8_t secure_state, const char* bogus, void *packet, size_t size) { + this->bogus = bogus ? std::string{bogus} : std::string{"packet is secure"}; + this->secure_state = secure_state; + + this->data = make_shared(); + this->data->buffer = (uint8_t*) malloc(size); + this->data->length = size; + + memcpy(this->data->buffer, packet, size); +} + +response::DNSHeader DNSResponse::header() const { + return response::DNSHeader{this}; +} + +bool DNSResponse::parse(std::string &error) { + if(this->is_parsed) { + error = this->parse_error; + return error.empty(); + } + error.clear(); + this->is_parsed = true; + + auto header = this->header(); + size_t index = 12; /* 12 bits for the header */ + + { + auto count = header.query_count(); + this->parsed_queries.reserve(count); + + for(size_t idx = 0; idx < count; idx++) { + auto dn = this->data->parse_dns_dn(error, index, true); + if(!error.empty()) { + error = "failed to parse query " + to_string(idx) + " dn: " + error; // NOLINT(performance-inefficient-string-concatenation) + goto error_exit; + } + + if(index + 4 > this->packet_length()) { + error = "truncated data for query " + to_string(index); + goto error_exit; + } + + auto type = (rrtype::value) ntohs(*(uint16_t*) (this->data->buffer + index)); + index += 2; + + auto klass = (rrclass::value) ntohs(*(uint16_t*) (this->data->buffer + index)); + index += 2; + + this->parsed_queries.emplace_back(new response::DNSQuery{dn, type, klass}); + } + } + + { + auto count = header.answer_count(); + this->parsed_answers.reserve(count); + + for(size_t idx = 0; idx < count; idx++) { + this->parsed_answers.push_back(this->parse_rr(error, index, true)); + if(!error.empty()) { + error = "failed to parse answer " + to_string(idx) + ": " + error; // NOLINT(performance-inefficient-string-concatenation) + goto error_exit; + } + } + } + + { + auto count = header.authority_count(); + this->parsed_authorities.reserve(count); + + for(size_t idx = 0; idx < count; idx++) { + this->parsed_authorities.push_back(this->parse_rr(error, index, true)); + if(!error.empty()) { + error = "failed to parse authority " + to_string(idx) + ": " + error; // NOLINT(performance-inefficient-string-concatenation) + goto error_exit; + } + } + } + + { + auto count = header.additional_count(); + this->parsed_additionals.reserve(count); + + for(size_t idx = 0; idx < count; idx++) { + this->parsed_additionals.push_back(this->parse_rr(error, index, true)); + if(!error.empty()) { + error = "failed to parse additional " + to_string(idx) + ": " + error; // NOLINT(performance-inefficient-string-concatenation) + goto error_exit; + } + } + } + + return true; + + error_exit: + this->parsed_queries.clear(); + this->parsed_answers.clear(); + this->parsed_authorities.clear(); + this->parsed_additionals.clear(); + return false; +} + +std::shared_ptr DNSResponse::parse_rr(std::string &error, size_t &index, bool allow_compressed) { + auto dn = this->data->parse_dns_dn(error, index, allow_compressed); + if(!error.empty()) { + error = "failed to parse rr dn: " + error; // NOLINT(performance-inefficient-string-concatenation) + return nullptr; + } + + if(index + 10 > this->packet_length()) { + error = "truncated header"; + return nullptr; + } + + auto type = (rrtype::value) ntohs(*(uint16_t*) (this->data->buffer + index)); + index += 2; + + auto klass = (rrclass::value) ntohs(*(uint16_t*) (this->data->buffer + index)); + index += 2; + + auto ttl = ntohl(*(uint32_t*) (this->data->buffer + index)); + index += 4; + + auto payload_length = ntohs(*(uint16_t*) (this->data->buffer + index)); + index += 2; + + if(index + payload_length > this->packet_length()) { + error = "truncated body"; + return nullptr; + } + + auto response = std::shared_ptr(new response::DNSResourceRecords{this->data, index, payload_length, ttl, dn, type, klass}); + index += payload_length; + return response; +} diff --git a/native/dns/src/resolver_windows.cpp b/native/dns/src/resolver_windows.cpp new file mode 100644 index 0000000..728e1db --- /dev/null +++ b/native/dns/src/resolver_windows.cpp @@ -0,0 +1,308 @@ +// +// Created by WolverinDEV on 25/10/2019. +// + +#include +#include +#include "./resolver.h" +#include "./response.h" +#include "resolver.h" + +using namespace std; +using namespace tc::dns; + +bool Resolver::initialize_platform(std::string &error, bool hosts, bool resolvconf) { + this->dnsapi.libhandle = LoadLibraryA("dnsapi.dll"); + + /* windows 8 or newer */ + if(this->dnsapi.libhandle) { + this->dnsapi.DnsCancelQuery = (decltype(this->dnsapi.DnsCancelQuery)) GetProcAddress(this->dnsapi.libhandle, "DnsCancelQuery"); + this->dnsapi.DnsQueryEx = (decltype(this->dnsapi.DnsQueryEx)) GetProcAddress(this->dnsapi.libhandle, "DnsQueryEx"); + + if(!this->dnsapi.DnsCancelQuery || !this->dnsapi.DnsQueryEx) { + this->dnsapi.DnsQueryEx = nullptr; + this->dnsapi.DnsCancelQuery = nullptr; + + FreeLibrary(this->dnsapi.libhandle); + this->dnsapi.libhandle = nullptr; + } + } + + return true; +} + +void Resolver::finalize_platform() { + if(this->dnsapi.libhandle) + FreeLibrary(this->dnsapi.libhandle); + this->dnsapi.libhandle = nullptr; + this->dnsapi.DnsQueryEx = nullptr; + this->dnsapi.DnsCancelQuery = nullptr; +} + +DWORD CreateDnsServerList( + _In_ PWSTR ServerIp, + _Out_ PDNS_ADDR_ARRAY DnsServerList +) +{ + DWORD Error = ERROR_SUCCESS; + SOCKADDR_STORAGE SockAddr; + INT AddressLength; + WSADATA wsaData; + + ZeroMemory(DnsServerList, sizeof(*DnsServerList)); + + Error = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (Error != 0) + { + wprintf(L"WSAStartup failed with %d\n", Error); + return Error; + } + + AddressLength = sizeof(SockAddr); + Error = WSAStringToAddressW(ServerIp, + AF_INET, + NULL, + (LPSOCKADDR)&SockAddr, + &AddressLength); + if (Error != ERROR_SUCCESS) + { + + AddressLength = sizeof(SockAddr); + Error = WSAStringToAddressW(ServerIp, + AF_INET6, + NULL, + (LPSOCKADDR)&SockAddr, + &AddressLength); + } + + if (Error != ERROR_SUCCESS) + { + wprintf(L"WSAStringToAddress for %s failed with error %d\n", + ServerIp, + Error); + goto exit; + } + + DnsServerList->MaxCount = 1; + DnsServerList->AddrCount = 1; + CopyMemory(DnsServerList->AddrArray[0].MaxSa, &SockAddr, DNS_ADDR_MAX_SOCKADDR_LENGTH); + + exit: + + WSACleanup(); + return Error; +} + +void Resolver::destroy_dns_request(Resolver::dns_request *request) { + assert(this_thread::get_id() == this->event.loop.get_id() || !this->event.loop_active); + + if(request->threaded_lock) { + unique_lock lock{*request->threaded_lock}; + if(request->thread_data) { + request->thread_data->request = nullptr; + request->thread_data = nullptr; + } else { + //Threaded data has been deleted now delete the lock + delete request->threaded_lock; + request->threaded_lock = nullptr; + } + } + + { + lock_guard lock{this->request_lock}; + this->dns_requests.erase(std::find(this->dns_requests.begin(), this->dns_requests.end(), request), this->dns_requests.end()); + } + + if(!this->event.loop_active && this->dnsapi.DnsQueryEx) + this->dnsapi.DnsCancelQuery(&request->dns_cancel); + + if(request->dns_result.pQueryRecords) + DnsRecordListFree(request->dns_result.pQueryRecords, DnsFreeRecordList); + + if(request->processed_event) { + event_del_noblock(request->processed_event); + event_free(request->processed_event); + request->processed_event = nullptr; + } + + if(request->timeout_event) { + event_del_noblock(request->timeout_event); + event_free(request->timeout_event); + request->timeout_event = nullptr; + } + + delete request; +} + +void Resolver::resolve_dns(const char *name, const rrtype::value &type, const rrclass::value &klass, const chrono::microseconds &timeout, const tc::dns::Resolver::dns_callback_t &callback) { + if(!this->event.loop_active) { + callback(ResultState::INITIALISATION_FAILED, 3, nullptr); + return; + } + + auto request = new dns_request{}; + request->resolver = this; + + request->host = name; + request->whost = std::wstring{request->host.begin(), request->host.end()}; + request->rrtype = type; + request->rrclass = klass; + request->callback = callback; + + memset(&request->dns_cancel, 0, sizeof(request->dns_cancel)); + memset(&request->dns_query, 0, sizeof(request->dns_query)); + memset(&request->dns_result, 0, sizeof(request->dns_result)); + request->dns_result.Version = DNS_QUERY_REQUEST_VERSION1; + + /* newer method */ + if(this->dnsapi.DnsQueryEx) { + request->dns_query.Version = DNS_QUERY_REQUEST_VERSION1; + request->dns_query.pQueryContext = request; + request->dns_query.QueryName = request->whost.c_str(); + request->dns_query.QueryType = type; + request->dns_query.pQueryCompletionCallback = [](void* _request, PDNS_QUERY_RESULT result) { + auto request = static_cast(_request); + assert(result == &request->dns_result); + evuser_trigger(request->processed_event); + request->resolver->event.condition.notify_one(); + }; + + /* + Error = CreateDnsServerList(ServerIp, &DnsServerList); + + if (Error != ERROR_SUCCESS) + { + wprintf(L"CreateDnsServerList failed with error %d", Error); + goto exit; + } + + DnsQueryRequest.pDnsServerList = &DnsServerList; + */ + } else { + request->threaded_lock = new std::mutex{}; + request->thread_data = new dns_old_request_data{}; + request->thread_data->request = request; + request->thread_data->lock = request->threaded_lock; + } + + request->timeout_event = evtimer_new(this->event.base, [](evutil_socket_t, short, void *_request) { + auto request = static_cast(_request); + request->resolver->evtimer_dns_callback(request); + }, request); + + request->processed_event = evuser_new(this->event.base, [](evutil_socket_t, short, void *_request) { + auto request = static_cast(_request); + request->resolver->dns_callback(request); + }, request); + + if(!request->timeout_event || !request->processed_event) { + if(request->timeout_event) + event_free(request->timeout_event); + + if(request->processed_event) + event_free(request->processed_event); + + callback(ResultState::INITIALISATION_FAILED, 2, nullptr); + return; + } + + unique_lock rlock{this->request_lock}; + if(this->dnsapi.DnsQueryEx) { + auto error = this->dnsapi.DnsQueryEx(&request->dns_query, &request->dns_result, &request->dns_cancel); + if (error != DNS_REQUEST_PENDING) { + rlock.unlock(); + + evuser_trigger(request->processed_event); + return; + } + } else { + auto data = request->thread_data; + + std::string host_str{name}; + auto t = std::thread([data, host_str, type]{ + ULONG64 query_options{0}; + + PDNS_RECORD query_results{nullptr}; + auto error = DnsQuery_A(host_str.c_str(), type, (DWORD) query_options, nullptr, &query_results, nullptr); + + unique_lock lock{*data->lock}; + if(!data->request) { + //We timed out, and we should do the lock delete stuff + lock.unlock(); + + delete data->lock; + delete data; + } + + data->request->dns_result.pQueryRecords = query_results; + data->request->dns_result.QueryOptions = query_options; + data->request->dns_result.QueryStatus = error; + data->request->thread_data = nullptr; + evuser_trigger(data->request->processed_event); + delete data; + }); + t.detach(); + } + + { + auto seconds = chrono::floor(timeout); + auto microseconds = chrono::ceil(timeout - seconds); + + timeval tv{(long) seconds.count(), (long) microseconds.count()}; + auto errc = event_add(request->timeout_event, &tv); + + //TODO: Check for error + } + + this->dns_requests.push_back(request); + this->event.condition.notify_one(); +} + +void Resolver::evtimer_dns_callback(Resolver::dns_request *request) { + if(this->dnsapi.DnsQueryEx) { + auto err = this->dnsapi.DnsCancelQuery(&request->dns_cancel); + if(err != 0) + std::cerr << "Failed to cancel timeouted DNS request" << std::endl; + } + + request->callback(ResultState::DNS_TIMEOUT, 0, nullptr); + this->destroy_dns_request(request); +} + +void Resolver::dns_callback(Resolver::dns_request *request) { + if(request->dns_result.QueryStatus != ERROR_SUCCESS) { + auto status = request->dns_result.QueryStatus; + if(status >= DNS_ERROR_RESPONSE_CODES_BASE && status <= DNS_ERROR_RCODE_LAST) + request->callback(ResultState::DNS_FAIL, request->dns_result.QueryStatus - DNS_ERROR_RESPONSE_CODES_BASE, nullptr); + else + request->callback(ResultState::DNS_API_FAIL, request->dns_result.QueryStatus, nullptr); + } else { + auto callback = request->callback; + auto data = make_shared(); + data->wide_string = this->dnsapi.DnsQueryEx != nullptr; + memcpy(&data->data, &request->dns_result, sizeof(request->dns_result)); + request->dns_result.pQueryRecords = nullptr; + callback(ResultState::SUCCESS, 0, std::unique_ptr(new DNSResponse{data})); + } + this->destroy_dns_request(request); +} + +DNSResponseData::~DNSResponseData() { + if(this->data.pQueryRecords) + DnsRecordListFree(this->data.pQueryRecords, DnsFreeRecordList); +} + +DNSResponse::DNSResponse(std::shared_ptr data) : data{std::move(data)} {} + +bool DNSResponse::parse(std::string &error) { + auto head = this->data->data.pQueryRecords; + if(!head) { + error = "empty response"; + return false; + } + + do { + this->parsed_answers.emplace_back(new response::DNSResourceRecords{this->data, head}); + } while((head = head->pNext)); + return true; +} \ No newline at end of file diff --git a/native/dns/src/response.cpp b/native/dns/src/response.cpp new file mode 100644 index 0000000..7691d48 --- /dev/null +++ b/native/dns/src/response.cpp @@ -0,0 +1,181 @@ +#include "./response.h" +#include "./resolver.h" + +#include +#include +#ifdef WIN32 + #include + #include + #include + #include + #include +#else + #include + #include +#endif + +using namespace tc::dns::response; +using namespace tc::dns::response::rrparser; + +#ifndef WIN32 +uint16_t DNSHeader::field(int index) const { + return ((uint16_t*) this->response->packet_data())[index]; +} + +DNSResourceRecords::DNSResourceRecords(std::shared_ptr packet, size_t payload_offset, size_t length, uint32_t ttl, std::string name, rrtype::value type, rrclass::value klass) + : offset{payload_offset}, length{length}, ttl{ttl}, name{std::move(name)}, type{type}, klass{klass} { + this->data = std::move(packet); +} + +const uint8_t* DNSResourceRecords::payload_data() const { + return this->data->buffer + this->offset; +} +#else +DNSResourceRecords::DNSResourceRecords(std::shared_ptr data, PDNS_RECORDA rdata) : nrecord{rdata}, data{std::move(data)} { } +bool DNSResourceRecords::is_wide_string() const { + return this->data->wide_string; +} +#endif + +bool A::is_valid() { +#ifdef WIN32 + return true; +#else + return this->handle->payload_length() == 4; +#endif +} + +in_addr A::address() { +#ifdef WIN32 + in_addr result{}; + result.S_un.S_addr = this->handle->native_record()->Data.A.IpAddress; + return result; +#else + //TODO: Attention: Unaligned access + return {*(uint32_t*) this->handle->payload_data()}; +#endif +} + +std::string A::address_string() { +#ifdef WIN32 + struct in_addr address = this->address(); + char buffer[17]; + RtlIpv4AddressToStringA(&address, buffer); + return std::string{buffer}; +#else + auto _1 = this->handle->payload_data()[0], + _2 = this->handle->payload_data()[1], + _3 = this->handle->payload_data()[2], + _4 = this->handle->payload_data()[3]; + return std::to_string(_1) + "." + std::to_string(_2) + "." + std::to_string(_3) + "." + std::to_string(_4); +#endif +} + +//---------------- AAAA +#ifdef WIN32 +bool AAAA::is_valid() { + return true; +} + +std::string AAAA::address_string() { + struct in6_addr address = this->address(); + char buffer[47]; + RtlIpv6AddressToStringA(&address, buffer); //Supported for Win7 as well and not only above 8.1 like inet_ntop + return std::string{buffer}; +} + +in6_addr AAAA::address() { + in6_addr result{}; + memcpy(result.u.Byte, this->handle->native_record()->Data.AAAA.Ip6Address.IP6Byte, 16); + return result; +} +#else +bool AAAA::is_valid() { + return this->handle->payload_length() == 16; +} + +std::string AAAA::address_string() { + auto address = this->address(); + + char buffer[INET6_ADDRSTRLEN]; + if(!inet_ntop(AF_INET6, (void*) &address, buffer, INET6_ADDRSTRLEN)) return ""; + return std::string(buffer); +} + +in6_addr AAAA::address() { + return { + .__in6_u = { + .__u6_addr32 = { + //TODO: Attention unaligned memory access + ((uint32_t*) this->handle->payload_data())[0], + ((uint32_t*) this->handle->payload_data())[1], + ((uint32_t*) this->handle->payload_data())[2], + ((uint32_t*) this->handle->payload_data())[3] + } + } + }; +} +#endif + +//---------------- SRV +#ifdef WIN32 +bool SRV::is_valid() { return true; } +std::string SRV::target_hostname() { + if(this->handle->is_wide_string()) { + auto result = std::wstring{ ((PDNS_RECORDW) this->handle->native_record())->Data.Srv.pNameTarget }; + return std::string{result.begin(), result.end()}; + } else { + return std::string{ this->handle->native_record()->Data.Srv.pNameTarget }; + } +} +uint16_t SRV::priority() { return this->handle->native_record()->Data.SRV.wPriority; } +uint16_t SRV::weight() { return this->handle->native_record()->Data.SRV.wWeight; } +uint16_t SRV::target_port() { return this->handle->native_record()->Data.SRV.wPort; } +#else +bool SRV::is_valid() { + if(this->handle->payload_length() < 7) + return false; + size_t index = this->handle->payload_offset() + 6; + std::string error{}; + this->handle->dns_data()->parse_dns_dn(error, index, true); + return error.empty(); +} + +std::string SRV::target_hostname() { + size_t index = this->handle->payload_offset() + 6; + std::string error{}; + return this->handle->dns_data()->parse_dns_dn(error, index, true); +} + + +uint16_t SRV::priority() { return ntohs(((uint16_t*) this->handle->payload_data())[0]); } +uint16_t SRV::weight() { return ntohs(((uint16_t*) this->handle->payload_data())[1]); } +uint16_t SRV::target_port() { return ntohs(((uint16_t*) this->handle->payload_data())[2]); } +#endif + +//---------------- All types with a name +bool named_base::is_valid() { +#ifdef WIN32 + return true; +#else + size_t index = this->handle->payload_offset(); + std::string error{}; + this->handle->dns_data()->parse_dns_dn(error, index, true); + return error.empty(); +#endif +} + +std::string named_base::name() { +#ifdef WIN32 + if(this->handle->is_wide_string()) { + auto result = std::wstring{ ((PDNS_RECORDW) this->handle->native_record())->Data.Cname.pNameHost }; + return std::string{result.begin(), result.end()}; + } else { + return std::string{ this->handle->native_record()->Data.Cname.pNameHost }; + } +#else + size_t index = this->handle->payload_offset(); + std::string error{}; + return this->handle->dns_data()->parse_dns_dn(error, index, true); +#endif +} diff --git a/native/dns/src/response.h b/native/dns/src/response.h new file mode 100644 index 0000000..dda0e0e --- /dev/null +++ b/native/dns/src/response.h @@ -0,0 +1,185 @@ +#pragma once + +#include +#include +#include +#ifdef WIN32 + #include + #include + #include +#else + #include +#endif + +#include "./types.h" + +struct in6_addr; +namespace tc::dns { + class DNSResponse; + struct DNSResponseData; + + namespace response { + #ifndef WIN32 + class DNSHeader { + friend class tc::dns::DNSResponse; + public: + [[nodiscard]] inline size_t id() const { return this->field(0); } + + [[nodiscard]] inline bool is_answer() const { return this->field(1) & 0x1UL; } + [[nodiscard]] inline bool is_authoritative_answer() const { return (uint8_t) ((this->field(1) >> 5UL) & 0x01UL); } + [[nodiscard]] inline bool is_truncation() const { return (uint8_t) ((this->field(1) >> 6UL) & 0x01UL); } + [[nodiscard]] inline bool is_recursion_desired() const { return (uint8_t) ((this->field(1) >> 7UL) & 0x01UL); } + [[nodiscard]] inline bool is_recursion_available() const { return (uint8_t) ((this->field(1) >> 8UL) & 0x01UL); } + + [[nodiscard]] inline uint8_t query_type() const { return (uint8_t) ((this->field(1) >> 1UL) & 0x07UL); } + [[nodiscard]] inline uint8_t response_code() const { return (uint8_t) ((this->field(1) >> 12UL) & 0x07UL); } + + [[nodiscard]] inline uint16_t query_count() const { return ntohs(this->field(2)); } + [[nodiscard]] inline uint16_t answer_count() const { return ntohs(this->field(3)); } + [[nodiscard]] inline uint16_t authority_count() const { return ntohs(this->field(4)); } + [[nodiscard]] inline uint16_t additional_count() const { return htons(this->field(5)); } + private: + [[nodiscard]] uint16_t field(int index) const; + + explicit DNSHeader(const DNSResponse* response) : response{response} {} + const DNSResponse* response{nullptr}; + }; + #endif + + class DNSQuery { + friend class tc::dns::DNSResponse; + public: + [[nodiscard]] inline std::string qname() const { return this->name; } + [[nodiscard]] inline rrtype::value qtype() const { return this->type; } + [[nodiscard]] inline rrclass::value qclass() const { return this->klass; } + private: + DNSQuery(std::string name, rrtype::value type, rrclass::value klass) : name{std::move(name)}, type{type}, klass{klass} {} + + std::string name; + rrtype::value type; + rrclass::value klass; + }; + + class DNSResourceRecords { + friend class tc::dns::DNSResponse; + public: + [[nodiscard]] inline std::string qname() const { +#ifdef WIN32 + return std::string{this->nrecord->pName}; +#else + return this->name; +#endif + } + [[nodiscard]] inline rrtype::value atype() const { +#ifdef WIN32 + return static_cast(this->nrecord->wType); +#else + return this->type; +#endif + } + [[nodiscard]] inline rrclass::value aclass() const { +#ifdef WIN32 + return static_cast(1); +#else + return this->klass; +#endif + } + [[nodiscard]] inline uint16_t attl() const { +#ifdef WIN32 + return (uint16_t) this->nrecord->dwTtl; +#else + return this->ttl; +#endif + } + + #ifndef WIN32 + [[nodiscard]] const uint8_t* payload_data() const; + [[nodiscard]] inline size_t payload_length() const { return this->length; } + [[nodiscard]] inline size_t payload_offset() const { return this->offset; } + #else + [[nodiscard]] inline PDNS_RECORDA native_record() const { return this->nrecord; } + [[nodiscard]] bool is_wide_string() const; + #endif + + [[nodiscard]] inline std::shared_ptr dns_data() const { + return this->data; + } + + template + [[nodiscard]] inline T parse() const { + if(T::type != this->atype()) + throw std::logic_error{"parser type mismatch"}; + return T{this}; + } + private: + std::shared_ptr data{nullptr}; + + #ifdef WIN32 + DNSResourceRecords(std::shared_ptr, PDNS_RECORDA); + + PDNS_RECORDA nrecord{nullptr}; + #else + DNSResourceRecords(std::shared_ptr, size_t, size_t, uint32_t, std::string , rrtype::value, rrclass::value); + + size_t offset{0}; + size_t length{0}; + + uint32_t ttl; + + std::string name; + rrtype::value type; + rrclass::value klass; + #endif + }; + + namespace rrparser { + struct base { + protected: + explicit base(const DNSResourceRecords* handle) : handle{handle} {} + const DNSResourceRecords* handle{nullptr}; + }; + + struct named_base : public base { + public: + [[nodiscard]] bool is_valid(); + [[nodiscard]] std::string name(); + protected: + explicit named_base(const DNSResourceRecords* handle) : base{handle} {} + }; + + #define define_parser(name, base, ...) \ + struct name : public base { \ + friend class response::DNSResourceRecords; \ + public: \ + static constexpr auto type = rrtype::name; \ + __VA_ARGS__ \ + private: \ + explicit name(const DNSResourceRecords* handle) : base{handle} {} \ + } + + define_parser(A, base, + [[nodiscard]] bool is_valid(); + [[nodiscard]] std::string address_string(); + + [[nodiscard]] in_addr address(); + ); + + define_parser(AAAA, base, + [[nodiscard]] bool is_valid(); + [[nodiscard]] std::string address_string(); + [[nodiscard]] in6_addr address(); + ); + + define_parser(SRV, base, + [[nodiscard]] bool is_valid(); + + [[nodiscard]] uint16_t priority(); + [[nodiscard]] uint16_t weight(); + [[nodiscard]] uint16_t target_port(); + [[nodiscard]] std::string target_hostname(); + ); + + define_parser(CNAME, named_base); + }; + } +} \ No newline at end of file diff --git a/native/dns/src/types.cpp b/native/dns/src/types.cpp new file mode 100644 index 0000000..00c4636 --- /dev/null +++ b/native/dns/src/types.cpp @@ -0,0 +1,102 @@ +#include "types.h" + +std::map tc::dns::rrtype::names{ + {tc::dns::rrtype::A, "A"}, + {tc::dns::rrtype::NS, "NS"}, + {tc::dns::rrtype::MD, "MD"}, + {tc::dns::rrtype::MF, "MF"}, + {tc::dns::rrtype::CNAME, "CNAME"}, + {tc::dns::rrtype::SOA, "SOA"}, + {tc::dns::rrtype::MB, "MB"}, + {tc::dns::rrtype::MG, "MG"}, + {tc::dns::rrtype::MR, "MR"}, + {tc::dns::rrtype::NULL_, "NULL_"}, + {tc::dns::rrtype::WKS, "WKS"}, + {tc::dns::rrtype::PTR, "PTR"}, + {tc::dns::rrtype::HINFO, "HINFO"}, + {tc::dns::rrtype::MINFO, "MINFO"}, + {tc::dns::rrtype::MX, "MX"}, + {tc::dns::rrtype::TXT, "TXT"}, + {tc::dns::rrtype::RP, "RP"}, + {tc::dns::rrtype::AFSDB, "AFSDB"}, + {tc::dns::rrtype::X25, "X25"}, + {tc::dns::rrtype::ISDN, "ISDN"}, + {tc::dns::rrtype::RT, "RT"}, + {tc::dns::rrtype::NSAP, "NSAP"}, + {tc::dns::rrtype::NSAP_PTR, "NSAP_PTR"}, + {tc::dns::rrtype::SIG, "SIG"}, + {tc::dns::rrtype::KEY, "KEY"}, + {tc::dns::rrtype::PX, "PX"}, + {tc::dns::rrtype::GPOS, "GPOS"}, + {tc::dns::rrtype::AAAA, "AAAA"}, + {tc::dns::rrtype::LOC, "LOC"}, + {tc::dns::rrtype::NXT, "NXT"}, + {tc::dns::rrtype::EID, "EID"}, + {tc::dns::rrtype::NIMLOC, "NIMLOC"}, + {tc::dns::rrtype::SRV, "SRV"}, + {tc::dns::rrtype::ATMA, "ATMA"}, + {tc::dns::rrtype::NAPTR, "NAPTR"}, + {tc::dns::rrtype::KX, "KX"}, + {tc::dns::rrtype::CERT, "CERT"}, + {tc::dns::rrtype::A6, "A6"}, + {tc::dns::rrtype::DNAME, "DNAME"}, + {tc::dns::rrtype::SINK, "SINK"}, + {tc::dns::rrtype::OPT, "OPT"}, + {tc::dns::rrtype::APL, "APL"}, + {tc::dns::rrtype::DS, "DS"}, + {tc::dns::rrtype::SSHFP, "SSHFP"}, + {tc::dns::rrtype::IPSECKEY, "IPSECKEY"}, + {tc::dns::rrtype::RRSIG, "RRSIG"}, + {tc::dns::rrtype::NSEC, "NSEC"}, + {tc::dns::rrtype::DNSKEY, "DNSKEY"}, + {tc::dns::rrtype::DHCID, "DHCID"}, + {tc::dns::rrtype::NSEC3, "NSEC3"}, + {tc::dns::rrtype::NSEC3PARAM, "NSEC3PARAM"}, + {tc::dns::rrtype::TLSA, "TLSA"}, + {tc::dns::rrtype::SMIMEA, "SMIMEA"}, + {tc::dns::rrtype::Unassigned, "Unassigned"}, + {tc::dns::rrtype::HIP, "HIP"}, + {tc::dns::rrtype::NINFO, "NINFO"}, + {tc::dns::rrtype::RKEY, "RKEY"}, + {tc::dns::rrtype::TALINK, "TALINK"}, + {tc::dns::rrtype::CDS, "CDS"}, + {tc::dns::rrtype::CDNSKEY, "CDNSKEY"}, + {tc::dns::rrtype::OPENPGPKEY, "OPENPGPKEY"}, + {tc::dns::rrtype::CSYNC, "CSYNC"}, + {tc::dns::rrtype::ZONEMD, "ZONEMD"}, + {tc::dns::rrtype::SPF, "SPF"}, + {tc::dns::rrtype::UINFO, "UINFO"}, + {tc::dns::rrtype::UID, "UID"}, + {tc::dns::rrtype::GID, "GID"}, + {tc::dns::rrtype::UNSPEC, "UNSPEC"}, + {tc::dns::rrtype::NID, "NID"}, + {tc::dns::rrtype::L32, "L32"}, + {tc::dns::rrtype::L64, "L64"}, + {tc::dns::rrtype::LP, "LP"}, + {tc::dns::rrtype::EUI48, "EUI48"}, + {tc::dns::rrtype::EUI64, "EUI64"}, + {tc::dns::rrtype::TKEY, "TKEY"}, + {tc::dns::rrtype::TSIG, "TSIG"}, + {tc::dns::rrtype::IXFR, "IXFR"}, + {tc::dns::rrtype::AXFR, "AXFR"}, + {tc::dns::rrtype::MAILB, "MAILB"}, + {tc::dns::rrtype::MAILA, "MAILA"}, + {tc::dns::rrtype::ANY, "ANY"}, + {tc::dns::rrtype::URI, "URI"}, + {tc::dns::rrtype::CAA, "CAA"}, + {tc::dns::rrtype::AVC, "AVC"}, + {tc::dns::rrtype::DOA, "DOA"}, + {tc::dns::rrtype::AMTRELAY, "AMTRELAY"}, + {tc::dns::rrtype::TA, "TA"}, + {tc::dns::rrtype::DLV, "DLV"}, + {tc::dns::rrtype::Reserved, "Reserved"}, +}; + + +std::map tc::dns::rrclass::names{ + {tc::dns::rrclass::IN, "IN"}, + {tc::dns::rrclass::CH, "CH"}, + {tc::dns::rrclass::HS, "HS"}, + {tc::dns::rrclass::QCLASS_ANY, "QCLASS_ANY"}, + {tc::dns::rrclass::QCLASS_NONE, "QCLASS_NONE"}, +}; \ No newline at end of file diff --git a/native/dns/src/types.h b/native/dns/src/types.h new file mode 100644 index 0000000..7813ddc --- /dev/null +++ b/native/dns/src/types.h @@ -0,0 +1,138 @@ +#pragma once + +#include +#include + +namespace tc::dns { + //https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2 + struct rrtype { + enum value : uint32_t { + A = 1, // a host address,[RFC1035], + NS = 2, // an authoritative name server,[RFC1035], + MD = 3, // a mail destination (OBSOLETE - use MX),[RFC1035], + MF = 4, // a mail forwarder (OBSOLETE - use MX),[RFC1035], + CNAME = 5, // the canonical name for an alias,[RFC1035], + SOA = 6, // marks the start of a zone of authority,[RFC1035], + MB = 7, // a mailbox domain name (EXPERIMENTAL),[RFC1035], + MG = 8, // a mail group member (EXPERIMENTAL),[RFC1035], + MR = 9, // a mail rename domain name (EXPERIMENTAL),[RFC1035], + NULL_ = 10, // a null RR (EXPERIMENTAL),[RFC1035], + WKS = 11, // a well known service description,[RFC1035], + PTR = 12, // a domain name pointer,[RFC1035], + HINFO = 13, // host information,[RFC1035], + MINFO = 14, // mailbox or mail list information,[RFC1035], + MX = 15, // mail exchange,[RFC1035], + TXT = 16, // text strings,[RFC1035], + RP = 17, // for Responsible Person,[RFC1183], + AFSDB = 18, // for AFS Data Base location,[RFC1183][RFC5864], + X25 = 19, // for X.25 PSDN address,[RFC1183], + ISDN = 20, // for ISDN address,[RFC1183], + RT = 21, // for Route Through,[RFC1183], + NSAP = 22, // "for NSAP address, NSAP style A record",[RFC1706], + NSAP_PTR = 23, // "for domain name pointer, NSAP style",[RFC1348][RFC1637][RFC1706], + SIG = 24, // for security signature,[RFC4034][RFC3755][RFC2535][RFC2536][RFC2537][RFC2931][RFC3110][RFC3008], + KEY = 25, // for security key,[RFC4034][RFC3755][RFC2535][RFC2536][RFC2537][RFC2539][RFC3008][RFC3110], + PX = 26, // X.400 mail mapping information,[RFC2163], + GPOS = 27, // Geographical Position,[RFC1712], + AAAA = 28, // IP6 Address,[RFC3596], + LOC = 29, // Location Information,[RFC1876], + NXT = 30, // Next Domain (OBSOLETE),[RFC3755][RFC2535], + EID = 31, // Endpoint Identifier,[Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt], + NIMLOC = 32, // Nimrod Locator,[1][Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt], + SRV = 33, // Server Selection,[1][RFC2782], + ATMA = 34, // ATM Address,"[ ATM Forum Technical Committee, ""ATM Name System, V2.0"", Doc ID: AF-DANS-0152.000, July 2000. Available from and held in escrow by IANA.]", + NAPTR = 35, // Naming Authority Pointer,[RFC2915][RFC2168][RFC3403], + KX = 36, // Key Exchanger,[RFC2230], + CERT = 37, //CERT, // [RFC4398], + A6 = 38, // A6 (OBSOLETE - use AAAA),[RFC3226][RFC2874][RFC6563], + DNAME = 39, //DNAME, // [RFC6672], + SINK = 40, //SINK, // [Donald_E_Eastlake][http://tools.ietf.org/html/draft-eastlake-kitchen-sink], + OPT = 41, //OPT, // [RFC6891][RFC3225], + APL = 42, //APL, // [RFC3123], + DS = 43, // Delegation Signer,[RFC4034][RFC3658], + SSHFP = 44, // SSH Key Fingerprint,[RFC4255], + IPSECKEY = 45, //IPSECKEY, // [RFC4025], + RRSIG = 46, //RRSIG, // [RFC4034][RFC3755], + NSEC = 47, //NSEC, // [RFC4034][RFC3755], + DNSKEY = 48, //DNSKEY, // [RFC4034][RFC3755], + DHCID = 49, //DHCID, // [RFC4701], + NSEC3 = 50, //NSEC3, // [RFC5155], + NSEC3PARAM = 51, //NSEC3PARAM, // [RFC5155], + TLSA = 52, //TLSA, // [RFC6698], + SMIMEA = 53, // S/MIME cert association,[RFC8162],SMIMEA/smimea-completed-template + Unassigned = 54, // , + HIP = 55, // Host Identity Protocol,[RFC8005], + NINFO = 56, //NINFO [Jim_Reid], // NINFO/ninfo-completed-template + RKEY = 57, //RKEY [Jim_Reid], // RKEY/rkey-completed-template + TALINK = 58, // Trust Anchor LINK,[Wouter_Wijngaards],TALINK/talink-completed-template + CDS = 59, // Child DS,[RFC7344],CDS/cds-completed-template + CDNSKEY = 60, // DNSKEY(s) the Child wants reflected in DS,[RFC7344], + OPENPGPKEY = 61, // OpenPGP Key,[RFC7929],OPENPGPKEY/openpgpkey-completed-template + CSYNC = 62, // Child-To-Parent Synchronization,[RFC7477], + ZONEMD = 63, // message digest for DNS zone,[draft-wessels-dns-zone-digest],ZONEMD/zonemd-completed-template + //Unassigned = 64-98, + SPF = 99, // [RFC7208], + UINFO = 100, // [IANA-Reserved], + UID = 101, // [IANA-Reserved], + GID = 102, // [IANA-Reserved], + UNSPEC = 103, // [IANA-Reserved], + NID = 104, //[RFC6742], // ILNP/nid-completed-template + L32 = 105, //[RFC6742], // ILNP/l32-completed-template + L64 = 106, //[RFC6742], // ILNP/l64-completed-template + LP = 107, //[RFC6742], // ILNP/lp-completed-template + EUI48 = 108, // an EUI-48 address,[RFC7043],EUI48/eui48-completed-template + EUI64 = 109, // an EUI-64 address,[RFC7043],EUI64/eui64-completed-template + //Unassigned = 110-248, // , + TKEY = 249, // Transaction Key,[RFC2930], + TSIG = 250, // Transaction Signature,[RFC2845], + IXFR = 251, // incremental transfer,[RFC1995], + AXFR = 252, // transfer of an entire zone,[RFC1035][RFC5936], + MAILB = 253, // "mailbox-related RRs (MB, MG or MR)",[RFC1035], + MAILA = 254, // mail agent RRs (OBSOLETE - see MX),[RFC1035], + ANY = 255, // A request for some or all records the server has available,[RFC1035][RFC6895][RFC8482], + URI = 256, //URI [RFC7553], // URI/uri-completed-template + CAA = 257, // Certification Authority Restriction,[RFC-ietf-lamps-rfc6844bis-07],CAA/caa-completed-template + AVC = 258, // Application Visibility and Control,[Wolfgang_Riedel],AVC/avc-completed-template + DOA = 259, // Digital Object Architecture,[draft-durand-doa-over-dns],DOA/doa-completed-template + AMTRELAY = 260, // Automatic Multicast Tunneling Relay,[draft-ietf-mboned-driad-amt-discovery],AMTRELAY/amtrelay-completed-template + //Unassigned = 261-32767, + TA = 32768, // DNSSEC Trust Authorities,"[Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, + // Information Networking Institute, Carnegie Mellon University, April 2004.]", + DLV = 32769, // DNSSEC Lookaside Validation,[RFC4431], + //Unassigned = 32770-65279,, // , + //Private use,65280-65534,,,, + Reserved = 65535, + }; + + static std::map names; + + static const char* name(const value& value) { + if(names.count(value) > 0) + return names.at(value); + return "unknown"; + } + }; + + struct rrclass { +#ifdef IN + #undef IN +#endif + + enum value : uint32_t { + IN = 1, /* Internet */ + CH = 3, /* Chaos */ + HS = 4, /* Hesiod */ + + QCLASS_NONE = 254, + QCLASS_ANY = 255, + }; + + static std::map names; + + static const char* name(const value& value) { + if(names.count(value) > 0) + return names.at(value); + return "unknown"; + } + }; +} \ No newline at end of file diff --git a/native/dns/test/crash.cpp b/native/dns/test/crash.cpp new file mode 100644 index 0000000..a1715eb --- /dev/null +++ b/native/dns/test/crash.cpp @@ -0,0 +1,66 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ITERATIONS (2000) + +int main() { + /* Setting up all libevent stuff */ + std::mutex ev_lock{}; + std::condition_variable ev_condition{}; + auto ev_base = event_base_new(); + + std::thread ev_loop = std::thread([&]{ + /* Wait until we should start the event loop */ + { + std::unique_lock lock{ev_lock}; + ev_condition.wait(lock); + } + + /* executing the event loop until no events are registered */ + event_base_loop(ev_base, 0); + }); + + + /* Setting up libunbound */ + auto ctx = ub_ctx_create_event(ev_base); + assert(ctx); + + auto errc = ub_ctx_hosts(ctx, nullptr); + assert(errc == 0); + + errc = ub_ctx_resolvconf(ctx, nullptr); + assert(errc == 0); + + int callback_call_count{0}; + for(int i = 0; i < ITERATIONS; i++){ + auto host = std::to_string(i) + "ts.teaspeak.de"; + errc = ub_resolve_event(ctx, host.c_str(), 33, 1, (void*) &callback_call_count, [](void* _ccc, int, void*, int, int, char*) { + *static_cast(_ccc) += 1; + }, nullptr); + assert(errc == 0); + + if(i == 0) { + //CASE 1: CRASH + //Start the event loop as soon the first resolve has been scheduled + ev_condition.notify_one(); + } + } + + //CASE 2: NO CRASH + //Start the event loop after all resolves have been scheduled + //ev_condition.notify_one(); + + /* Hang up until no more events */ + ev_loop.join(); + assert(ITERATIONS == callback_call_count); + + ub_ctx_delete(ctx); + event_base_free(ev_base); +} \ No newline at end of file diff --git a/native/dns/test/main.cpp b/native/dns/test/main.cpp new file mode 100644 index 0000000..b365fe5 --- /dev/null +++ b/native/dns/test/main.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../src/response.h" +#include "../src/resolver.h" +#include "../utils.h" + +using namespace tc::dns; +using namespace std; + +namespace parser = response::rrparser; + +int main() { +#ifdef WIN32 + { + WSADATA wsaData; + auto error = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (error != 0) { + wprintf(L"WSAStartup failed with %d\n", error); + return error; + } + } + + evthread_use_windows_threads(); +#else + evthread_use_pthreads(); +#endif + //evthread_enable_lock_debugging(); + + std::string error{}; + Resolver resolver{}; + + if(!resolver.initialize(error, true, true)) { + cerr << "failed to initialize resolver: " << error << endl; + return 1; + } + + auto begin = chrono::system_clock::now(); + for(int i = 0; i < 1; i++) { + cr(resolver, { + to_string(i) + "ts.twerion.net", + 9922 + }, [begin](bool success, auto data) { + auto end = chrono::system_clock::now(); + cout << "Success: " << success << " Time: " << chrono::ceil(end - begin).count() << "ms" << endl; + if(success) { + auto address = std::get(data); + cout << "Target: " << address.host << ":" << address.port << endl; + } else { + cout << "Message: " << std::get(data) << endl; + } + }); + } + + this_thread::sleep_for(chrono::seconds{5}); + cout << "Timeout" << endl; + resolver.finalize(); + cout << "Exit" << endl; + + return 0; +} \ No newline at end of file diff --git a/native/dns/test/main.ts b/native/dns/test/main.ts new file mode 100644 index 0000000..d02a11d --- /dev/null +++ b/native/dns/test/main.ts @@ -0,0 +1,27 @@ +/// + +console.log("HELLO WORLD"); +module.paths.push("../../build/linux_x64"); +module.paths.push("../../build/win32_64"); + +const original_require = require; +require = (module => original_require("/home/wolverindev/TeaSpeak-Client/client/native/build/linux_x64/" + module + ".node")) as any; +import * as handle from "teaclient_dns"; +require = original_require; + +handle.initialize(); +console.log("INITS"); +handle.resolve_cr("voice.teamspeak.com", 9987, result => { + console.log("Result: " + JSON.stringify(result)); +}); +handle.resolve_cr("ts.twerion.net", 9987, result => { + console.log("Result: " + JSON.stringify(result)); +}); +handle.resolve_cr("twerion.net", 9987, result => { + console.log("Result: " + JSON.stringify(result)); +}); +/* +handle.resolve_cr("localhost", 9987, result => { + console.log("Result: " + JSON.stringify(result)); +}); +*/ \ No newline at end of file diff --git a/native/dns/utils.cpp b/native/dns/utils.cpp new file mode 100644 index 0000000..b922284 --- /dev/null +++ b/native/dns/utils.cpp @@ -0,0 +1,546 @@ +#include "./utils.h" +#include "./src/response.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef WIN32 + #include +#else + #include + #include +#endif + +using namespace tc::dns; +namespace parser = tc::dns::response::rrparser; + +//-------------------------- IP-Resolve +struct CrIpStatus { + std::mutex pending_lock; + uint8_t pending{0}; + + ServerAddress original{"", 0}; + + std::tuple a{false, "unset"}; + std::tuple aaaa{false, "unset"}; + + cr_callback_t callback; + std::function&)> finish_callback; + + void one_finished(const std::shared_ptr& _this) { + assert(&*_this == this); + + std::lock_guard lock{this->pending_lock}; + if(--pending == 0) + this->finish_callback(_this); + } +}; + +void cr_ip_finish(const std::shared_ptr& status) { + if(std::get<0>(status->a)) { + status->callback(true, ServerAddress{std::get<1>(status->a), status->original.port}); + } else if(std::get<0>(status->aaaa)) { + status->callback(true, ServerAddress{std::get<1>(status->aaaa), status->original.port}); + } else { + status->callback(false, "failed to resolve an IP for " + status->original.host + ": A{" + std::get<1>(status->a) + "} AAAA{" + std::get<1>(status->aaaa) + "}"); + } +} + +void tc::dns::cr_ip(Resolver& resolver, const ServerAddress& address, const cr_callback_t& callback) { + auto status = std::make_shared(); + + status->original = address; + status->finish_callback = cr_ip_finish; + status->callback = callback; + + /* general pending so we could finish our method */ + status->pending++; + + status->pending++; + resolver.resolve_dns(address.host.c_str(), rrtype::A, rrclass::IN, std::chrono::seconds{5}, [status, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ + if(state != 0) { + status->a = {false, "A query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; + status->one_finished(status); + return; + } + std::string error; + if(!data->parse(error)) { + status->a = {false, "A query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; + status->one_finished(status); + return; + } + + for(const auto& answer : data->answers()) { + if(answer->atype() != rrtype::A){ + std::cerr << "Received a non A record answer in A query!" << std::endl; + continue; + } + + auto data = answer->parse(); + if(!data.is_valid()) + continue; + + status->a = {true, data.address_string()}; + status->one_finished(status); + return; + } + + status->a = {false, "empty response"}; + status->one_finished(status); + }); + + status->pending++; + resolver.resolve_dns(address.host.c_str(), rrtype::AAAA, rrclass::IN, std::chrono::seconds{5}, [status, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ + if(state != 0) { + status->aaaa = {false, "AAAA query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; + status->one_finished(status); + return; + } + + std::string error; + if(!data->parse(error)) { + status->aaaa = {false, "failed to parse AAAA query reponse: " + error}; + status->one_finished(status); + return; + } + + for(const auto& answer : data->answers()) { + if(answer->atype() != rrtype::AAAA){ + std::cerr << "Received a non AAAA record answer in AAAA query!" << std::endl; + continue; + } + + auto data = answer->parse(); + if(!data.is_valid()) + continue; + + status->aaaa = {true, data.address_string()}; + status->one_finished(status); + return; + } + + status->aaaa = {false, "empty response"}; + status->one_finished(status); + return; + }); + + status->one_finished(status); +} + +//-------------------------- SRV-Resolve +static std::random_device srv_rnd_dev; +static std::mt19937 srv_rnd(srv_rnd_dev()); + +/* connect resolve for TS3 srv records */ +void tc::dns::cr_srv(Resolver& resolver, const ServerAddress& address, const cr_callback_t& callback, const std::string& application) { + auto query = application + "." + address.host; + resolver.resolve_dns(query.c_str(), rrtype::SRV, rrclass::IN, std::chrono::seconds{5}, [callback, address, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ + if(state != 0) { + callback(false, "SRV query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)); + return; + } + + std::string error; + if(!data->parse(error)) { + callback(false, "failed to parse srv query reponse: " + error); + return; + } + + struct SrvEntry { + uint16_t weight; + std::string target; + uint16_t port; + }; + std::map> entries{}; + + auto answers = data->answers(); + for(const auto& answer : answers) { + if(answer->atype() != rrtype::SRV) { + std::cerr << "Received a non SRV record answer in SRV query (" << rrtype::name(answer->atype()) << ")!" << std::endl; + continue; + } + + auto srv = answer->parse(); + entries[srv.priority()].push_back({srv.weight(), srv.target_hostname(), srv.target_port()}); + } + + if(entries.empty()) { + callback(false, "empty response"); + return; + } + + std::deque> results{}; + for(auto [priority, pentries] : entries) { + uint32_t count = 0; + for(const auto& entry : pentries) { + #ifdef WIN32 + count += max((size_t) entry.weight, 1UL); + #else + count += std::max((size_t) entry.weight, 1UL); + #endif + } + + std::uniform_int_distribution dist(0, (uint32_t) (count - 1)); + auto index = dist(srv_rnd); + + count = 0; + for(const auto& entry : pentries) { + #ifdef WIN32 + count += max((size_t) entry.weight, 1UL); + #else + count += std::max((size_t) entry.weight, 1UL); + #endif + if(count > index) { + count = -1; + results.emplace_back(priority, entry); + break; + } + } + } + assert(!results.empty()); + + std::sort(results.begin(), results.end(), [](const auto& a, const auto& b) { return std::get<0>(a) < std::get<0>(b); }); + + //TODO: Resolve backup stuff as well + auto target = std::get<1>(*results.begin()); + cr_ip(resolver, { + target.target, + target.port == 0 ? address.port : target.port + }, [callback](bool success, auto response) { + if(!success) { + //TODO: Use the backup stuff? + callback(false, "failed to resolve dns pointer: " + std::get(response)); + return; + } + + callback(true, std::get(response)); + }); + }); +} + +//-------------------------- TSDNS-Resolve +void tc::dns::cr_tsdns(tc::dns::Resolver &resolver, const tc::dns::ServerAddress &address, const tc::dns::cr_callback_t &callback) { + auto root = domain_root(address.host); + cr_srv(resolver, {root, 0}, [&resolver, callback, address](bool success, auto data){ + if(!success) { + callback(false, "failed to resolve tsdns address: " + std::get(data)); + return; + } + auto tsdns_host = std::get(data); + + sockaddr_storage tsdns_address{}; + memset(&tsdns_address, 0, sizeof(tsdns_address)); + + auto tsdns_a6 = (sockaddr_in6*) &tsdns_address; + auto tsdns_a4 = (sockaddr_in*) &tsdns_address; +#ifdef WIN32 + PCSTR terminator{nullptr}; + if(RtlIpv6StringToAddressA(tsdns_host.host.c_str(), &terminator, (in6_addr*) &tsdns_a6->sin6_addr) == 0) +#else + if(inet_pton(AF_INET6, tsdns_host.host.c_str(), &tsdns_a6->sin6_addr) == 1) +#endif + { + tsdns_a6->sin6_family = AF_INET6; + tsdns_a6->sin6_port = htons(tsdns_host.port == 0 ? 41144 : tsdns_host.port); + } +#ifdef WIN32 + else if(RtlIpv4StringToAddressA(tsdns_host.host.c_str(), false, &terminator, (in_addr*) &tsdns_a4->sin_addr) == 0) +#else + else if(inet_pton(AF_INET, tsdns_host.host.c_str(), &(tsdns_a4->sin_addr)) == 1) +#endif + { + tsdns_a4->sin_family = AF_INET; + tsdns_a4->sin_port = htons(tsdns_host.port == 0 ? 41144 : tsdns_host.port); + } else { + callback(false, "invalid tsdns host: " + tsdns_host.host); + return; + } + + auto query = address.host; + std::transform(query.begin(), query.end(), query.begin(), tolower); + resolver.resolve_tsdns(query.c_str(), tsdns_address, std::chrono::seconds{5}, [callback, query, address](Resolver::ResultState::value error, int detail, const std::string& response) { + if(error == Resolver::ResultState::SUCCESS) { + if(response == "404") + callback(false, "no record found for " + query); + else { + std::string host{response}; + std::string port{"$PORT"}; + + //TODO: Backup IP-Addresses? + if(host.find(',') != -1) + host = std::string{host.begin(), host.begin() + host.find(',')}; + + auto colon_index = host.rfind(':'); + if(colon_index > 0 && (host[colon_index - 1] == ']' || host.find(':') == colon_index)) { + port = host.substr(colon_index + 1); + host = host.substr(0, colon_index); + } + + ServerAddress resp{host, 0}; + if(port == "$PORT") { + resp.port = address.port; + } else { + try { + resp.port = (uint16_t) stoul(port); + } catch(const std::exception&) { + callback(false, "failed to parse response: " + response + " Failed to parse port: " + port); + return; + } + } + callback(true, resp); + } + } else { + callback(false, "query failed. Code: " + std::to_string(error) + "," + std::to_string(detail) + ": " + response); + } + }); + }, "_tsdns._tcp"); +} + +//-------------------------- Full-Resolve + +struct CrStatus { + enum State { + PENDING, + FAILED, + SUCCESS + }; + + std::recursive_mutex pending_lock; /* do_done could be called recursively because DNS request could answer instant! */ + uint8_t pending{0}; + bool finished{false}; + + tc::dns::ServerAddress address; + tc::dns::cr_callback_t callback; + + ~CrStatus() { + assert(this->pending == 0); + } + + void do_done(const std::shared_ptr& _this) { + std::lock_guard lock{pending_lock}; + this->finished |= this->try_answer(_this); //May invokes next DNS query + + assert(this->pending > 0); + if(--pending == 0 && !this->finished) { //Order matters we have to decrease pensing! + this->callback(false, "no results"); + this->finished = true; + return; + } + } + + typedef std::tuple&)>> flagged_executor_t; + + flagged_executor_t execute_subsrv_ts; + std::tuple subsrv_ts; + + flagged_executor_t execute_subsrv_ts3; + std::tuple subsrv_ts3; + + flagged_executor_t execute_tsdns; + std::tuple tsdns; + + flagged_executor_t execute_subdomain; + std::tuple subdomain; + + //Only after subsrc and tsdns failed + flagged_executor_t execute_rootsrv; + std::tuple rootsrv; + + //Only after subsrc and tsdns failed + flagged_executor_t execute_rootdomain; + std::tuple rootdomain; + +#define try_answer_test(element, executor) \ + if(std::get<0>(element) == State::SUCCESS) { \ + this->call_answer(std::get<2>(element)); \ + return true; \ + } else if(std::get<0>(element) == State::PENDING) { \ + if(!std::get<0>(executor)) { \ + std::get<0>(executor) = true; \ + if(!!std::get<1>(executor)) { \ + std::get<1>(executor)(_this); \ + return false; \ + } else { \ + std::get<1>(element) = "No executor"; \ + std::get<0>(element) = State::FAILED; \ + } \ + } else \ + return false; \ + } + + bool try_answer(const std::shared_ptr& _this) { + if(this->finished) + return true; + + try_answer_test(this->subsrv_ts, this->execute_subsrv_ts); + try_answer_test(this->subsrv_ts3, this->execute_subsrv_ts3); + try_answer_test(this->tsdns, this->execute_tsdns); + try_answer_test(this->subdomain, this->execute_subdomain); + try_answer_test(this->rootsrv, this->execute_rootsrv); + try_answer_test(this->rootdomain, this->execute_rootdomain); + return false; + } + + #define answer_log(element, executor) \ + if(!std::get<0>(executor)) \ + std::cout << #element << ": not executed" << std::endl; \ + else if(std::get<0>(element) == State::PENDING) \ + std::cout << #element << ": pending" << std::endl; \ + else if(std::get<0>(element) == State::FAILED) \ + std::cout << #element << ": failed: " << std::get<1>(element) << std::endl; \ + else \ + std::cout << #element << ": success: " << std::get<2>(element).host << ":" << std::get<2>(element).port << std::endl; + + void call_answer(const tc::dns::ServerAddress& data) { + answer_log(this->subsrv_ts, this->execute_subsrv_ts); + answer_log(this->subsrv_ts3, this->execute_subsrv_ts3); + answer_log(this->tsdns, this->execute_tsdns); + answer_log(this->subdomain, this->execute_subdomain); + answer_log(this->rootsrv, this->execute_rootsrv); + answer_log(this->rootdomain, this->execute_rootdomain); + + //TODO: Print data + this->callback(true, data); + } +}; + +void tc::dns::cr(Resolver& resolver, const tc::dns::ServerAddress& address, const tc::dns::cr_callback_t& callback) { + auto status = std::make_shared(); + status->address = address; + status->callback = callback; + status->pending++; + + status->execute_subsrv_ts = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute subsrc ts" << std::endl; + status->pending++; + tc::dns::cr_srv(resolver, status->address, [status](bool success, auto data) { + if(success) { + status->subsrv_ts = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->subsrv_ts = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }, "_ts._udp"); + } + }; + /* execute */ + std::get<0>(status->execute_subsrv_ts) = true; + + status->execute_subsrv_ts3 = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute subsrc ts3" << std::endl; + status->pending++; + tc::dns::cr_srv(resolver, status->address, [status](bool success, auto data) { + if(success) { + status->subsrv_ts3 = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->subsrv_ts3 = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }, "_ts3._udp"); + } + }; + /* execute */ + std::get<0>(status->execute_subsrv_ts3) = true; + + status->execute_subdomain = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute subdomain" << std::endl; + status->pending++; + tc::dns::cr_ip(resolver, status->address, [status](bool success, auto data) { + if(success) { + status->subdomain = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->subdomain = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }); + } + }; + /* execute */ + //Will be autoamticall be executed after the SRV stuff + //std::get<0>(status->execute_subdomain) = true; + + status->execute_tsdns = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute tsdns" << std::endl; + status->pending++; + + tc::dns::cr_tsdns(resolver, status->address, [status](bool success, auto data) { + if(success) { + status->tsdns = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->tsdns = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }); + } + }; + /* execute */ + //Execute the TSDNS request right at the beginning because it could hang sometimes + std::get<0>(status->execute_tsdns) = true; + + auto root_domain = tc::dns::domain_root(status->address.host); + if(root_domain != status->address.host) { + status->execute_rootsrv = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute root srv" << std::endl; + status->pending++; + + tc::dns::cr_srv(resolver, { + tc::dns::domain_root(status->address.host), + status->address.port + }, [status](bool success, auto data) { + if(success) { + status->rootsrv = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->rootsrv = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }, "_ts3._udp"); + } + }; + + status->execute_rootdomain = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute root domain" << std::endl; + status->pending++; + + tc::dns::cr_ip(resolver,{ + tc::dns::domain_root(status->address.host), + status->address.port + }, [status](bool success, auto data) { + if(success) { + status->rootdomain = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->rootdomain = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }); + } + }; + } + + /* Only execute after every executor has been registered! */ + std::get<1>(status->execute_subsrv_ts)(status); + std::get<1>(status->execute_subsrv_ts3)(status); + //std::get<1>(status->execute_subdomain)(status); + std::get<1>(status->execute_tsdns)(status); + + status->do_done(status); +} \ No newline at end of file diff --git a/native/dns/utils.h b/native/dns/utils.h new file mode 100644 index 0000000..5efb48f --- /dev/null +++ b/native/dns/utils.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include +#include "./src/resolver.h" + +namespace tc::dns { + struct ServerAddress { + std::string host; + uint16_t port; + }; + typedef std::function& /* data */)> cr_callback_t; + + inline std::string domain_root(std::string input) { + size_t dot_count = 0; + auto it = input.rbegin(); + while(it != input.rend()) { + if(*it == '.' && ++dot_count == 2) + break; + it++; + } + std::string result{}; + result.append(input.begin() + std::distance(it, input.rend()), input.end()); + return result; + } + + extern void cr_ip(Resolver& resolver, const ServerAddress& address, const cr_callback_t& callback); + extern void cr_srv(Resolver& resolver, const ServerAddress& address, const cr_callback_t& callback, const std::string& application = "_ts._udp"); + extern void cr_tsdns(Resolver& resolver, const ServerAddress& address, const cr_callback_t& callback); + extern void cr(Resolver& resolver, const tc::dns::ServerAddress& address, const tc::dns::cr_callback_t& callback); +} \ No newline at end of file diff --git a/native/ppt/.gitignore b/native/ppt/.gitignore new file mode 100644 index 0000000..dbb958a --- /dev/null +++ b/native/ppt/.gitignore @@ -0,0 +1,3 @@ +.idea/ +cmake-build-* +!exports/*.d.ts \ No newline at end of file diff --git a/native/ppt/CMakeLists.txt b/native/ppt/CMakeLists.txt new file mode 100644 index 0000000..2c0e7c8 --- /dev/null +++ b/native/ppt/CMakeLists.txt @@ -0,0 +1,16 @@ +set(MODULE_NAME "teaclient_ppt") + +if (MSVC) + set(SOURCE_FILES ${SOURCE_FILES} src/Win32KeyboardHook.cpp) + add_definitions(-DUSING_UV_SHARED) +else() + add_definitions(-DHAVE_X11) + set(SOURCE_FILES ${SOURCE_FILES} src/X11KeyboardHook.cpp ../updater/main.cpp ../updater/config.cpp ../updater/config.h) +endif() + +add_nodejs_module(${MODULE_NAME} binding.cc ${SOURCE_FILES}) +add_executable(Hook-Test ${SOURCE_FILES} test/HookTest.cpp) +if(NOT MSVC) + target_link_libraries(${MODULE_NAME} X11) + target_link_libraries(Hook-Test X11 pthread) +endif() diff --git a/native/ppt/binding.cc b/native/ppt/binding.cc new file mode 100644 index 0000000..cf7009c --- /dev/null +++ b/native/ppt/binding.cc @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include + +using namespace std; + +#include "NanException.h" +#include "NanEventCallback.h" +#include "src/KeyboardHook.h" + + +std::mutex callback_lock; +std::deque> callbacks; +std::deque> queued_events; +std::unique_ptr hook; + +Nan::callback_t<> event_callback; + +inline v8::Local event_to_object(const std::shared_ptr& event) { + Nan::EscapableHandleScope scope; + + auto object = Nan::New(); + object->Set(Nan::New("type").ToLocalChecked(), Nan::New(event->type)); + object->Set(Nan::New("key_code").ToLocalChecked(), Nan::New(event->code).ToLocalChecked()); + + object->Set(Nan::New("key_shift").ToLocalChecked(), Nan::New(event->key_shift)); + object->Set(Nan::New("key_alt").ToLocalChecked(), Nan::New(event->key_alt)); + object->Set(Nan::New("key_windows").ToLocalChecked(), Nan::New(event->key_windows)); + object->Set(Nan::New("key_ctrl").ToLocalChecked(), Nan::New(event->key_ctrl)); + + return scope.Escape(object); +} + +NAN_METHOD(RegisterCallback) { + if(!info[0]->IsFunction()) { + NAN_THROW_EXCEPTION(Error, "argument must be a function!"); + return; + } + + auto callback = make_shared(info[0].As()); + { + lock_guard lock(callback_lock); + callbacks.push_back(callback); + } +} + +NAN_METHOD(UnregisterCallback) { + if(!info[0]->IsFunction()) { + NAN_THROW_EXCEPTION(Error, "argument must be a function!"); + return; + } + + { + lock_guard lock(callback_lock); + + callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(), [&](const std::shared_ptr& callback){ + return callback->GetFunction() == info[0]; + }), callbacks.end()); + } +} + +NAN_MODULE_INIT(init) { + hook = make_unique(); + if(!hook->attach()) { + NAN_THROW_EXCEPTION(Error, "Failed to attach hook!"); + return; + } + hook->callback_event = [&](const shared_ptr& event) { + { + lock_guard lock(callback_lock); + queued_events.push_back(event); + } + + event_callback(); + }; + + + event_callback = Nan::async_callback([](){ + Nan::HandleScope scope; + + unique_lock lock(callback_lock); + auto events = queued_events; + auto calls = callbacks; + queued_events.clear(); + lock.unlock(); + + + for(const auto& event : events) { + auto object = event_to_object(event); + + for(const auto& callback : calls) { + v8::Local args[] = { + object + }; + callback->Call(1, args); + } + } + }); + + NAN_EXPORT(target, RegisterCallback); + NAN_EXPORT(target, UnregisterCallback); +} + +NODE_MODULE(MODULE_NAME, init) \ No newline at end of file diff --git a/native/ppt/exports/exports.d.ts b/native/ppt/exports/exports.d.ts new file mode 100644 index 0000000..d8d442f --- /dev/null +++ b/native/ppt/exports/exports.d.ts @@ -0,0 +1,21 @@ +declare module "teaclient_ppt" { + enum KeyEventType { + PRESS = 0, + RELEASE = 1, + TYPE = 2 + } + + export interface KeyEvent { + type: KeyEventType; + + key_code: string; + + key_shift: boolean; + key_alt: boolean; + key_windows: boolean; + key_ctrl: boolean; + } + + export function RegisterCallback(_: (_: KeyEvent) => any); + export function UnregisterCallback(_: (_: KeyEvent) => any); +} diff --git a/native/ppt/src/KeyboardHook.h b/native/ppt/src/KeyboardHook.h new file mode 100644 index 0000000..6eaf5e2 --- /dev/null +++ b/native/ppt/src/KeyboardHook.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include + +#ifdef HAVE_X11 + #include +#elif defined(WIN32) + #include +#endif +class KeyboardHook { + #if defined(WIN32) + friend LRESULT CALLBACK keyboard_hook_callback(int, WPARAM, LPARAM); + #endif + public: + struct KeyType { + enum value { + KEY_UNKNOWN, + + KEY_NORMAL, + KEY_SHIFT, + KEY_ALT, + KEY_WIN, + KEY_CTRL + }; + }; + + struct KeyEvent { + enum type { + PRESS, + RELEASE, + TYPE + }; + + type type; + std::string key; + std::string code; + + bool key_ctrl; + bool key_windows; + bool key_shift; + bool key_alt; + }; + typedef std::function& /* event */)> callback_event_t; + + KeyboardHook(); + virtual ~KeyboardHook(); + + bool attach(); + inline bool attached() { return this->_attached; } + void detach(); + + callback_event_t callback_event; + private: + #ifdef HAVE_X11 + typedef int KeyID; + Display* display = nullptr; + Window window_root = 0; + Window window_focused = 0; + int focus_revert; + + long end_id = 0; + #elif defined(WIN32) + typedef UINT KeyID; + HHOOK hook_id = nullptr; + bool _hook_callback(int, WPARAM, LPARAM); + #endif + + std::map map_key; + std::map map_special; + + bool _attached = false; + bool active = false; + std::thread poll_thread; + void poll_events(); +}; \ No newline at end of file diff --git a/native/ppt/src/Win32KeyboardHook.cpp b/native/ppt/src/Win32KeyboardHook.cpp new file mode 100644 index 0000000..720e910 --- /dev/null +++ b/native/ppt/src/Win32KeyboardHook.cpp @@ -0,0 +1,185 @@ +#include +#include +#include "KeyboardHook.h" + +using namespace std; + +typedef KBDLLHOOKSTRUCT KeyboardHookStruct; +LRESULT CALLBACK keyboard_hook_callback(int, WPARAM, LPARAM); +std::map hook_handles; + +KeyboardHook::KeyboardHook() {} +KeyboardHook::~KeyboardHook() { + if(this->_attached) + this->detach(); +} + +bool KeyboardHook::attach() { + assert(!this->_attached); + this->active = true; + + this->poll_thread = std::thread(std::bind(&KeyboardHook::poll_events, this)); + + this->_attached = true; + return true; +} + +void KeyboardHook::detach() { + assert(this->_attached); + this->active = false; + { + //TODO trigger no message! + } + if(this->poll_thread.joinable()) + this->poll_thread.join(); + + this->_attached = false; +} + +void KeyboardHook::poll_events() { + hook_handles[this_thread::get_id()] = this; + this->hook_id = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_callback, GetModuleHandle(nullptr), 0); + if(!this->hook_id) { + cerr << "Failed to register hook!" << endl; + return; + } + + MSG msg; + while(!GetMessage(&msg, nullptr, 0, 0) && this->active) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + UnhookWindowsHookEx(this->hook_id); + hook_handles[this_thread::get_id()] = nullptr; +} + +LRESULT keyboard_hook_callback(int nCode, WPARAM event, LPARAM ptr_keyboard) { + auto handle = hook_handles[this_thread::get_id()]; + assert(handle); + auto consume = handle->_hook_callback(nCode, event, ptr_keyboard); + if(consume) + return 1; + return CallNextHookEx(nullptr, nCode, event, ptr_keyboard); +} + +inline std::string key_code(DWORD code, bool extended = false) { + auto scan_code = MapVirtualKey(code, MAPVK_VK_TO_VSC); + if(extended) + scan_code |= KF_EXTENDED; + + char key_buffer[255]; + auto length = GetKeyNameTextA(scan_code << 16, key_buffer, 255); + if(length == 0) + return "error"; + else + return string(key_buffer, length); +} + +inline std::string key_code(KeyboardHookStruct* keyboard) { + return key_code(keyboard->vkCode, (keyboard->flags & LLKHF_EXTENDED) > 0); +} + +using KeyType = KeyboardHook::KeyType; +//https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes +inline KeyType::value key_type(DWORD vk_code) { + switch(vk_code) { + case VK_CONTROL: + case VK_LCONTROL: + case VK_RCONTROL: + return KeyType::KEY_CTRL; + case VK_MENU: + case VK_RMENU: + case VK_LMENU: + return KeyType::KEY_ALT; + case VK_SHIFT: + case VK_RSHIFT: + case VK_LSHIFT: + return KeyType::KEY_SHIFT; + case VK_LWIN: + case VK_RWIN: + return KeyType::KEY_WIN; + default: + return KeyType::KEY_NORMAL; + } +} + +bool KeyboardHook::_hook_callback(int nCode, WPARAM event, LPARAM ptr_keyboard) { + auto keyboard = (KeyboardHookStruct*) ptr_keyboard; + if(event == WM_KEYDOWN || event == WM_SYSKEYDOWN) { + auto& state = this->map_key[keyboard->vkCode]; + bool typed = state; + state = true; + + auto type = key_type(keyboard->vkCode); + if(type != KeyType::KEY_NORMAL) + this->map_special[type] = true; + else + this->map_special[type] = keyboard->vkCode; + + if (this->callback_event) { + if(!typed) { + auto e = make_shared(); + e->type = KeyboardHook::KeyEvent::PRESS; + if(type == KeyType::KEY_NORMAL) { + e->code = key_code(keyboard); + } else { + e->code = key_code(this->map_special[KeyType::KEY_NORMAL], false); + } + + e->key_alt = this->map_special[KeyType::KEY_ALT]; + e->key_ctrl = this->map_special[KeyType::KEY_CTRL]; + e->key_windows = this->map_special[KeyType::KEY_WIN]; + e->key_shift = this->map_special[KeyType::KEY_SHIFT]; + + this->callback_event(e); + } + { + auto e = make_shared(); + e->type = KeyboardHook::KeyEvent::TYPE; + if(type == KeyType::KEY_NORMAL) { + e->code = key_code(keyboard); + } else { + e->code = key_code(this->map_special[KeyType::KEY_NORMAL], false); + } + + e->key_alt = this->map_special[KeyType::KEY_ALT]; + e->key_ctrl = this->map_special[KeyType::KEY_CTRL]; + e->key_windows = this->map_special[KeyType::KEY_WIN]; + e->key_shift = this->map_special[KeyType::KEY_SHIFT]; + + this->callback_event(e); + } + } + } else if(event == WM_KEYUP || event == WM_SYSKEYUP) { + auto& state = this->map_key[keyboard->vkCode]; + if(!state) return false; //Duplicate + state = false; + + auto type = key_type(keyboard->vkCode); + if(type != KeyType::KEY_NORMAL) + this->map_special[type] = false; + else if(this->map_special[KeyType::KEY_NORMAL] == keyboard->vkCode) + this->map_special[KeyType::KEY_NORMAL] = 0xFF; + + if (this->callback_event) { + auto e = make_shared(); + e->type = KeyboardHook::KeyEvent::RELEASE; + if(type == KeyType::KEY_NORMAL) { + e->code = key_code(keyboard); + } else { + e->code = key_code(this->map_special[KeyType::KEY_NORMAL], false); + } + + e->key_alt = this->map_special[KeyType::KEY_ALT]; + e->key_ctrl = this->map_special[KeyType::KEY_CTRL]; + e->key_windows = this->map_special[KeyType::KEY_WIN]; + e->key_shift = this->map_special[KeyType::KEY_SHIFT]; + + this->callback_event(e); + } + } + + //Consume the event: return 1 + return false; +} \ No newline at end of file diff --git a/native/ppt/src/X11KeyboardHook.cpp b/native/ppt/src/X11KeyboardHook.cpp new file mode 100644 index 0000000..24632ac --- /dev/null +++ b/native/ppt/src/X11KeyboardHook.cpp @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#include +#include "KeyboardHook.h" + +#define ClientMessageMask (1L<<24) +#define SelectMask (KeyPressMask | KeyReleaseMask | FocusChangeMask | ClientMessageMask) + +using namespace std; +using KeyType = KeyboardHook::KeyType::value; + +inline KeyType key_type(XID key_id) { + switch (key_id) { + case XK_Shift_L: + case XK_Shift_R: + return KeyType::KEY_SHIFT; + case XK_Alt_L: + case XK_Alt_R: + return KeyType::KEY_ALT; + case XK_Control_L: + case XK_Control_R: + return KeyType::KEY_CTRL; + case XK_Menu: + return KeyType::KEY_WIN; + + default: + break; + } + + /* + if(key_id >= XK_space && key_id <= XK_asciitilde) return KeyType::KEY_NORMAL; //Normal ASCI + if(key_id >= XK_KP_Space && key_id <= XK_KP_Divide) return KeyType::KEY_NORMAL; // Keypad functions, keypad numbers cleverly chosen to map to ASCII + if(key_id >= XK_Kanji && key_id <= XK_Mae_Koho) return KeyType::KEY_NORMAL; // Japanese keyboard support + */ + return KeyType::KEY_NORMAL; +} + +KeyboardHook::KeyboardHook() { + this->map_special[KeyType::KEY_NORMAL] = XK_VoidSymbol; +} +KeyboardHook::~KeyboardHook() { + if(this->active) + this->detach(); +} + +bool KeyboardHook::attach() { + assert(!this->active); + this->active = true; + + this->display = XOpenDisplay(nullptr); + if(!this->display) return false; + + { + this->window_root = XDefaultRootWindow(this->display); + + XGetInputFocus(display, &this->window_focused, &this->focus_revert); + if(this->window_focused == PointerRoot) + this->window_focused = this->window_root; + XSelectInput(this->display, this->window_focused, SelectMask); + //XGrabKeyboard(this->display, this->window_focused, false, GrabModeAsync, GrabModeAsync, CurrentTime); + } + + XSetErrorHandler([](Display* display, XErrorEvent* event) { + if(event->type == BadWindow) + return 0; + /* + * X Error of failed request: BadWindow (invalid Window parameter) + Major opcode of failed request: 2 (X_ChangeWindowAttributes) + Resource id in failed request: 0x0 + Serial number of failed request: 32 + Current serial number in output stream: 32 + */ + cerr << "Caught X11 error: " << event->type << endl; + return 0; + }); + + this->poll_thread = thread(bind(&KeyboardHook::poll_events, this)); + return true; +} + +void KeyboardHook::detach() { + assert(this->active); + this->active = false; + + { + // push a dummy event into the queue so that the event loop has a chance to stop + XClientMessageEvent dummy_event; + memset((void*) &dummy_event, 0, sizeof(XClientMessageEvent)); + dummy_event.type = ClientMessage; + dummy_event.window = this->window_focused; + dummy_event.format = 32; + dummy_event.data.l[0] = this->end_id = rand(); + + XSendEvent(this->display, this->window_focused, 0, ClientMessageMask, (XEvent*) &dummy_event); + XFlush(this->display); + } + + if(this->poll_thread.joinable()) + this->poll_thread.join(); + + XCloseDisplay(this->display); + this->display = nullptr; +} + +void KeyboardHook::poll_events() { + XEvent event; + bool has_event = false; + + while(this->active) { + if(!has_event) { + auto result = XNextEvent(this->display, &event); + if(result != 0) { + //TODO throw error + cout << "XNextEvent returned invalid code: " << result << endl; + break; + } + } + has_event = false; + + if(event.type == FocusOut) { + cout << "Old windows lost focus. Attaching to new one" << endl; + int result = 0; + if(this->window_root != this->window_focused) { + result = XSelectInput(display, this->window_focused, 0); //Release events + } + result = XGetInputFocus(display, &this->window_focused, &this->focus_revert); + if(this->window_focused == PointerRoot) + this->window_focused = this->window_root; + result = XSelectInput(display, this->window_focused, SelectMask); + continue; + } else if(event.type == FocusIn) { + + } else if(event.type == KeyPress) { + auto& old_flag = this->map_key[event.xkey.keycode]; + bool typed = old_flag; + old_flag = true; + + auto key_sym = XLookupKeysym(&event.xkey, 0); + auto type = key_type(key_sym); + + if(type != KeyType::KEY_NORMAL) + this->map_special[type] = true; + else + this->map_special[type] = key_sym; + + if (this->callback_event) { + if(!typed) { + auto e = make_shared(); + e->type = KeyboardHook::KeyEvent::PRESS; + if(type == KeyType::KEY_NORMAL) { + e->code = XKeysymToString(key_sym); + } else { + e->code = XKeysymToString(this->map_special[KeyType::KEY_NORMAL]); + } + + e->key_alt = this->map_special[KeyType::KEY_ALT] > 0; + e->key_ctrl = this->map_special[KeyType::KEY_CTRL] > 0; + e->key_windows = this->map_special[KeyType::KEY_WIN] > 0; + e->key_shift = this->map_special[KeyType::KEY_SHIFT] > 0; + + this->callback_event(e); + } + { + auto e = make_shared(); + e->type = KeyboardHook::KeyEvent::TYPE; + if(type == KeyType::KEY_NORMAL) { + e->code = XKeysymToString(key_sym); + } else { + e->code = XKeysymToString(this->map_special[KeyType::KEY_NORMAL]); + } + + e->key_alt = this->map_special[KeyType::KEY_ALT] > 0; + e->key_ctrl = this->map_special[KeyType::KEY_CTRL] > 0; + e->key_windows = this->map_special[KeyType::KEY_WIN] > 0; + e->key_shift = this->map_special[KeyType::KEY_SHIFT] > 0; + + this->callback_event(e); + } + } + } else if(event.type == KeyRelease) { + auto key_sym = XLookupKeysym(&event.xkey, 0); + if(XEventsQueued(this->display, 0) > 0) { + auto result = XNextEvent(this->display, &event); + if(result != 0) { + cerr << "XNextEvent(...) => " << result << endl; + break; + } + has_event = true; + if(event.type == KeyPress && XLookupKeysym(&event.xkey, 0) == key_sym) //Key retriggered + continue; //Handle repress + } + + auto& old_flag = this->map_key[event.xkey.keycode]; + if(!old_flag) continue; //Nothing to update + old_flag = false; + + auto type = key_type(key_sym); + if(type != KeyType::KEY_NORMAL) + this->map_special[type] = false; + else if(this->map_special[KeyType::KEY_NORMAL] == key_sym) + this->map_special[KeyType::KEY_NORMAL] = XK_VoidSymbol; + + if (this->callback_event) { + auto e = make_shared(); + e->type = KeyboardHook::KeyEvent::RELEASE; + if(type == KeyType::KEY_NORMAL) { + e->code = XKeysymToString(key_sym); + } else { + e->code = XKeysymToString(this->map_special[KeyType::KEY_NORMAL]); + } + + e->key_alt = this->map_special[KeyType::KEY_ALT] > 0; + e->key_ctrl = this->map_special[KeyType::KEY_CTRL] > 0; + e->key_windows = this->map_special[KeyType::KEY_WIN] > 0; + e->key_shift = this->map_special[KeyType::KEY_SHIFT] > 0; + + this->callback_event(e); + } + } else if(event.type == ClientMessage) { + cout << "Got client message. End ID: " << event.xclient.data.l[0] << " <=> " << this->end_id << endl; + if(event.xclient.data.l[0] == this->end_id) break; + } else { + cerr << "Got unknown event of type " << event.type << endl; + } + } +} \ No newline at end of file diff --git a/native/ppt/test/HookTest.cpp b/native/ppt/test/HookTest.cpp new file mode 100644 index 0000000..5515046 --- /dev/null +++ b/native/ppt/test/HookTest.cpp @@ -0,0 +1,26 @@ +#include "../src/KeyboardHook.h" +#include +#include + +using namespace std::chrono; +using namespace std; + +int main() { + KeyboardHook hook; + hook.callback_event = [](const shared_ptr& event) { + if(event->type == KeyboardHook::KeyEvent::PRESS) + cout << "press " << event->code.c_str() << ": shift: " << event->key_shift << ", alt: " << event->key_alt << ", ctrl: " << event->key_ctrl << ", win: " << event->key_windows << endl; + else if(event->type == KeyboardHook::KeyEvent::TYPE) + cout << "type " << event->code.c_str() << ": shift: " << event->key_shift << ", alt: " << event->key_alt << ", ctrl: " << event->key_ctrl << ", win: " << event->key_windows << endl; + else + cout << "release " << event->code.c_str() << ": shift: " << event->key_shift << ", alt: " << event->key_alt << ", ctrl: " << event->key_ctrl << ", win: " << event->key_windows << endl; + }; + + if(!hook.attach()) { + cerr << "failed to attach!" << endl; + return 0; + } + + this_thread::sleep_for(seconds(100)); + return 0; +} \ No newline at end of file diff --git a/native/relink.sh b/native/relink.sh new file mode 100755 index 0000000..1c90ce8 --- /dev/null +++ b/native/relink.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +BASEDIR=$(dirname "$0") +cd "$BASEDIR/" + +machine="$(uname -s)" +case "${machine}" in + Linux*) machine=Linux;; +# Darwin*) machine=Mac;; + MINGW*) machine=MinGW;; + *) machine="UNKNOWN:${machine}" +esac + +if [[ ${machine} == "UNKNOWN"* ]]; then + echo "Unknown platform ${machine}" + exit 1 +fi + +if [[ ${machine} == "MinGW" ]]; then + mkdir -p build/win32_64/ + cd build/win32_64 + + rm teaclient_codec.node; ln -s ../../codec/cmake-build-debug/teaclient_codec.node + rm teaclient_ppt.node; ln -s ../../ppt/cmake-build-debug/teaclient_ppt.node +fi +if [[ ${machine} == "Linux" ]]; then + mkdir -p build/linux_amd64/ + cd build/linux_amd64 + + rm teaclient_codec.node; ln -s ../../codec/cmake-build-debug/Debug/teaclient_codec.node + rm teaclient_ppt.node; ln -s ../../ppt/cmake-build-debug/Debug/teaclient_ppt.node +fi + +#/home/wolverindev/.config/TeaClient/crash_dumps/crash_dump_renderer_04a85069-9d30-48ec-e2fd5e9e-846c5305.dmp \ No newline at end of file diff --git a/native/serverconnection/.gitignore b/native/serverconnection/.gitignore new file mode 100644 index 0000000..dbb958a --- /dev/null +++ b/native/serverconnection/.gitignore @@ -0,0 +1,3 @@ +.idea/ +cmake-build-* +!exports/*.d.ts \ No newline at end of file diff --git a/native/serverconnection/CMakeLists.txt b/native/serverconnection/CMakeLists.txt new file mode 100644 index 0000000..32f3f8c --- /dev/null +++ b/native/serverconnection/CMakeLists.txt @@ -0,0 +1,151 @@ +set(MODULE_NAME "teaclient_connection") + +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -static-libasan -lasan -lubsan") +set(SOURCE_FILES + src/logger.cpp + src/EventLoop.cpp + src/hwuid.cpp + + src/connection/ft/FileTransferManager.cpp + src/connection/ft/FileTransferObject.cpp + + src/audio/AudioSamples.cpp + src/audio/AudioDevice.cpp + src/audio/AudioMerger.cpp + src/audio/AudioOutput.cpp + src/audio/AudioInput.cpp + src/audio/AudioResampler.cpp + src/audio/AudioReframer.cpp + + src/audio/filter/FilterVad.cpp + src/audio/filter/FilterThreshold.cpp + src/audio/filter/FilterState.cpp + + src/audio/codec/Converter.cpp + src/audio/codec/OpusConverter.cpp +) + +set(NODEJS_SOURCE_FILES + src/bindings.cpp + + src/connection/ServerConnection.cpp + src/connection/Socket.cpp + src/connection/ProtocolHandler.cpp + src/connection/ProtocolHandlerPOW.cpp + src/connection/ProtocolHandlerCrypto.cpp + src/connection/ProtocolHandlerPackets.cpp + src/connection/ProtocolHandlerCommands.cpp + src/connection/audio/AudioSender.cpp + src/connection/audio/AudioEventLoop.cpp + + src/connection/audio/VoiceConnection.cpp + src/connection/audio/VoiceClient.cpp + + src/audio/js/AudioPlayer.cpp + src/audio/js/AudioOutputStream.cpp + + src/audio/js/AudioRecorder.cpp + src/audio/js/AudioConsumer.cpp + src/audio/js/AudioFilter.cpp +) + +if (MSVC) + set(SOURCE_FILES ${SOURCE_FILES}) + add_definitions(-DUSING_UV_SHARED) +else() + set(SOURCE_FILES ${SOURCE_FILES}) +endif() + +add_nodejs_module(${MODULE_NAME} ${SOURCE_FILES} ${NODEJS_SOURCE_FILES}) +target_link_libraries(${MODULE_NAME} ${NODEJS_LIBRARIES}) +#target_compile_options(${MODULE_NAME} PUBLIC "-fPIC") + +find_package(TomMath REQUIRED) +include_directories(${TomMath_INCLUDE_DIR}) + +find_package(TomCrypt REQUIRED) +include_directories(${TomCrypt_INCLUDE_DIR}) + +find_package(DataPipes REQUIRED) +include_directories(${DataPipes_INCLUDE_DIR}) + +find_package(Libevent REQUIRED) +include_directories(${LIBEVENT_INCLUDE_DIRS}) +message("libevent include dir: ${LIBEVENT_INCLUDE_DIRS}") +message("libevent static libraries: ${LIBEVENT_STATIC_LIBRARIES}") + +find_package(TeaSpeak_SharedLib REQUIRED) +include_directories(${TeaSpeak_SharedLib_INCLUDE_DIR}) + +find_package(StringVariable REQUIRED) +include_directories(${StringVariable_INCLUDE_DIR}) + +find_package(Ed25519 REQUIRED) +include_directories(${ed25519_INCLUDE_DIR}) + +find_package(ThreadPool REQUIRED) +include_directories(${ThreadPool_INCLUDE_DIR}) +if (WIN32) + add_compile_options(/NODEFAULTLIB:ThreadPoolStatic) + add_definitions(-DWINDOWS) #Required by ThreadPool + add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Let windows allow strerror + add_definitions(-D_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING) # For the FMT library +endif () + +find_package(Soxr REQUIRED) +include_directories(${soxr_INCLUDE_DIR}) + +find_package(PortAudio REQUIRED) +include_directories(${PortAudio_INCLUDE_DIR}) + +find_package(fvad REQUIRED) +include_directories(${fvad_INCLUDE_DIR}) + +find_package(Opus REQUIRED) +include_directories(${opus_INCLUDE_DIR}) + +find_package(spdlog REQUIRED) + +set(REQUIRED_LIBRARIES + ${TeaSpeak_SharedLib_LIBRARIES_STATIC} + + ${TomCrypt_LIBRARIES_STATIC} + ${TomMath_LIBRARIES_STATIC} + + ${LIBEVENT_STATIC_LIBRARIES} + + ${StringVariable_LIBRARIES_STATIC} + ${DataPipes_LIBRARIES_STATIC} #Needs to be static because something causes ca bad function call when loaded in electron + ${ThreadPool_LIBRARIES_STATIC} + ${soxr_LIBRARIES_STATIC} + ${PortAudio_LIBRARIES_STATIC} + ${fvad_LIBRARIES_STATIC} + ${opus_LIBRARIES_STATIC} + + ${ed25519_LIBRARIES_STATIC} + + spdlog::spdlog +) + +if (WIN32) + set(REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} "Ws2_32.Lib") +else() + set(REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} + libstdc++fs.a + asound + jack.a + pthread + ) +endif() + +add_definitions(-DNO_OPEN_SSL) +target_link_libraries(${MODULE_NAME} ${REQUIRED_LIBRARIES}) +target_compile_definitions(${MODULE_NAME} PUBLIC -DNODEJS_API) + +add_executable(Audio-Test ${SOURCE_FILES} test/audio/main.cpp) +target_link_libraries(Audio-Test ${REQUIRED_LIBRARIES}) + +add_executable(HW-UID-Test src/hwuid.cpp) +target_link_libraries(HW-UID-Test + ${REQUIRED_LIBRARIES} +) \ No newline at end of file diff --git a/native/serverconnection/exports/exports.d.ts b/native/serverconnection/exports/exports.d.ts new file mode 100644 index 0000000..b2f6310 --- /dev/null +++ b/native/serverconnection/exports/exports.d.ts @@ -0,0 +1,252 @@ +declare module "teaclient_connection" { + export enum ServerType { + UNKNOWN, + TEASPEAK, + TEAMSPEAK + } + + export enum PlayerState { + BUFFERING, + PLAYING, + STOPPING, + STOPPED + } + + export interface NativeVoiceClient { + client_id: number; + + callback_playback: () => any; + callback_stopped: () => any; + + callback_state_changed: (new_state: PlayerState) => any; + + get_state() : PlayerState; + + get_volume() : number; + set_volume(volume: number) : void; + + abort_replay(); + get_stream() : audio.playback.AudioOutputStream; + } + + export interface NativeVoiceConnection { + register_client(client_id: number) : NativeVoiceClient; + available_clients() : NativeVoiceClient[]; + unregister_client(client_id: number); + + audio_source() : audio.record.AudioConsumer; + set_audio_source(consumer: audio.record.AudioConsumer | undefined); + + decoding_supported(codec: number) : boolean; + encoding_supported(codec: number) : boolean; + + get_encoder_codec() : number; + set_encoder_codec(codec: number); + + /* could may throw an exception when the underlying voice sender has been deallocated */ + enable_voice_send(flag: boolean); + } + + export interface NativeServerConnection { + callback_voice_data: (buffer: Uint8Array, client_id: number, codec_id: number, flag_head: boolean, packet_id: number) => any; + callback_command: (command: string, arguments: any, switches: string[]) => any; + callback_disconnect: (reason?: string) => any; + _voice_connection: NativeVoiceConnection; + server_type: ServerType; + + connected(): boolean; + + connect(properties: { + remote_host: string, + remote_port: number, + + timeout: number, + + callback: (error: number) => any, + + identity_key: string | undefined, /* if identity_key empty, then an ephemeral license will be created */ + teamspeak: boolean + }); + + disconnect(reason: string | undefined, callback: (error: number) => any) : boolean; + + error_message(id: number) : string; + + send_command(command: string, arguments: any[], switches: string[]); + send_voice_data(buffer: Uint8Array, codec_id: number, header: boolean); + send_voice_data_raw(buffer: Float32Array, channels: number, sample_rate: number, header: boolean); + + /* ping in microseconds */ + current_ping() : number; + } + + export function spawn_server_connection() : NativeServerConnection; + export function destroy_server_connection(connection: NativeServerConnection); + + + export namespace ft { + export interface TransferObject { + name: string; + direction: "upload" | "download"; + } + + export interface FileTransferSource extends TransferObject { + total_size: number; + } + + export interface FileTransferTarget extends TransferObject { + expected_size: number; + } + + export interface NativeFileTransfer { + handle: TransferObject; + + callback_finished: (aborted?: boolean) => any; + callback_start: () => any; + callback_progress: (current: number, max: number) => any; + callback_failed: (message: string) => any; + + start(); + } + + export interface TransferOptions { + remote_address: string; + remote_port: number; + + transfer_key: string; + client_transfer_id: number; + server_transfer_id: number; + + object: TransferObject; + } + + export function upload_transfer_object_from_file(path: string, name: string) : FileTransferSource; + export function upload_transfer_object_from_buffer(buffer: ArrayBuffer) : FileTransferSource; + export function download_transfer_object_from_buffer(target_buffer: ArrayBuffer) : TransferObject; + + export function destroy_connection(connection: NativeFileTransfer); + export function spawn_connection(transfer: TransferOptions) : NativeFileTransfer; + } + + export namespace audio { + export interface AudioDevice { + name: string; + driver: string; + + device_id: string; + + input_supported: boolean; + output_supported: boolean; + + input_default: boolean; + output_default: boolean; + + device_index: number; + } + + export namespace playback { + export interface AudioOutputStream { + sample_rate: number; + channels: number; + + get_buffer_latency() : number; + set_buffer_latency(value: number); + + get_buffer_max_latency() : number; + set_buffer_max_latency(value: number); + } + + export interface OwnedAudioOutputStream extends AudioOutputStream { + callback_underflow: () => any; + callback_overflow: () => any; + + clear(); + write_data(buffer: ArrayBuffer, interleaved: boolean); + write_data_rated(buffer: ArrayBuffer, interleaved: boolean, sample_rate: number); + + deleted() : boolean; + delete(); + } + + export function set_device(device: number); + export function current_device() : number; + + export function create_stream() : OwnedAudioOutputStream; + + export function get_master_volume() : number; + export function set_master_volume(volume: number); + } + + export namespace record { + export interface ConsumeFilter { + get_name() : string; + } + + export interface MarginedFilter { + get_margin_frames() : number; + set_margin_frames(value: number); + } + + export interface VADConsumeFilter extends ConsumeFilter, MarginedFilter { + get_level() : number; + } + + export interface ThresholdConsumeFilter extends ConsumeFilter, MarginedFilter { + get_threshold() : number; + set_threshold(value: number); + + get_attack_smooth() : number; + set_attack_smooth(value: number); + + get_release_smooth() : number; + set_release_smooth(value: number); + + set_analyze_filter(callback: (value: number) => any); + } + + export interface StateConsumeFilter extends ConsumeFilter { + is_consuming() : boolean; + set_consuming(flag: boolean); + } + + export interface AudioConsumer { + sample_rate: number; + channels: number; + frame_size: number; + + /* TODO add some kind of order to may improve CPU performance (Some filters are more intense then others) */ + get_filters() : ConsumeFilter[]; + unregister_filter(filter: ConsumeFilter); + + create_filter_vad(level: number) : VADConsumeFilter; + create_filter_threshold(threshold: number) : ThresholdConsumeFilter; + create_filter_state() : StateConsumeFilter; + + callback_data: (buffer: Float32Array) => any; + callback_ended: () => any; + callback_started: () => any; + } + + export interface AudioRecorder { + get_device() : number; + set_device(device: number, callback: (flag: boolean | string) => void); /* Recorder needs to be started afterwards */ + + start(callback: (flag: boolean) => void); + started() : boolean; + stop(); + + get_volume() : number; + set_volume(volume: number); + + create_consumer() : AudioConsumer; + get_consumers() : AudioConsumer[]; + delete_consumer(consumer: AudioConsumer); + } + + export function create_recorder() : AudioRecorder; + } + + export function initialize(); + export function available_devices() : AudioDevice[]; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/EventLoop.cpp b/native/serverconnection/src/EventLoop.cpp new file mode 100644 index 0000000..1f987dd --- /dev/null +++ b/native/serverconnection/src/EventLoop.cpp @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include "EventLoop.h" + +using namespace std; +using namespace tc::event; + +EventExecutor::EventExecutor(const std::string& thread_prefix) : thread_prefix(thread_prefix) {} +EventExecutor::~EventExecutor() { + unique_lock lock(this->lock); + this->_shutdown(lock); + this->_reset_events(lock); +} + +bool EventExecutor::initialize(int threads) { + unique_lock lock(this->lock); + this->_shutdown(lock); + if(!lock.owns_lock()) + lock.lock(); + + this->should_shutdown = false; + while(threads-- > 0) { + this->threads.emplace_back(&EventExecutor::_executor, this); + + #ifndef WIN32 + { + auto handle = this->threads.back().native_handle(); + auto name = this->thread_prefix + to_string(this->threads.size()); + pthread_setname_np(handle, name.c_str()); + } + #endif + } + return true; +} + +void EventExecutor::shutdown() { + unique_lock lock(this->lock); + this->_shutdown(lock); +} + +bool EventExecutor::schedule(const std::shared_ptr &entry) { + unique_lock lock(this->lock); + if(!entry || entry->_event_ptr) + return true; /* already scheduled */ + + auto linked_entry = new LinkedEntry{}; + linked_entry->entry = entry; + linked_entry->next = nullptr; + linked_entry->previous = this->tail; + linked_entry->scheduled = std::chrono::system_clock::now(); + + if(this->tail) { + this->tail->next = linked_entry; + this->tail = linked_entry; + } else { + this->head = linked_entry; + this->tail = linked_entry; + } + this->condition.notify_one(); + + entry->_event_ptr = linked_entry; + return true; +} + +bool EventExecutor::cancel(const std::shared_ptr &entry) { + unique_lock lock(this->lock); + if(!entry || !entry->_event_ptr) + return false; + + auto linked_entry = (LinkedEntry*) entry->_event_ptr; + this->head = linked_entry->next; + if(this->head) { + assert(linked_entry == this->head->previous); + this->head->previous = nullptr; + } else { + assert(linked_entry == this->tail); + this->tail = nullptr; + } + + delete linked_entry; + entry->_event_ptr = nullptr; + return true; +} + +void EventExecutor::_shutdown(std::unique_lock &lock) { + if(!lock.owns_lock()) + lock.lock(); + + this->should_shutdown = true; + this->condition.notify_all(); + lock.unlock(); + for(auto& thread : this->threads) + thread.join(); /* TODO: Timeout? */ + lock.lock(); + this->should_shutdown = false; +} + +void EventExecutor::_reset_events(std::unique_lock &lock) { + if(!lock.owns_lock()) + lock.lock(); + auto entry = this->head; + while(entry) { + auto next = entry->next; + delete entry; + entry = next; + } + this->head = nullptr; + this->tail = nullptr; +} + +void EventExecutor::_executor(tc::event::EventExecutor *loop) { + while(true) { + unique_lock lock(loop->lock); + loop->condition.wait(lock, [&] { return loop->should_shutdown || loop->head != nullptr; }); + if(loop->should_shutdown) + break; + + if(!loop->head) + continue; + + auto linked_entry = loop->head; + loop->head = linked_entry->next; + if(loop->head) { + assert(linked_entry == loop->head->previous); + loop->head->previous = nullptr; + } else { + assert(linked_entry == loop->tail); + loop->tail = nullptr; + } + + auto event_handler = linked_entry->entry.lock(); + assert(event_handler->_event_ptr == linked_entry); + event_handler->_event_ptr = nullptr; + lock.unlock(); + + if(event_handler) { + if(event_handler->single_thread_executed()) { + auto execute_lock = event_handler->execute_lock(false); + if(!execute_lock) { + event_handler->event_execute_dropped(linked_entry->scheduled); + } else { + event_handler->event_execute(linked_entry->scheduled); + } + } else { + event_handler->event_execute(linked_entry->scheduled); + } + } + delete linked_entry; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/EventLoop.h b/native/serverconnection/src/EventLoop.h new file mode 100644 index 0000000..ae1f98f --- /dev/null +++ b/native/serverconnection/src/EventLoop.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace tc { + namespace event { + class EventExecutor; + class EventEntry { + friend class EventExecutor; + public: + virtual void event_execute(const std::chrono::system_clock::time_point& /* scheduled timestamp */) = 0; + virtual void event_execute_dropped(const std::chrono::system_clock::time_point& /* scheduled timestamp */) {} + + std::unique_lock execute_lock(bool force) { + if(force) + return std::unique_lock(this->_execute_mutex); + else + return std::unique_lock(this->_execute_mutex, std::try_to_lock); + } + + inline bool single_thread_executed() const { return this->_single_thread; } + inline void single_thread_executed(bool value) { this->_single_thread = value; } + private: + void* _event_ptr = nullptr; + bool _single_thread = true; /* if its set to true there might are some dropped executes! */ + std::mutex _execute_mutex; + }; + + class EventExecutor { + public: + explicit EventExecutor(const std::string& /* thread prefix */); + virtual ~EventExecutor(); + + bool initialize(int /* num threads */); + bool schedule(const std::shared_ptr& /* entry */); + bool cancel(const std::shared_ptr& /* entry */); /* Note: Will not cancel already running executes */ + void shutdown(); + private: + struct LinkedEntry { + LinkedEntry* previous; + LinkedEntry* next; + + std::chrono::system_clock::time_point scheduled; + std::weak_ptr entry; + }; + static void _executor(EventExecutor*); + void _shutdown(std::unique_lock&); + void _reset_events(std::unique_lock&); + + bool should_shutdown = true; + + std::vector threads; + std::mutex lock; + std::condition_variable condition; + + LinkedEntry* head = nullptr; + LinkedEntry* tail = nullptr; + + std::string thread_prefix; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioDevice.cpp b/native/serverconnection/src/audio/AudioDevice.cpp new file mode 100644 index 0000000..ec9e7a4 --- /dev/null +++ b/native/serverconnection/src/audio/AudioDevice.cpp @@ -0,0 +1,102 @@ +#include "AudioDevice.h" +#include "../logger.h" + +using namespace std; +using namespace tc; +using namespace tc::audio; + +extern bool devices_cached(); /* if the result is false then the call to devices() may take a while */ +extern std::deque> devices(); + +bool _devices_cached = false; +mutex _audio_devices_lock; +deque> _audio_devices{}; + +bool audio::devices_cached() { + return _devices_cached; +} + +void audio::clear_device_cache() { + lock_guard lock(_audio_devices_lock); + _audio_devices.clear(); + _devices_cached = false; +} + +deque> audio::devices() { + lock_guard lock(_audio_devices_lock); + if(_devices_cached) + return _audio_devices; + + /* query devices */ + auto device_count = Pa_GetDeviceCount(); + if(device_count < 0) { + log_error(category::audio, tr("Pa_GetDeviceCount() returned {}"), device_count); + return {}; + } + + auto default_input_device = Pa_GetDefaultInputDevice(); + auto default_output_device = Pa_GetDefaultOutputDevice(); + + for(PaDeviceIndex device_index = 0; device_index < device_count; device_index++) { + auto device_info = Pa_GetDeviceInfo(device_index); + if(!device_info) { + log_warn(category::audio, tr("Pa_GetDeviceInfo(...) failed for device {}"), device_index); + continue; + } + + auto device_host_info = Pa_GetHostApiInfo(device_info->hostApi); + if(!device_host_info) { + log_warn(category::audio, tr("Pa_GetHostApiInfo(...) failed for device {} with host api {}"), device_index, device_info->hostApi); + continue; + } + + auto info = make_shared(); + info->device_id = device_index; + info->name = device_info->name; + + info->max_inputs = device_info->maxInputChannels; + info->input_supported = device_info->maxInputChannels > 0; + + info->max_outputs = device_info->maxOutputChannels; + info->output_supported = device_info->maxOutputChannels > 0; + + info->is_default_input = device_index == default_input_device; + info->is_default_output = device_index == default_output_device; + + info->driver = device_host_info->name; + info->is_default_driver_input = device_index == device_host_info->defaultInputDevice; + info->is_default_driver_output = device_index == device_host_info->defaultOutputDevice; + + PaStreamParameters test_parameters{}; + test_parameters.device = device_index; + test_parameters.sampleFormat = paFloat32; + test_parameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ + test_parameters.hostApiSpecificStreamInfo = nullptr; + + /* + if(info->input_supported) { + test_parameters.channelCount = device_info->maxInputChannels; + for(size_t index = 0; standard_sample_rates[index] > 0; index++) { + auto rate = standard_sample_rates[index]; + auto err = Pa_IsFormatSupported(&test_parameters, nullptr, rate); + if(err == paFormatIsSupported) + info->supported_input_rates.push_back(rate); + } + } + if(info->output_supported) { + test_parameters.channelCount = device_info->maxOutputChannels; + for(size_t index = 0; standard_sample_rates[index] > 0; index++) { + auto rate = standard_sample_rates[index]; + auto err = Pa_IsFormatSupported(nullptr, &test_parameters, rate); + if(err == paFormatIsSupported) + info->supported_output_rates.push_back(rate); + } + } + */ + + _audio_devices.push_back(info); + } + + _devices_cached = true; + return _audio_devices; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioDevice.h b/native/serverconnection/src/audio/AudioDevice.h new file mode 100644 index 0000000..91d7fa2 --- /dev/null +++ b/native/serverconnection/src/audio/AudioDevice.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace tc { + namespace audio { + static constexpr double standard_sample_rates[] = { + 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, + 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */ + }; + + struct AudioDevice { + PaDeviceIndex device_id; + + bool is_default_output; + bool is_default_input; + + bool is_default_driver_output; + bool is_default_driver_input; + + bool input_supported; + bool output_supported; + std::string name; + std::string driver; + + /* + std::vector supported_input_rates; + std::vector supported_output_rates; + */ + + int max_inputs; + int max_outputs; + }; + + extern void clear_device_cache(); + extern bool devices_cached(); /* if the result is false then the call to devices() may take a while */ + extern std::deque> devices(); + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioInput.cpp b/native/serverconnection/src/audio/AudioInput.cpp new file mode 100644 index 0000000..247fd33 --- /dev/null +++ b/native/serverconnection/src/audio/AudioInput.cpp @@ -0,0 +1,165 @@ +#include +#include +#include "AudioInput.h" +#include "AudioReframer.h" +#include "../logger.h" + +using namespace std; +using namespace tc; +using namespace tc::audio; + +AudioConsumer::AudioConsumer(tc::audio::AudioInput *handle, size_t channel_count, size_t sample_rate, size_t frame_size) : + handle(handle), + channel_count(channel_count), + sample_rate(sample_rate) , + frame_size(frame_size) { + if(this->frame_size > 0) { + this->reframer = make_unique(channel_count, frame_size); + this->reframer->on_frame = [&](const void* buffer) { this->handle_framed_data(buffer, this->frame_size); }; + } +} + +void AudioConsumer::handle_framed_data(const void *buffer, size_t samples) { + unique_lock read_callback_lock(this->on_read_lock); + auto function = this->on_read; /* copy */ + read_callback_lock.unlock(); + if(!function) + return; + + function(buffer, samples); +} + +void AudioConsumer::process_data(const void *buffer, size_t samples) { + if(this->reframer) + this->reframer->process(buffer, samples); + else + this->handle_framed_data(buffer, samples); +} + +AudioInput::AudioInput(size_t channels, size_t rate) : _channel_count(channels), _sample_rate(rate) {} +AudioInput::~AudioInput() { + this->close_device(); + lock_guard lock(this->consumers_lock); + for(const auto& consumer : this->_consumers) + consumer->handle = nullptr; +} + +bool AudioInput::open_device(std::string& error, PaDeviceIndex index) { + lock_guard lock(this->input_stream_lock); + + if(index == this->_current_device_index) + return true; + + this->close_device(); + this->_current_device_index = index; + if(index == paNoDevice) + return true; + + this->_current_device = Pa_GetDeviceInfo(index); + if(!this->_current_device) { + this->_current_device_index = paNoDevice; + error = "failed to get device info"; + return false; + } + + PaStreamParameters parameters{}; + memset(¶meters, 0, sizeof(parameters)); + parameters.channelCount = (int) this->_channel_count; + parameters.device = this->_current_device_index; + parameters.sampleFormat = paFloat32; + parameters.suggestedLatency = this->_current_device->defaultLowOutputLatency; + + auto err = Pa_OpenStream(&this->input_stream, ¶meters, nullptr, (double) this->_sample_rate, paFramesPerBufferUnspecified, paClipOff, &AudioInput::_audio_callback, this); + if(err != paNoError) { + error = "Pa_OpenStream returned " + to_string(err); + return false; + } + + return true; +} + +bool AudioInput::record() { + lock_guard lock(this->input_stream_lock); + if(!this->input_stream) + return false; + if(Pa_IsStreamActive(this->input_stream)) + return true; + + auto err = Pa_StartStream(this->input_stream); + if(err != paNoError && err != paStreamIsNotStopped) { + log_error(category::audio, tr("Pa_StartStream returned {}"), err); + return false; + } + + return true; +} + +bool AudioInput::recording() { + lock_guard lock(this->input_stream_lock); + return this->input_stream && Pa_IsStreamActive(this->input_stream); +} + +void AudioInput::stop() { + lock_guard lock(this->input_stream_lock); + if(this->input_stream) { + Pa_AbortStream(this->input_stream); + } +} + +void AudioInput::close_device() { + lock_guard lock(this->input_stream_lock); + if(this->input_stream) { + /* TODO: Test for errors */ + Pa_AbortStream(this->input_stream); + Pa_CloseStream(this->input_stream); + + this->input_stream = nullptr; + } +} + +std::shared_ptr AudioInput::create_consumer(size_t frame_length) { + auto result = shared_ptr(new AudioConsumer(this, this->_channel_count, this->_sample_rate, frame_length)); + { + lock_guard lock(this->consumers_lock); + this->_consumers.push_back(result); + } + return result; +} + +void AudioInput::delete_consumer(const std::shared_ptr &source) { + { + lock_guard lock(this->consumers_lock); + auto it = find(this->_consumers.begin(), this->_consumers.end(), source); + if(it != this->_consumers.end()) + this->_consumers.erase(it); + } + + source->handle = nullptr; +} + +int AudioInput::_audio_callback(const void *a, void *b, unsigned long c, const PaStreamCallbackTimeInfo* d, PaStreamCallbackFlags e, void *_ptr_audio_output) { + return reinterpret_cast(_ptr_audio_output)->audio_callback(a, b, c, d, e); +} + +int AudioInput::audio_callback(const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags) { + if (!input) /* hmmm.. suspicious */ + return 0; + + if(this->_volume != 1) { + auto ptr = (float*) input; + auto left = frameCount * this->_channel_count; + while(left-- > 0) + *(ptr++) *= this->_volume; + } + + auto begin = chrono::system_clock::now(); + for(const auto& consumer : this->consumers()) { + consumer->process_data(input, frameCount); + } + auto end = chrono::system_clock::now(); + auto ms = chrono::duration_cast(end - begin).count(); + if(ms > 5) { + log_warn(category::audio, tr("Processing of audio input needed {}ms. This could be an issue!"), chrono::duration_cast(end - begin).count()); + } + return 0; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioInput.h b/native/serverconnection/src/audio/AudioInput.h new file mode 100644 index 0000000..d441272 --- /dev/null +++ b/native/serverconnection/src/audio/AudioInput.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "AudioSamples.h" + +namespace tc { + namespace audio { + class AudioInput; + class Reframer; + + class AudioConsumer { + friend class AudioInput; + public: + AudioInput* handle; + + size_t const channel_count = 0; + size_t const sample_rate = 0; + + size_t const frame_size = 0; + + spin_lock on_read_lock; /* locked to access the function */ + std::function on_read; + private: + AudioConsumer(AudioInput* handle, size_t channel_count, size_t sample_rate, size_t frame_size); + + std::unique_ptr reframer; + std::mutex buffer_lock; + size_t buffered_samples = 0; + std::deque> sample_buffers; + + void process_data(const void* /* buffer */, size_t /* samples */); + void handle_framed_data(const void* /* buffer */, size_t /* samples */); + }; + + class AudioInput { + public: + AudioInput(size_t /* channels */, size_t /* rate */); + virtual ~AudioInput(); + + bool open_device(std::string& /* error */, PaDeviceIndex); + bool record(); + bool recording(); + void stop(); + void close_device(); + PaDeviceIndex current_device() { return this->_current_device_index; } + + std::deque> consumers() { + std::lock_guard lock(this->consumers_lock); + return this->_consumers; + } + + std::shared_ptr create_consumer(size_t /* frame size */); + void delete_consumer(const std::shared_ptr& /* source */); + + inline size_t channel_count() { return this->_channel_count; } + inline size_t sample_rate() { return this->_sample_rate; } + + inline float volume() { return this->_volume; } + inline void set_volume(float value) { this->_volume = value; } + private: + static int _audio_callback(const void *, void *, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); + int audio_callback(const void *, void *, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags); + + size_t const _channel_count; + size_t const _sample_rate; + + std::mutex consumers_lock; + std::deque> _consumers; + + std::recursive_mutex input_stream_lock; + const PaDeviceInfo* _current_device = nullptr; + PaDeviceIndex _current_device_index = paNoDevice; + PaStream* input_stream = nullptr; + + float _volume = 1.f; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioMerger.cpp b/native/serverconnection/src/audio/AudioMerger.cpp new file mode 100644 index 0000000..b1f2e63 --- /dev/null +++ b/native/serverconnection/src/audio/AudioMerger.cpp @@ -0,0 +1,111 @@ +#include +#include "AudioMerger.h" +#include "../logger.h" +#include + +using namespace std; +using namespace tc::audio; + +/* technique based on http://www.vttoth.com/CMS/index.php/technical-notes/68 */ +inline float merge_ab(float a, float b) { + /* + * Form: A,B := [0;n] + * Z = 2(A + B) - (2/n) * A * B - n + * + * For a range from 0 to 2: Z = 2(A + B) - AB - 2 + */ + + a += 1; + b += 1; + + return (2 * (a + b) - a * b - 2) - 1; +} + +bool merge::merge_sources(void *_dest, void *_src_a, void *_src_b, size_t channels, size_t samples) { + auto dest = (float*) _dest; + auto src_a = (float*) _src_a; + auto src_b = (float*) _src_b; + + for(size_t index = 0; index < channels * samples; index++) + dest[index] = merge_ab(src_a[index], src_b[index]); + + return true; +} + +bool merge::merge_n_sources(void *dest, void **srcs, size_t src_length, size_t channels, size_t samples) { + assert(src_length > 0); + + /* find the first non empty source */ + while(!srcs[0]) { + srcs++; + src_length--; + + if(src_length == 0) + return false; + } + memcpy(dest, srcs[0], channels * samples * 4); + srcs++; + src_length--; + + while(src_length > 0) { + /* only invoke is srcs is not null! */ + if(srcs[0] && !merge::merge_sources(dest, srcs[0], dest, channels, samples)) + return false; + + srcs++; + src_length--; + } + + return true; +} + +#define stack_buffer_length (1024 * 8) +bool merge::merge_channels_interleaved(void *target, size_t target_channels, const void *src, size_t src_channels, size_t samples) { + assert(src_channels == 1 || src_channels == 2); + assert(target_channels == 1 || target_channels == 2); + + if(src_channels == target_channels) { + if(src == target) + return true; + memcpy(target, src, samples * src_channels * 4); + return true; + } + + if(src_channels == 1 && target_channels == 2) { + auto source_array = (float*) src; + auto target_array = (float*) target; + + if(source_array == target_array) { + if(stack_buffer_length < samples * src_channels) { + log_error(category::audio, tr("channel merge failed due to large inputs")); + return false; + } + float stack_buffer[stack_buffer_length]; + memcpy(stack_buffer, src, src_channels * samples * 4); + source_array = stack_buffer; + + while(samples-- > 0) { + *(target_array++) = *source_array; + *(target_array++) = *source_array; + source_array++; + } + } else { + while(samples-- > 0) { + *(target_array++) = *source_array; + *(target_array++) = *source_array; + source_array++; + } + } + } else if(src_channels == 2 && target_channels == 1) { + auto source_array = (float*) src; + auto target_array = (float*) target; + + while(samples-- > 0) { + *(target_array++) = merge_ab(*(source_array), *(source_array + 1)); + source_array += 2; + } + } else + return false; + + return true; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioMerger.h b/native/serverconnection/src/audio/AudioMerger.h new file mode 100644 index 0000000..bf67767 --- /dev/null +++ b/native/serverconnection/src/audio/AudioMerger.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace tc { + namespace audio { + namespace merge { + /* the result buffer could be equal to one of the source buffers to prevent unnecessary allocations + * Note: The sample order is irrelevant + */ + extern bool merge_sources(void* /* result */, void* /* source a */, void* /* source b */, size_t /* channels */, size_t /* samples */); + + extern bool merge_n_sources(void* /* result */, void** /* sources */, size_t /* size_t sources count */, size_t /* channels */, size_t /* samples */); + + extern bool merge_channels_interleaved(void* /* result */, size_t /* result channels */, const void* /* source */, size_t /* source channels */, size_t /* samples */); + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioOutput.cpp b/native/serverconnection/src/audio/AudioOutput.cpp new file mode 100644 index 0000000..7d1d947 --- /dev/null +++ b/native/serverconnection/src/audio/AudioOutput.cpp @@ -0,0 +1,293 @@ +#include "AudioOutput.h" +#include "AudioMerger.h" +#include "../logger.h" +#include +#include +#include + +using namespace std; +using namespace tc; +using namespace tc::audio; + +void AudioOutputSource::clear() { + lock_guard lock(this->buffer_lock); + this->sample_buffers.clear(); + this->buffered_samples = 0; +} + +ssize_t AudioOutputSource::pop_samples(void *buffer, size_t samples) { + auto sample_count = samples; + + _retest: + { + lock_guard lock(this->buffer_lock); + while(sample_count > 0 && !this->sample_buffers.empty()) { + auto buf = this->sample_buffers[0]; + auto sc = min((size_t) (buf->sample_size - buf->sample_index), (size_t) sample_count); + if(sc > 0 && buffer) { /* just to ensure */ + memcpy(buffer, (char *) buf->sample_data + this->channel_count * buf->sample_index * 4, sc * this->channel_count * 4); + } else { +#ifndef WIN32 + /* for my debugger */ + __asm__("nop"); +#endif + } + + sample_count -= sc; + buf->sample_index += (uint16_t) sc; + if(buf->sample_index == buf->sample_size) + this->sample_buffers.pop_front(); + + if(buffer) + buffer = (char*) buffer + sc * this->channel_count * 4; + } + this->buffered_samples -= samples - sample_count; + } + + if(sample_count > 0) { + if(this->on_underflow) { + if(this->on_underflow()) { + goto _retest; + } + } + + this->buffering = true; + } + + if(this->on_read) + this->on_read(); + + return samples - sample_count; /* return the written samples */ +} + +ssize_t AudioOutputSource::enqueue_samples(const void *buffer, size_t samples) { + auto buf = SampleBuffer::allocate((uint8_t) this->channel_count, (uint16_t) samples); + if(!buf) + return -1; + + buf->sample_index = 0; + memcpy(buf->sample_data, buffer, this->channel_count * samples * 4); + + return this->enqueue_samples(buf); +} + +ssize_t AudioOutputSource::enqueue_samples(const std::shared_ptr &buf) { + if(!buf) return 0; + + { + unique_lock lock(this->buffer_lock); + if(this->max_latency > 0 && this->buffered_samples + buf->sample_size > this->max_latency) { + /* overflow! */ + auto overflow_length = this->buffered_samples + buf->sample_size - this->max_latency; + if(this->on_overflow) { + lock.unlock(); + this->on_overflow(overflow_length); + lock.lock(); + } + + switch (this->overflow_strategy) { + case overflow_strategy::discard_input: + return -2; + case overflow_strategy::discard_buffer_all: + this->sample_buffers.clear(); + break; + case overflow_strategy::discard_buffer_half: + this->sample_buffers.erase(this->sample_buffers.begin(), this->sample_buffers.begin() + (int) ceil(this->sample_buffers.size() / 2)); + break; + case overflow_strategy::ignore: + break; + } + } + + this->sample_buffers.push_back(buf); + this->buffered_samples += buf->sample_size; + } + + return buf->sample_size; +} + +AudioOutput::AudioOutput(size_t channels, size_t rate) : _channel_count(channels), _sample_rate(rate) {} +AudioOutput::~AudioOutput() { + this->close_device(); + this->cleanup_buffers(); +} + +std::shared_ptr AudioOutput::create_source() { + auto result = shared_ptr(new AudioOutputSource(this, this->_channel_count, this->_sample_rate)); + { + lock_guard lock(this->sources_lock); + this->_sources.push_back(result); + } + return result; +} + +void AudioOutput::delete_source(const std::shared_ptr &source) { + { + lock_guard lock(this->sources_lock); + auto it = find(this->_sources.begin(), this->_sources.end(), source); + if(it != this->_sources.end()) + this->_sources.erase(it); + } + + source->handle = nullptr; +} + +void AudioOutput::cleanup_buffers() { + lock_guard buffer_lock(this->buffer_lock); + if(this->source_buffer) + free(this->source_buffer); + if(this->source_merge_buffer) + free(this->source_merge_buffer); + + this->source_merge_buffer = nullptr; + this->source_buffer = nullptr; + this->source_merge_buffer_length = 0; + this->source_buffer_length = 0; +} + +int AudioOutput::_audio_callback(const void *a, void *b, unsigned long c, const PaStreamCallbackTimeInfo* d, PaStreamCallbackFlags e, void *_ptr_audio_output) { + return reinterpret_cast(_ptr_audio_output)->audio_callback(a, b, c, d, e); +} + +int AudioOutput::audio_callback(const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags) { + if(!output) /* hmmm.. suspicious */ + return 0; + + lock_guard buffer_lock(this->buffer_lock); + size_t buffer_length = frameCount * 4 * this->_channel_count; + size_t sources = 0; + size_t actual_sources = 0; + + auto volume = this->_volume; + { + lock_guard lock(this->sources_lock); + sources = this->_sources.size(); + actual_sources = sources; + + if(sources > 0) { + if(volume > 0) { /* allocate the required space */ + auto source_buffer_length = buffer_length * sources; + auto source_merge_buffer_length = sizeof(void*) * sources; + + if(this->source_buffer_length < source_buffer_length || !this->source_buffer) { + if(this->source_buffer) + free(this->source_buffer); + this->source_buffer = malloc(source_buffer_length); + this->source_buffer_length = source_buffer_length; + } + if(this->source_merge_buffer_length < source_merge_buffer_length || !this->source_merge_buffer) { + if(this->source_merge_buffer) + free(this->source_merge_buffer); + this->source_merge_buffer = (void**) malloc(source_merge_buffer_length); + this->source_merge_buffer_length = source_merge_buffer_length; + } + } + + for(size_t index = 0; index < sources; index++) { + auto& source = this->_sources[index]; + + { + lock_guard lock(source->buffer_lock); + if(source->buffering) { + if(source->buffered_samples > source->min_buffer) { + source->buffering = false; + } else { + this->source_merge_buffer[index] = nullptr; + actual_sources--; + continue; + } + } + } + + if(volume > 0) { + this->source_merge_buffer[index] = (char*) this->source_buffer + (buffer_length * index); + auto written_frames = this->_sources[index]->pop_samples(this->source_merge_buffer[index], frameCount); + if(written_frames != frameCount) { + if(written_frames == 0) { + this->source_merge_buffer[index] = nullptr; + actual_sources--; + } else { + /* fill up the rest with silence (0) */ + auto written = written_frames * this->_channel_count * 4; + memset((char*) this->source_merge_buffer[index] + written, 0, (frameCount - written_frames) * this->_channel_count * 4); + } + } + } else { + this->_sources[index]->pop_samples(nullptr, frameCount); + } + } + } + } + + if(actual_sources > 0 && volume > 0) { + if(!merge::merge_n_sources(output, this->source_merge_buffer, sources, this->_channel_count, frameCount)) { + log_warn(category::audio, tr("failed to merge buffers!")); + } + auto float_length = this->_channel_count * frameCount; + auto data = (float*) output; + while(float_length-- > 0) + *data++ *= volume; + + } else { + memset(output, 0, this->_channel_count * 4 * frameCount); + } + + return 0; +} + +bool AudioOutput::open_device(std::string& error, PaDeviceIndex index) { + lock_guard lock(this->output_stream_lock); + + if(index == this->_current_device_index) + return true; + + this->close_device(); + this->_current_device_index = index; + this->_current_device = Pa_GetDeviceInfo(index); + + if(!this->_current_device) { + this->_current_device_index = paNoDevice; + error = "failed to get device info"; + return false; + } + + PaStreamParameters output_parameters{}; + memset(&output_parameters, 0, sizeof(output_parameters)); + output_parameters.channelCount = (int) this->_channel_count; + output_parameters.device = this->_current_device_index; + output_parameters.sampleFormat = paFloat32; + output_parameters.suggestedLatency = this->_current_device->defaultLowOutputLatency; + + auto err = Pa_OpenStream(&output_stream, nullptr, &output_parameters, (double) this->_sample_rate, paFramesPerBufferUnspecified, paClipOff, &AudioOutput::_audio_callback, this); + if(err != paNoError) { + error = "Pa_OpenStream returned " + to_string(err); + return false; + } + + return true; +} + +bool AudioOutput::playback() { + lock_guard lock(this->output_stream_lock); + if(!this->output_stream) + return false; + + auto err = Pa_StartStream(this->output_stream); + if(err != paNoError && err != paStreamIsNotStopped) { + log_error(category::audio, tr("Pa_StartStream returned {}"), err); + return false; + } + + return true; +} + +void AudioOutput::close_device() { + lock_guard lock(this->output_stream_lock); + if(this->output_stream) { + /* TODO: Test for errors */ + Pa_StopStream(this->output_stream); + Pa_CloseStream(this->output_stream); + + this->output_stream = nullptr; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioOutput.h b/native/serverconnection/src/audio/AudioOutput.h new file mode 100644 index 0000000..64b11be --- /dev/null +++ b/native/serverconnection/src/audio/AudioOutput.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "AudioSamples.h" + +#ifdef WIN32 + #define ssize_t int64_t +#endif + +namespace tc { + namespace audio { + class AudioOutput; + + namespace overflow_strategy { + enum value { + ignore, + discard_buffer_all, + discard_buffer_half, + discard_input + }; + } + class AudioOutputSource { + friend class AudioOutput; + public: + AudioOutput* handle; + + size_t const channel_count = 0; + size_t const sample_rate = 0; + + bool buffering = true; + size_t min_buffer = 0; + + /* For stream set it to the max latency in samples you want. + * Zero means unlimited + */ + size_t max_latency = 0; + overflow_strategy::value overflow_strategy = overflow_strategy::discard_buffer_half; + + /* if it returns true then the it means that the buffer has been refilled, we have to test again */ + std::function on_underflow; + std::function on_overflow; + std::function on_read; /* will be invoked after sample read, e.g. for buffer fullup */ + + void clear(); + ssize_t pop_samples(void* /* output buffer */, size_t /* sample count */); + ssize_t enqueue_samples(const void * /* input buffer */, size_t /* sample count */); + ssize_t enqueue_samples(const std::shared_ptr& /* buffer */); + private: + AudioOutputSource(AudioOutput* handle, size_t channel_count, size_t sample_rate) : handle(handle), channel_count(channel_count), sample_rate(sample_rate) {} + + std::mutex buffer_lock; + size_t buffered_samples = 0; + std::deque> sample_buffers; + }; + + class AudioOutput { + public: + AudioOutput(size_t /* channels */, size_t /* rate */); + virtual ~AudioOutput(); + + bool open_device(std::string& /* error */, PaDeviceIndex); + bool playback(); + void close_device(); + PaDeviceIndex current_device() { return this->_current_device_index; } + + std::deque> sources() { + std::lock_guard lock(this->sources_lock); + return this->_sources; + } + + std::shared_ptr create_source(); + void delete_source(const std::shared_ptr& /* source */); + + inline size_t channel_count() { return this->_channel_count; } + inline size_t sample_rate() { return this->_sample_rate; } + + inline float volume() { return this->_volume; } + inline void set_volume(float value) { this->_volume = value; } + private: + static int _audio_callback(const void *, void *, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); + int audio_callback(const void *, void *, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags); + + size_t const _channel_count; + size_t const _sample_rate; + + std::mutex sources_lock; + std::deque> _sources; + + std::recursive_mutex output_stream_lock; + const PaDeviceInfo* _current_device = nullptr; + PaDeviceIndex _current_device_index = paNoDevice; + PaStream* output_stream = nullptr; + + std::mutex buffer_lock; /* not required, but why not. Usually only used within audio_callback! */ + void* source_buffer = nullptr; + void** source_merge_buffer = nullptr; + + size_t source_buffer_length = 0; + size_t source_merge_buffer_length = 0; + void cleanup_buffers(); + + float _volume = 1.f; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioReframer.cpp b/native/serverconnection/src/audio/AudioReframer.cpp new file mode 100644 index 0000000..ffae477 --- /dev/null +++ b/native/serverconnection/src/audio/AudioReframer.cpp @@ -0,0 +1,49 @@ +#include +#include +#include "AudioReframer.h" + +using namespace tc::audio; + +Reframer::Reframer(size_t channels, size_t frame_size) : _frame_size(frame_size), _channels(channels) { + this->buffer = nullptr; + this->_buffer_index = 0; +} + +Reframer::~Reframer() { + if(this->buffer) + free(this->buffer); +} + +void Reframer::process(const void *source, size_t samples) { + if(!this->buffer) + this->buffer = (float*) malloc(this->_channels * this->_frame_size * sizeof(float)); + assert(this->on_frame); + + if(this->_buffer_index > 0) { + if(this->_buffer_index + samples > this->_frame_size) { + auto required = this->_frame_size - this->_buffer_index; + auto length = required * this->_channels * 4; + + memcpy((char*) this->buffer + this->_buffer_index * 4 * this->_channels, source, length); + samples -= required; + source = (char*) source + length; + + this->on_frame(this->buffer); + } else { + memcpy((char*) this->buffer + this->_buffer_index * 4 * this->_channels, source, samples * this->_channels * 4); + this->_buffer_index += samples; + return; + } + } + + auto _on_frame = this->on_frame; + while(samples > this->_frame_size) { + if(_on_frame) + _on_frame(source); + samples -= this->_frame_size; + source = (char*) source + this->_frame_size * this->_channels * 4; + } + if(samples > 0) + memcpy((char*) this->buffer, source, samples * this->_channels * 4); + this->_buffer_index = samples; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioReframer.h b/native/serverconnection/src/audio/AudioReframer.h new file mode 100644 index 0000000..5d2e14c --- /dev/null +++ b/native/serverconnection/src/audio/AudioReframer.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace tc { + namespace audio { + class Reframer { + public: + Reframer(size_t channels, size_t frame_size); + virtual ~Reframer(); + + void process(const void* /* source */, size_t /* samples */); + + inline size_t channels() { return this->_channels; } + inline size_t frame_size() { return this->_frame_size; } + + std::function on_frame; + private: + void* buffer; + size_t _buffer_index; + + size_t _channels; + size_t _frame_size; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioResampler.cpp b/native/serverconnection/src/audio/AudioResampler.cpp new file mode 100644 index 0000000..43cae70 --- /dev/null +++ b/native/serverconnection/src/audio/AudioResampler.cpp @@ -0,0 +1,43 @@ +#include +#include +#include "AudioResampler.h" +#include "../logger.h" + +using namespace std; +using namespace tc::audio; + +AudioResampler::AudioResampler(size_t irate, size_t orate, size_t channels) : _input_rate(irate), _output_rate(orate), _channels(channels) { + if(this->input_rate() != this->output_rate()) { + soxr_error_t error; + this->soxr_handle = soxr_create((double) this->_input_rate, (double) this->_output_rate, (unsigned) this->_channels, &error, nullptr, nullptr, nullptr); + + if(!this->soxr_handle) { + log_error(category::audio, tr("Failed to create soxr resampler: {}. Input: {}; Output: {}; Channels: {}"), error, this->_input_rate, this->_output_rate, this->_channels); + } + } +} + +AudioResampler::~AudioResampler() { + if(this->soxr_handle) + soxr_delete(this->soxr_handle); +} + +ssize_t AudioResampler::process(void *output, const void *input, size_t input_length) { + if(this->io_ratio() == 1) { + if(input != output) + memcpy(output, input, input_length * this->_channels * 4); + + return input_length; + } + if(!this->soxr_handle) + return -2; + + size_t output_length = 0; + auto error = soxr_process(this->soxr_handle, input, input_length, nullptr, output, this->estimated_output_size(input_length), &output_length); + if(error) { + log_error(category::audio, tr("Failed to process resample: {}"), error); + return -1; + } + + return output_length; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioResampler.h b/native/serverconnection/src/audio/AudioResampler.h new file mode 100644 index 0000000..cef4f55 --- /dev/null +++ b/native/serverconnection/src/audio/AudioResampler.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include +#include + +#if defined(WIN32) && !defined(ssize_t) + #define ssize_t int64_t +#endif + +namespace tc { + namespace audio { + class AudioResampler { + public: + AudioResampler(size_t /* input rate */, size_t /* output rate */, size_t /* channels */); + virtual ~AudioResampler(); + + inline size_t channels() { return this->_channels; } + inline size_t input_rate() { return this->_input_rate; } + inline size_t output_rate() { return this->_output_rate; } + + inline long double io_ratio() { return (long double) this->_output_rate / (long double) this->_input_rate; } + inline size_t estimated_output_size(size_t input_length) { + return (size_t) lroundl(this->io_ratio() * input_length) + 1; + } + + inline bool valid() { return this->io_ratio() == 1 || this->soxr_handle != nullptr; } + + ssize_t process(void* /* output */, const void* /* input */, size_t /* input length */); + private: + size_t const _channels = 0; + size_t const _input_rate = 0; + size_t const _output_rate = 0; + + soxr_t soxr_handle = nullptr; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioSamples.cpp b/native/serverconnection/src/audio/AudioSamples.cpp new file mode 100644 index 0000000..d2364cc --- /dev/null +++ b/native/serverconnection/src/audio/AudioSamples.cpp @@ -0,0 +1,15 @@ +#include "AudioSamples.h" + +using namespace std; +using namespace tc; +using namespace tc::audio; + +std::shared_ptr SampleBuffer::allocate(uint8_t channels, uint16_t samples) { + auto _buffer = (SampleBuffer*) malloc(SampleBuffer::HEAD_LENGTH + channels * samples * 4); + if(!_buffer) + return nullptr; + + _buffer->sample_size = samples; + _buffer->sample_index = 0; + return shared_ptr(_buffer, ::free); +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/AudioSamples.h b/native/serverconnection/src/audio/AudioSamples.h new file mode 100644 index 0000000..6ed93ed --- /dev/null +++ b/native/serverconnection/src/audio/AudioSamples.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +namespace tc { + namespace audio { + +#ifdef WIN32 + #pragma pack(push,1) + #define __attribute__packed_1 +#else + #define __attribute__packed_1 __attribute__((packed, aligned(1))) +#endif + /* Every sample is a float (4byte) */ + struct __attribute__packed_1 SampleBuffer { + static constexpr size_t HEAD_LENGTH = 4; + + uint16_t sample_size; + uint16_t sample_index; + + char sample_data[ +#ifndef WIN32 + 0 +#else + 1 /* windows does not allow zero sized arrays */ +#endif + ]; + + static std::shared_ptr allocate(uint8_t /* channels */, uint16_t /* samples */); + }; + +#ifndef WIN32 + static_assert(sizeof(SampleBuffer) == 4, "Invalid SampleBuffer packaging!"); +#else + #pragma pack(pop) + static_assert(sizeof(SampleBuffer) == 5, "Invalid SampleBuffer packaging!"); +#endif + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/codec/Converter.cpp b/native/serverconnection/src/audio/codec/Converter.cpp new file mode 100644 index 0000000..5bf11ed --- /dev/null +++ b/native/serverconnection/src/audio/codec/Converter.cpp @@ -0,0 +1,34 @@ +// +// Created by wolverindev on 28.04.19. +// + +#include "Converter.h" + +using namespace tc::audio::codec; + +Converter::Converter(size_t c, size_t s, size_t f) : _channels(c), _sample_rate(s), _frame_size(f) {} +Converter::~Converter() {} + +bool type::supported(value type) { +#ifdef HAVE_CODEC_OPUS + if(type == type::opus) + return true; +#endif + +#ifdef HAVE_CODEC_SPEEX + if(type == type::speex) + return true; +#endif + +#ifdef HAVE_CODEC_FLAC + if(type == type::flac) + return true; +#endif + +#ifdef HAVE_CODEC_CELT + if(type == type::celt) + return true; +#endif + + return false; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/codec/Converter.h b/native/serverconnection/src/audio/codec/Converter.h new file mode 100644 index 0000000..fcea8f0 --- /dev/null +++ b/native/serverconnection/src/audio/codec/Converter.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +#if !defined(ssize_t) && defined(WIN32) + #define ssize_t int64_t +#endif + +namespace tc { + namespace audio { + namespace codec { + namespace type { + enum value { + undefined, + + /* supported */ + opus, + speex, + + /* unsupported */ + flac, + celt + }; + + extern bool supported(value); + } + + class Converter { + public: + Converter(size_t /* channels */, size_t /* sample rate */, size_t /* frame size */); + virtual ~Converter(); + + /* initialize parameters depend on the codec */ + virtual bool valid() = 0; + virtual void finalize() = 0; + + virtual void reset_encoder() = 0; + virtual void reset_decoder() = 0; + + /** + * @return number of bytes written on success + */ + virtual ssize_t encode(std::string& /* error */, const void* /* source */, void* /* destination */, size_t /* destination byte length */) = 0; + + /** + * @return number of samples on success + */ + virtual ssize_t decode(std::string& /* error */, const void* /* source */, size_t /* source byte length */, void* /* destination */) = 0; + virtual ssize_t decode_lost(std::string& /* error */, size_t /* packets */) = 0; + + virtual size_t expected_encoded_length(size_t /* sample count */) = 0; + virtual size_t expected_decoded_length(const void* /* source */, size_t /* source byte length */) { + return this->bytes_per_frame(); + } + + inline size_t channels() { return this->_channels; } + inline size_t sample_rate() { return this->_sample_rate; } + inline size_t frame_size() { return this->_frame_size; } + + inline size_t bytes_per_frame() { return this->_channels * this->_frame_size * 4; } + protected: + size_t _frame_size; + size_t _channels; + size_t _sample_rate; + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/codec/OpusConverter.cpp b/native/serverconnection/src/audio/codec/OpusConverter.cpp new file mode 100644 index 0000000..2a2ee96 --- /dev/null +++ b/native/serverconnection/src/audio/codec/OpusConverter.cpp @@ -0,0 +1,143 @@ +#include "OpusConverter.h" +#include "../../logger.h" + +using namespace std; +using namespace tc::audio::codec; + +OpusConverter::OpusConverter(size_t c, size_t s, size_t f) : Converter(c, s, f) { } +OpusConverter::~OpusConverter() {} + +bool OpusConverter::valid() { + return this->encoder && this->decoder; +} + +bool OpusConverter::initialize(std::string &error, int application_type) { + lock_guard lock(this->coder_lock); + this->_application_type = application_type; + + if(!this->_initialize_encoder(error)) + return false; + + if(!this->_initialize_decoder(error)) { + this->reset_encoder(); + return false; + } + + return true; +} + +void OpusConverter::reset_encoder() { + lock_guard lock(this->coder_lock); + + + auto result = opus_encoder_ctl(this->encoder, OPUS_RESET_STATE); + if(result != OPUS_OK) + log_warn(category::audio, tr("Failed to reset opus encoder. Opus result: {}"), result); +} + +void OpusConverter::reset_decoder() { + lock_guard lock(this->coder_lock); + + auto result = opus_decoder_ctl(this->decoder, OPUS_RESET_STATE); + if(result != OPUS_OK) + log_warn(category::audio, tr("Failed to reset opus decoder. Opus result: {}"), result); +} + + +void OpusConverter::finalize() { + lock_guard lock(this->coder_lock); + + if(this->encoder) opus_encoder_destroy(this->encoder); + this->encoder = nullptr; + + if(this->decoder) opus_decoder_destroy(this->decoder); + this->decoder = nullptr; +} + +ssize_t OpusConverter::encode(std::string &error, const void *source, void *target, size_t target_length) { + lock_guard lock(this->coder_lock); + + auto result = opus_encode_float(this->encoder, (float*) source, (int) this->_frame_size, (uint8_t*) target, (opus_int32) target_length); + if(result < OPUS_OK) { + error = to_string(result) + "|" + opus_strerror(result); + return -1; + } + return result; +} + +ssize_t OpusConverter::decode(std::string &error, const void *source, size_t source_length, void *target) { + lock_guard lock(this->coder_lock); + + auto result = opus_decode_float(this->decoder, (uint8_t*) source, (opus_int32) source_length, (float*) target, (int) this->_frame_size, 0); + if(result < OPUS_OK) { + error = to_string(result) + "|" + opus_strerror(result); + return -1; + } + return result; +} + +ssize_t OpusConverter::decode_lost(std::string &error, size_t packets) { + lock_guard lock(this->coder_lock); + + auto buffer = (float*) malloc(this->_frame_size * this->_channels * sizeof(float)); + while (packets-- > 0) { + auto result = opus_decode_float(this->decoder, nullptr, 0, buffer, (int) this->_frame_size, false); + if(result < OPUS_OK) + log_warn(category::audio, tr("Opus decode lost resulted in error: {}"), result); + } + free(buffer); + return 0; +} + +size_t OpusConverter::expected_encoded_length(size_t sample_count) { + //TODO calculate stuff + return 512; +} + +bool OpusConverter::_initialize_decoder(std::string &error) { + if(!this->_finalize_decoder(error)) + return false; + + int error_id = 0; + this->decoder = opus_decoder_create((opus_int32) this->_sample_rate, (int) this->_channels, &error_id); + if(!this->encoder || error_id) { + error = "failed to create decoder (" + to_string(error_id) + ")"; + return false; + } + return true; +} + +bool OpusConverter::_initialize_encoder(std::string &error) { + if(!this->_finalize_encoder(error)) + return false; + + int error_id = 0; + this->encoder = opus_encoder_create((opus_int32) this->_sample_rate, (int) this->_channels, this->_application_type, &error_id); + if(!this->encoder || error_id) { + error = "failed to create encoder (" + to_string(error_id) + ")"; + return false; + } + + error_id = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(64000)); + if(error_id) { + error = "failed to set bitrate (" + to_string(error_id) + ")"; + return false; + } + return true; +} + +bool OpusConverter::_finalize_decoder(std::string &) { + if(this->decoder) { + opus_decoder_destroy(this->decoder); + this->decoder = nullptr; + } + return true; +} + +bool OpusConverter::_finalize_encoder(std::string &) { + if(this->encoder) { + opus_encoder_destroy(this->encoder); + this->encoder = nullptr; + } + return true; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/codec/OpusConverter.h b/native/serverconnection/src/audio/codec/OpusConverter.h new file mode 100644 index 0000000..8a9f17c --- /dev/null +++ b/native/serverconnection/src/audio/codec/OpusConverter.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Converter.h" +#include +#include + +namespace tc { + namespace audio { + namespace codec { + class OpusConverter : public Converter { + public: + OpusConverter(size_t /* channels */, size_t /* sample rate */, size_t /* frame size */); + virtual ~OpusConverter(); + + bool valid() override; + + bool initialize(std::string& /* error */, int /* application type */); + void finalize() override; + + void reset_encoder() override; + void reset_decoder() override; + + ssize_t encode(std::string & /* error */, const void * /* source */, void * /* target */, size_t /* target size */) override; + ssize_t decode(std::string & /* error */, const void * /* source */, size_t /* source size */, void *pVoid1) override; + + ssize_t decode_lost(std::string &string, size_t /* packets */) override; + + size_t expected_encoded_length(size_t size) override; + private: + std::mutex coder_lock; + OpusDecoder* decoder = nullptr; + OpusEncoder* encoder = nullptr; + + int _application_type = 0; + + bool _finalize_encoder(std::string& /* error */); + bool _finalize_decoder(std::string& /* error */); + bool _initialize_encoder(std::string& /* error */); + bool _initialize_decoder(std::string& /* error */); + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/filter/Filter.h b/native/serverconnection/src/audio/filter/Filter.h new file mode 100644 index 0000000..7770ffe --- /dev/null +++ b/native/serverconnection/src/audio/filter/Filter.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace tc { + namespace audio { + namespace filter { + class Filter { + public: + Filter(size_t channel_count, size_t sample_rate, size_t frame_size) : + _frame_size(frame_size), _sample_rate(sample_rate), _channels(channel_count) {} + + virtual bool process(const void* /* buffer */) = 0; + + inline size_t sample_rate() { return this->_sample_rate; } + inline size_t channels() { return this->_channels; } + inline size_t frame_size() { return this->_frame_size; } + + protected: + size_t _frame_size; + size_t _sample_rate; + size_t _channels; + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/filter/FilterState.cpp b/native/serverconnection/src/audio/filter/FilterState.cpp new file mode 100644 index 0000000..ae54a83 --- /dev/null +++ b/native/serverconnection/src/audio/filter/FilterState.cpp @@ -0,0 +1,17 @@ +#include "FilterState.h" +#include "Filter.h" + +using namespace std; +using namespace tc::audio; +using namespace tc::audio::filter; + +StateFilter::StateFilter(size_t a, size_t b, size_t c) : Filter(a, b, c) {} +StateFilter::~StateFilter() {} + +bool StateFilter::initialize(std::string &) { + return true; +} + +bool StateFilter::process(const void *_buffer) { + return !this->_consume; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/filter/FilterState.h b/native/serverconnection/src/audio/filter/FilterState.h new file mode 100644 index 0000000..b5501cd --- /dev/null +++ b/native/serverconnection/src/audio/filter/FilterState.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Filter.h" +#include +#include + +namespace tc { + namespace audio { + namespace filter { + class StateFilter : public Filter { + public: + StateFilter(size_t /* channel count */, size_t /* sample rate */, size_t /* frame size */); + virtual ~StateFilter(); + + bool initialize(std::string& /* error */); + bool process(const void* /* buffer */) override; + + inline bool consumes_input() { return this->_consume; } + inline void set_consume_input(bool state) { this->_consume = state; } + private: + bool _consume = false; + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/filter/FilterThreshold.cpp b/native/serverconnection/src/audio/filter/FilterThreshold.cpp new file mode 100644 index 0000000..3919188 --- /dev/null +++ b/native/serverconnection/src/audio/filter/FilterThreshold.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include "FilterThreshold.h" +#include "../../logger.h" + +using namespace std; +using namespace tc::audio; +using namespace tc::audio::filter; + +ThresholdFilter::ThresholdFilter(size_t a, size_t b, size_t c) : Filter(a, b, c) {} +ThresholdFilter::~ThresholdFilter() {} + +bool ThresholdFilter::initialize(std::string &, float val, size_t margin) { + this->_threshold = val; + this->_margin_frames = margin; + return true; +} + +/* technique based on http://www.vttoth.com/CMS/index.php/technical-notes/68 */ +inline float merge_ab(float a, float b, float n) { + /* + * Form: A,B := [0;n] + * IF A <= n/2 AND B <= N/2 + * Z = (2 * A * B) / n + * ELSE + * Z = 2(A + B) - (2/n) * A * B - n + * + * For a range from 0 to 2: Z = 2(A + B) - AB - 2 + */ + + auto half_n = n / 2; + auto inv_half_n = 1 / half_n; + + if(a < half_n && b < half_n) + return inv_half_n * a * b; + + return 2 * (a + b) - inv_half_n * a * b - n; +} + +bool ThresholdFilter::process(const void *_buffer) { + float value = -1; + auto analyze_callback = this->on_analyze; + + for(size_t channel = 0; channel < this->_channels; channel++) { + auto percentage = this->analyze(_buffer, channel); + + if(channel == 0) + value = (float) percentage; + else + value = merge_ab(value, (float) percentage, 100); + } + + auto last_level = this->_current_level; + float smooth; + if(this->_margin_processed_frames == 0) /* we're in release */ + smooth = this->_release_smooth; + else + smooth = this->_attack_smooth; + + this->_current_level = last_level * smooth + value * (1 - smooth); + //log_trace(category::audio, "Vad level: before: {}, edit: {}, now: {}, smooth: {}", last_level, value, this->_current_level, smooth); + + if(analyze_callback) + analyze_callback(this->_current_level); + + if(this->_current_level >= this->_threshold) { + this->_margin_processed_frames = 0; + return true; + } + + return this->_margin_processed_frames++ < this->_margin_frames; +} + + +long double ThresholdFilter::analyze(const void *_buffer, size_t channel) { + /* equation taken from the web client */ + + auto buffer = (float*) _buffer; + buffer += channel; + + long double value = 0; + auto sample = this->_frame_size; + + while(sample-- > 0) { + const auto num = floorl(*buffer * 127) / 127.f; /* to be like the web client */ + value += num * num; + buffer += this->_channels; + } + + long double rms = sqrtl(value / (long double) this->_frame_size); + auto db = (long double) 20 * (log(rms) / log(10)); + db = max((long double) -192, min(db, (long double) 0)); + + + float percentage = (float) (100 + (db * 1.92f)); + return max(0.f, min(percentage, 100.f)); +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/filter/FilterThreshold.h b/native/serverconnection/src/audio/filter/FilterThreshold.h new file mode 100644 index 0000000..1285021 --- /dev/null +++ b/native/serverconnection/src/audio/filter/FilterThreshold.h @@ -0,0 +1,46 @@ +#pragma once + +#include "Filter.h" +#include +#include +#include + +namespace tc { + namespace audio { + namespace filter { + class ThresholdFilter : public Filter { + public: + ThresholdFilter(size_t /* channel count */, size_t /* sample rate */, size_t /* frame size */); + virtual ~ThresholdFilter(); + + bool initialize(std::string& /* error */, float /* threshold */, size_t /* margin frames */); + bool process(const void* /* buffer */) override; + + long double analyze(const void* /* buffer */, size_t /* channel */); + + inline float threshold() { return this->_threshold; } + inline void set_threshold(float value) { this->_threshold = value; } + + inline size_t margin_frames() { return this->_margin_frames; } + inline void set_margin_frames(size_t value) { this->_margin_frames = value; } + + inline void attack_smooth(float value) { this->_attack_smooth = value; } + inline float attack_smooth() { return this->_attack_smooth; } + + inline void release_smooth(float value) { this->_release_smooth = value; } + inline float release_smooth() { return this->_release_smooth; } + + std::function on_analyze; + private: + float _attack_smooth = 0; + float _release_smooth = 0; + float _current_level = 0; + + float _threshold; + + size_t _margin_frames = 0; + size_t _margin_processed_frames = 0; + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/filter/FilterVad.cpp b/native/serverconnection/src/audio/filter/FilterVad.cpp new file mode 100644 index 0000000..d38c3a8 --- /dev/null +++ b/native/serverconnection/src/audio/filter/FilterVad.cpp @@ -0,0 +1,108 @@ +#include +#include "FilterVad.h" +#include "../AudioMerger.h" +#include "../../logger.h" + +using namespace std; +using namespace tc::audio; +using namespace tc::audio::filter; + +VadFilter::VadFilter(size_t channels, size_t rate, size_t frames) : Filter(channels, rate, frames) { } + +VadFilter::~VadFilter() { + this->cleanup_buffer(); + if(this->_vad_handle) { + fvad_free(this->_vad_handle); + this->_vad_handle = nullptr; + } +} + +void VadFilter::cleanup_buffer() { + lock_guard lock(this->_buffer_lock); + if(this->_buffer) + free(this->_buffer); + this->_buffer = nullptr; + this->_buffer_size = 0; +} + +bool VadFilter::initialize(std::string &error, size_t mode, size_t margin) { + + this->_vad_handle = fvad_new(); + if(!this->_vad_handle) { + error = "failed to allocate handle"; + return false; + } + + if(fvad_set_sample_rate(this->_vad_handle, (int) this->_sample_rate) != 0) { + error = "invalid sample rate. Sample rate must be one of [8000, 16000, 32000 and 48000]"; + return false; + } + + if(fvad_set_mode(this->_vad_handle, (int) mode) != 0) { + error = "failed to set mode"; + return false; + } + + this->_mode = mode; + this->_margin_frames = margin; + if(this->_channels > 1) { + this->ensure_buffer(this->_frame_size * this->_channels * 4); /* buffer to merge the channels into one channel */ + } else { + this->ensure_buffer(this->_frame_size * 2); + } + + return true; +} + +bool VadFilter::process(const void *buffer) { + if(!this->_vad_handle) { + log_warn(category::audio, tr("Vad filter hasn't been initialized!")); + return false; + } + + lock_guard lock(this->_buffer_lock); + if(this->_channels > 1) { + if(!merge::merge_channels_interleaved(this->_buffer, 1, buffer, this->_channels, this->_frame_size)) { + log_warn(category::audio, tr("Failed to merge channels")); + return false; + } + buffer = this->_buffer; + } + + /* convert float32 samples to signed int16 */ + { + auto target = (int16_t*) this->_buffer; + auto source = (float*) buffer; + auto sample = this->_frame_size; + + float tmp; + while(sample-- > 0) { + tmp = *source++; + tmp *= 32768; + + if(tmp > 32767) + tmp = 32767; + + if(tmp < -32768) + tmp = -32768; + + *target++ = (int16_t) tmp; + } + } + + auto result = fvad_process(this->_vad_handle, (int16_t*) this->_buffer, this->_frame_size); + if(result == -1) { + log_warn(category::audio, tr("Invalid frame length")); + return false; + } + + auto flag_vad = result == 1; + + if(!flag_vad) { + this->_margin_processed_frames++; + return this->_margin_processed_frames <= this->_margin_frames; + } else { + this->_margin_processed_frames = 0; + } + return flag_vad; +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/filter/FilterVad.h b/native/serverconnection/src/audio/filter/FilterVad.h new file mode 100644 index 0000000..c09a300 --- /dev/null +++ b/native/serverconnection/src/audio/filter/FilterVad.h @@ -0,0 +1,46 @@ +#pragma once + +#include "Filter.h" +#include +#include + +namespace tc { + namespace audio { + namespace filter { + class VadFilter : public Filter { + public: + VadFilter(size_t /* channel count */, size_t /* sample rate */, size_t /* frame size */); + virtual ~VadFilter(); + + bool initialize(std::string& /* error */, size_t /* mode */, size_t /* margin frames */); + bool process(const void* /* buffer */) override; + + inline size_t margin_frames() { return this->_margin_frames; } + inline void set_margin_frames(size_t value) { this->_margin_frames = value; } + + inline size_t mode() { return this->_mode; } + private: + Fvad* _vad_handle = nullptr; + + size_t _mode = 0; + size_t _margin_frames = 0; + size_t _margin_processed_frames = 0; + + std::mutex _buffer_lock; + void* _buffer = nullptr; + size_t _buffer_size = 0; + + void cleanup_buffer(); + inline void ensure_buffer(size_t length) { + if(this->_buffer_size < length) { + if(this->_buffer) + free(this->_buffer); + + this->_buffer_size = length; + this->_buffer = malloc(this->_buffer_size); + } + } + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioConsumer.cpp b/native/serverconnection/src/audio/js/AudioConsumer.cpp new file mode 100644 index 0000000..c3c7075 --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioConsumer.cpp @@ -0,0 +1,322 @@ +#include "AudioConsumer.h" +#include "AudioRecorder.h" +#include "AudioFilter.h" +#include "../AudioInput.h" +#include "../filter/Filter.h" +#include "../filter/FilterVad.h" +#include "../filter/FilterThreshold.h" +#include "../filter/FilterState.h" +#include "../../logger.h" + +using namespace std; +using namespace tc::audio; +using namespace tc::audio::recorder; + +NAN_MODULE_INIT(AudioConsumerWrapper::Init) { + auto klass = Nan::New(AudioConsumerWrapper::NewInstance); + klass->SetClassName(Nan::New("AudioConsumer").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "get_filters", AudioConsumerWrapper::_get_filters); + Nan::SetPrototypeMethod(klass, "unregister_filter", AudioConsumerWrapper::_unregister_filter); + + Nan::SetPrototypeMethod(klass, "create_filter_vad", AudioConsumerWrapper::_create_filter_vad); + Nan::SetPrototypeMethod(klass, "create_filter_threshold", AudioConsumerWrapper::_create_filter_threshold); + Nan::SetPrototypeMethod(klass, "create_filter_state", AudioConsumerWrapper::_create_filter_state); + + constructor_template().Reset(klass); + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(AudioConsumerWrapper::NewInstance) { + if(!info.IsConstructCall()) + Nan::ThrowError("invalid invoke!"); +} + +AudioConsumerWrapper::AudioConsumerWrapper(AudioRecorderWrapper* h, const std::shared_ptr &handle) : _handle(handle), _recorder(h) { + log_allocate("AudioConsumerWrapper", this); + { + lock_guard read_lock(handle->on_read_lock); + handle->on_read = [&](const void* buffer, size_t length){ this->process_data(buffer, length); }; + } + +#ifdef DO_DEADLOCK_REF + this->_recorder->js_ref(); /* FML Mem leak! (In general the consumer live is related to the recorder handle, but for nodejs testing we want to keep this reference ) */ +#endif +} + +AudioConsumerWrapper::~AudioConsumerWrapper() { + log_free("AudioConsumerWrapper", this); + + lock_guard lock(this->execute_lock); + this->unbind(); + if(this->_handle->handle) { + this->_handle->handle->delete_consumer(this->_handle); + this->_handle = nullptr; + } + +#ifdef DO_DEADLOCK_REF + if(this->_recorder) + this->_recorder->js_unref(); +#endif +} + +void AudioConsumerWrapper::do_wrap(const v8::Local &obj) { + this->Wrap(obj); + + this->_call_data = Nan::async_callback([&] { + Nan::HandleScope scope; + + auto handle = this->handle(); + v8::Local callback_function = handle->Get(Nan::New("callback_data").ToLocalChecked()); + if(callback_function.IsEmpty() || callback_function->IsNullOrUndefined() || !callback_function->IsFunction()) { + lock_guard lock(this->_data_lock); + this->_data_entries.clear(); + } + + std::unique_ptr buffer; + while(true) { + { + lock_guard lock(this->_data_lock); + if(this->_data_entries.empty()) + break; + buffer = move(this->_data_entries.front()); + this->_data_entries.pop_front(); + } + + const auto byte_length = buffer->sample_count * this->_handle->channel_count * 4; + auto js_buffer = v8::ArrayBuffer::New(Nan::GetCurrentContext()->GetIsolate(), byte_length); + auto js_fbuffer = v8::Float32Array::New(js_buffer, 0, byte_length / 4); + + memcpy(js_buffer->GetContents().Data(), buffer->buffer, byte_length); + + v8::Local argv[1]; + argv[0] = js_fbuffer; + callback_function.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, argv); + } + }); + + this->_call_ended = Nan::async_callback([&]{ + Nan::HandleScope scope; + + auto handle = this->handle(); + v8::Local callback_function = handle->Get(Nan::New("callback_ended").ToLocalChecked()); + if(callback_function.IsEmpty() || callback_function->IsNullOrUndefined() || !callback_function->IsFunction()) + return; + callback_function.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); + }); + + this->_call_started = Nan::async_callback([&]{ + Nan::HandleScope scope; + + auto handle = this->handle(); + v8::Local callback_function = handle->Get(Nan::New("callback_started").ToLocalChecked()); + if(callback_function.IsEmpty() || callback_function->IsNullOrUndefined() || !callback_function->IsFunction()) + return; + callback_function.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); + }); + + Nan::Set(this->handle(), Nan::New("frame_size").ToLocalChecked(), Nan::New(this->_handle->frame_size)); + Nan::Set(this->handle(), Nan::New("sample_rate").ToLocalChecked(), Nan::New(this->_handle->sample_rate)); + Nan::Set(this->handle(), Nan::New("channels").ToLocalChecked(), Nan::New(this->_handle->channel_count)); +} + +void AudioConsumerWrapper::unbind() { + if(this->_handle) { + lock_guard lock(this->_handle->on_read_lock); + this->_handle->on_read = nullptr; + } +} + +void AudioConsumerWrapper::process_data(const void *buffer, size_t samples) { + lock_guard lock(this->execute_lock); + + auto filters = this->filters(); + for(const auto& filter : filters) { + auto _filter = filter->filter(); + if(!_filter) continue; + + if(_filter->frame_size() != samples) { + cerr << "Tried to use a filter, but frame size does not match!" << endl; + continue; + } + if(!_filter->process(buffer)) { + if(!this->last_consumed) { + this->last_consumed = true; + this->_call_ended(); + unique_lock native_read_lock(this->native_read_callback_lock); + if(this->native_read_callback) { + auto callback = this->native_read_callback; /* copy */ + native_read_lock.unlock(); + callback(nullptr, 0); /* notify end */ + } + } + return; + } + } + + if(this->last_consumed) + this->_call_started(); + this->last_consumed = false; + + { + unique_lock native_read_lock(this->native_read_callback_lock); + if(this->native_read_callback) { + auto callback = this->native_read_callback; /* copy */ + native_read_lock.unlock(); + + callback(buffer, samples); + return; + } + } + + auto byte_length = samples * this->_handle->channel_count * 4; + auto buf = make_unique(); + buf->buffer = malloc(byte_length); + memcpy(buf->buffer, buffer, byte_length); + buf->sample_count = samples; + + { + lock_guard lock(this->_data_lock); + this->_data_entries.push_back(move(buf)); + } + this->_call_data(); +} + + + +std::shared_ptr AudioConsumerWrapper::create_filter(const std::string& name, const std::shared_ptr &impl) { + auto result = shared_ptr(new AudioFilterWrapper(name, impl), [](AudioFilterWrapper* ptr) { + assert(v8::Isolate::GetCurrent()); + ptr->Unref(); + }); + + /* wrap into object */ + { + auto js_object = Nan::NewInstance(Nan::New(AudioFilterWrapper::constructor()), 0, nullptr).ToLocalChecked(); + result->do_wrap(js_object); + result->Ref(); + } + + { + lock_guard lock(this->_filters_lock); + this->_filters.push_back(result); + } + + return result; +} + +void AudioConsumerWrapper::delete_filter(const AudioFilterWrapper* filter) { + shared_ptr handle; /* need to keep the handle 'till everything has been finished */ + { + lock_guard lock(this->_filters_lock); + for(auto& c : this->_filters) { + if(&*c == filter) { + handle = c; + break; + } + } + if(!handle) + return; + + { + auto it = find(this->_filters.begin(), this->_filters.end(), handle); + if(it != this->_filters.end()) + this->_filters.erase(it); + } + } + + { + lock_guard lock(this->execute_lock); /* ensure that the filter isn't used right now */ + handle->_filter = nullptr; + } +} + + +NAN_METHOD(AudioConsumerWrapper::_get_filters) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto filters = handle->filters(); + + auto result = Nan::New(filters.size()); + + for(size_t index = 0; index < filters.size(); index++) + result->Set(index, filters[index]->handle()); + + info.GetReturnValue().Set(result); +} + +NAN_METHOD(AudioConsumerWrapper::_unregister_filter) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + + if(info.Length() != 1 || !info[0]->IsObject()) { + Nan::ThrowError("invalid argument"); + return; + } + + if(!Nan::New(AudioFilterWrapper::constructor_template())->HasInstance(info[0])) { + Nan::ThrowError("invalid consumer"); + return; + } + + auto consumer = ObjectWrap::Unwrap(info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked()); + handle->delete_filter(consumer); +} + + +NAN_METHOD(AudioConsumerWrapper::_create_filter_vad) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto consumer = handle->_handle; + assert(consumer); /* should never be null! */ + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid argument"); + return; + } + + string error; + auto filter = make_shared(consumer->channel_count,consumer->sample_rate,consumer->frame_size); + if(!filter->initialize(error, info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0), 2)) { + Nan::ThrowError(Nan::New("failed to initialize filter (" + error + ")").ToLocalChecked()); + return; + } + + auto object = handle->create_filter("vad", filter); + info.GetReturnValue().Set(object->handle()); +} + +NAN_METHOD(AudioConsumerWrapper::_create_filter_threshold) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto consumer = handle->_handle; + assert(consumer); /* should never be null! */ + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid argument"); + return; + } + + string error; + auto filter = make_shared(consumer->channel_count,consumer->sample_rate,consumer->frame_size); + if(!filter->initialize(error, info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0), 2)) { + Nan::ThrowError(Nan::New("failed to initialize filter (" + error + ")").ToLocalChecked()); + return; + } + + auto object = handle->create_filter("threshold", filter); + info.GetReturnValue().Set(object->handle()); +} + +NAN_METHOD(AudioConsumerWrapper::_create_filter_state) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto consumer = handle->_handle; + assert(consumer); /* should never be null! */ + + string error; + auto filter = make_shared(consumer->channel_count,consumer->sample_rate,consumer->frame_size); + if(!filter->initialize(error)) { + Nan::ThrowError(Nan::New("failed to initialize filter (" + error + ")").ToLocalChecked()); + return; + } + + auto object = handle->create_filter("state", filter); + info.GetReturnValue().Set(object->handle()); +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioConsumer.h b/native/serverconnection/src/audio/js/AudioConsumer.h new file mode 100644 index 0000000..00658e9 --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioConsumer.h @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include +#include + +namespace tc { + namespace audio { + class AudioInput; + class AudioConsumer; + + namespace filter { + class Filter; + } + + namespace recorder { + class AudioFilterWrapper; + class AudioRecorderWrapper; + /* + get_filters() : ConsumeFilter[]; + + register_filter(filter: ConsumeFilter); + unregister_filter(filter: ConsumeFilter); + + create_filter_vad() : VADConsumeFilter; + create_filter_threshold() : ThresholdConsumeFilter; + */ + + class AudioConsumerWrapper : public Nan::ObjectWrap { + friend class AudioRecorderWrapper; + public: + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + static inline Nan::Persistent & constructor_template() { + static Nan::Persistent my_constructor_template; + return my_constructor_template; + } + + AudioConsumerWrapper(AudioRecorderWrapper*, const std::shared_ptr& /* handle */); + ~AudioConsumerWrapper() override; + + static NAN_METHOD(_get_filters); + static NAN_METHOD(_unregister_filter); + + static NAN_METHOD(_create_filter_vad); + static NAN_METHOD(_create_filter_threshold); + static NAN_METHOD(_create_filter_state); + + std::shared_ptr create_filter(const std::string& /* name */, const std::shared_ptr& /* filter impl */); + void delete_filter(const AudioFilterWrapper*); + + inline std::deque> filters() { + std::lock_guard lock(this->_filters_lock); + return this->_filters; + } + + inline std::shared_ptr native_consumer() { return this->_handle; } + + std::mutex native_read_callback_lock; + std::function native_read_callback; + private: + AudioRecorderWrapper* _recorder; + + std::mutex execute_lock; + std::shared_ptr _handle; + + std::mutex _filters_lock; + std::deque> _filters; + bool last_consumed = false; + + void do_wrap(const v8::Local& /* object */); + + void unbind(); /* called with execute_lock locked */ + void process_data(const void* /* buffer */, size_t /* samples */); + + struct DataEntry { + void* buffer = nullptr; + size_t sample_count = 0; + + ~DataEntry() { + if(buffer) + free(buffer); + } + }; + + std::mutex _data_lock; + std::deque> _data_entries; + + Nan::callback_t<> _call_data; + Nan::callback_t<> _call_ended; + Nan::callback_t<> _call_started; + /* + callback_data: (buffer: Float32Array) => any; + callback_ended: () => any; + */ + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioFilter.cpp b/native/serverconnection/src/audio/js/AudioFilter.cpp new file mode 100644 index 0000000..c456df1 --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioFilter.cpp @@ -0,0 +1,321 @@ +#include "AudioFilter.h" +#include "../filter/FilterVad.h" +#include "../filter/FilterThreshold.h" +#include "../filter/FilterState.h" +#include "../../logger.h" + +using namespace std; +using namespace tc::audio; +using namespace tc::audio::recorder; + + +NAN_MODULE_INIT(AudioFilterWrapper::Init) { + auto klass = Nan::New(AudioFilterWrapper::NewInstance); + klass->SetClassName(Nan::New("AudioFilter").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "get_name", AudioFilterWrapper::_get_name); + + Nan::SetPrototypeMethod(klass, "get_margin_frames", AudioFilterWrapper::_get_margin_frames); + Nan::SetPrototypeMethod(klass, "set_margin_frames", AudioFilterWrapper::_set_margin_frames); + + Nan::SetPrototypeMethod(klass, "get_level", AudioFilterWrapper::_get_level); + + Nan::SetPrototypeMethod(klass, "get_threshold", AudioFilterWrapper::_get_threshold); + Nan::SetPrototypeMethod(klass, "set_threshold", AudioFilterWrapper::_set_threshold); + + Nan::SetPrototypeMethod(klass, "get_attack_smooth", AudioFilterWrapper::_get_attack_smooth); + Nan::SetPrototypeMethod(klass, "set_attack_smooth", AudioFilterWrapper::_set_attack_smooth); + + Nan::SetPrototypeMethod(klass, "get_release_smooth", AudioFilterWrapper::_get_release_smooth); + Nan::SetPrototypeMethod(klass, "set_release_smooth", AudioFilterWrapper::_set_release_smooth); + + Nan::SetPrototypeMethod(klass, "set_analyze_filter", AudioFilterWrapper::_set_analyze_filter); + + Nan::SetPrototypeMethod(klass, "is_consuming", AudioFilterWrapper::_is_consuming); + Nan::SetPrototypeMethod(klass, "set_consuming", AudioFilterWrapper::_set_consuming); + + constructor_template().Reset(klass); + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(AudioFilterWrapper::NewInstance) { + if(!info.IsConstructCall()) + Nan::ThrowError("invalid invoke!"); +} + +AudioFilterWrapper::AudioFilterWrapper(const std::string& name, const std::shared_ptr &filter) : _filter(filter), _name(name) { + auto threshold_filter = dynamic_pointer_cast(this->_filter); + if(threshold_filter) { + this->_call_analyzed = Nan::async_callback([&](float value) { + Nan::HandleScope scope; + + if(!this->_callback_analyzed.IsEmpty()) { + auto cb = Nan::New(this->_callback_analyzed); + + v8::Local argv[1]; + argv[0] = Nan::New(value); + + cb->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, argv); + } + }); + } + log_allocate("AudioFilterWrapper", this); +} +AudioFilterWrapper::~AudioFilterWrapper() { + log_free("AudioFilterWrapper", this); + + auto threshold_filter = dynamic_pointer_cast(this->_filter); + if(threshold_filter) + threshold_filter->on_analyze = nullptr; + + this->_callback_analyzed.Reset(); +} + +void AudioFilterWrapper::do_wrap(const v8::Local &obj) { + this->Wrap(obj); +} + +NAN_METHOD(AudioFilterWrapper::_get_name) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + + info.GetReturnValue().Set(Nan::New(handle->_name).ToLocalChecked()); +} + +NAN_METHOD(AudioFilterWrapper::_get_level) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + info.GetReturnValue().Set((int) filter->mode()); +} + + +NAN_METHOD(AudioFilterWrapper::_get_margin_frames) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + + auto vad_filter = dynamic_pointer_cast(handle->_filter); + auto threshold_filter = dynamic_pointer_cast(handle->_filter); + if(vad_filter) { + info.GetReturnValue().Set((int) vad_filter->margin_frames()); + } else if(threshold_filter) { + info.GetReturnValue().Set((int) threshold_filter->margin_frames()); + } else { + Nan::ThrowError("invalid handle"); + return; + } +} + +NAN_METHOD(AudioFilterWrapper::_set_margin_frames) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid argument"); + return; + } + + auto vad_filter = dynamic_pointer_cast(handle->_filter); + auto threshold_filter = dynamic_pointer_cast(handle->_filter); + if(vad_filter) { + vad_filter->set_margin_frames(info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); + } else if(threshold_filter) { + threshold_filter->set_margin_frames(info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); + } else { + Nan::ThrowError("invalid handle"); + return; + } +} + + +NAN_METHOD(AudioFilterWrapper::_get_threshold) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + info.GetReturnValue().Set((int) filter->threshold()); +} + + +NAN_METHOD(AudioFilterWrapper::_set_threshold) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid argument"); + return; + } + + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + filter->set_threshold(info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); +} + +NAN_METHOD(AudioFilterWrapper::_get_attack_smooth) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + info.GetReturnValue().Set((int) filter->attack_smooth()); +} + +NAN_METHOD(AudioFilterWrapper::_set_attack_smooth) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid argument"); + return; + } + + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + filter->attack_smooth(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); +} + +NAN_METHOD(AudioFilterWrapper::_get_release_smooth) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + info.GetReturnValue().Set((int) filter->release_smooth()); +} + +NAN_METHOD(AudioFilterWrapper::_set_release_smooth) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid argument"); + return; + } + + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + filter->release_smooth(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); +} + +NAN_METHOD(AudioFilterWrapper::_set_analyze_filter) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + + if(info.Length() != 1 || !(info[0]->IsFunction() || info[0]->IsNullOrUndefined())) { + Nan::ThrowError("invalid argument"); + return; + } + + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + if(info[0]->IsNullOrUndefined()) { + handle->_callback_analyzed.Reset(); + filter->on_analyze = nullptr; + } else { + handle->_callback_analyzed.Reset(info[0].As()); + filter->on_analyze = [handle](float value){ + handle->_call_analyzed.call(std::forward(value), true); + }; + } +} + + +NAN_METHOD(AudioFilterWrapper::_is_consuming) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + info.GetReturnValue().Set(filter->consumes_input()); +} +NAN_METHOD(AudioFilterWrapper::_set_consuming) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + if(!handle->_filter) { + Nan::ThrowError("invalid handle"); + return; + } + + if(info.Length() != 1 || !info[0]->IsBoolean()) { + Nan::ThrowError("invalid argument"); + return; + } + + auto filter = dynamic_pointer_cast(handle->_filter); + if(!filter) { + Nan::ThrowError("filter does not support this method"); + return; + } + + filter->set_consume_input(info[0]->BooleanValue(info.GetIsolate())); +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioFilter.h b/native/serverconnection/src/audio/js/AudioFilter.h new file mode 100644 index 0000000..ecd6b24 --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioFilter.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include + +namespace tc { + namespace audio { + namespace filter { + class Filter; + } + + namespace recorder { + class AudioConsumerWrapper; + + class AudioFilterWrapper : public Nan::ObjectWrap { + friend class AudioConsumerWrapper; + public: + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + static inline Nan::Persistent & constructor_template() { + static Nan::Persistent my_constructor_template; + return my_constructor_template; + } + + AudioFilterWrapper(const std::string& name, const std::shared_ptr& /* handle */); + virtual ~AudioFilterWrapper(); + + static NAN_METHOD(_get_name); + + /* VAD and Threshold */ + static NAN_METHOD(_get_margin_frames); + static NAN_METHOD(_set_margin_frames); + + /* VAD relevant */ + static NAN_METHOD(_get_level); + + /* threshold filter relevant */ + static NAN_METHOD(_get_threshold); + static NAN_METHOD(_set_threshold); + + static NAN_METHOD(_get_attack_smooth); + static NAN_METHOD(_set_attack_smooth); + + static NAN_METHOD(_get_release_smooth); + static NAN_METHOD(_set_release_smooth); + + static NAN_METHOD(_set_analyze_filter); + + /* consume filter */ + static NAN_METHOD(_is_consuming); + static NAN_METHOD(_set_consuming); + + inline std::shared_ptr filter() { return this->_filter; } + private: + std::shared_ptr _filter; + std::string _name; + + void do_wrap(const v8::Local& /* object */); + + Nan::callback_t _call_analyzed; + Nan::Persistent _callback_analyzed; + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioOutputStream.cpp b/native/serverconnection/src/audio/js/AudioOutputStream.cpp new file mode 100644 index 0000000..90c58ac --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioOutputStream.cpp @@ -0,0 +1,285 @@ +#include +#include "AudioOutputStream.h" +#include "../AudioOutput.h" +#include "../AudioResampler.h" + +using namespace std; +using namespace tc; +using namespace tc::audio; + +NAN_MODULE_INIT(AudioOutputStreamWrapper::Init) { + auto klass = Nan::New(AudioOutputStreamWrapper::NewInstance); + klass->SetClassName(Nan::New("AudioOutputStream").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "write_data", AudioOutputStreamWrapper::_write_data); + + Nan::SetPrototypeMethod(klass, "get_buffer_latency", AudioOutputStreamWrapper::_get_buffer_latency); + Nan::SetPrototypeMethod(klass, "set_buffer_latency", AudioOutputStreamWrapper::_set_buffer_latency); + + Nan::SetPrototypeMethod(klass, "get_buffer_max_latency", AudioOutputStreamWrapper::_get_buffer_max_latency); + Nan::SetPrototypeMethod(klass, "set_buffer_max_latency", AudioOutputStreamWrapper::_set_buffer_max_latency); + + Nan::SetPrototypeMethod(klass, "write_data", AudioOutputStreamWrapper::_write_data); + Nan::SetPrototypeMethod(klass, "write_data_rated", AudioOutputStreamWrapper::_write_data_rated); + Nan::SetPrototypeMethod(klass, "deleted", AudioOutputStreamWrapper::_deleted); + Nan::SetPrototypeMethod(klass, "delete", AudioOutputStreamWrapper::_delete); + Nan::SetPrototypeMethod(klass, "clear", AudioOutputStreamWrapper::_clear); + + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(AudioOutputStreamWrapper::NewInstance) { + if(!info.IsConstructCall()) + Nan::ThrowError("invalid invoke!"); +} + + +AudioOutputStreamWrapper::AudioOutputStreamWrapper(const std::shared_ptr &stream, bool owns) { + this->_handle = stream; + if(owns) { + this->_own_handle = stream; + } +} + +AudioOutputStreamWrapper::~AudioOutputStreamWrapper() { + this->drop_stream(); +} + +void AudioOutputStreamWrapper::drop_stream() { + if(this->_own_handle) { + auto handle = this->_own_handle->handle; + if(handle) { + handle->delete_source(this->_own_handle); + } + this->_own_handle->on_underflow = nullptr; + this->_own_handle->on_overflow = nullptr; + } + + this->_handle.reset(); + this->_own_handle = nullptr; +} + +void AudioOutputStreamWrapper::do_wrap(const v8::Local &obj) { + this->Wrap(obj); + + auto handle = this->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + Nan::ForceSet(this->handle(), Nan::New("sample_rate").ToLocalChecked(), Nan::New(handle->sample_rate), v8::ReadOnly); + Nan::ForceSet(this->handle(), Nan::New("channels").ToLocalChecked(), Nan::New(handle->channel_count), v8::ReadOnly); + + if(this->_own_handle) { + this->call_underflow = Nan::async_callback([&]{ + + Nan::HandleScope scope; + auto handle = this->handle(); + auto callback = Nan::Get(handle, Nan::New("callback_underflow").ToLocalChecked()).ToLocalChecked(); + if(callback->IsFunction()) + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); + }); + this->call_overflow = Nan::async_callback([&]{ + Nan::HandleScope scope; + auto handle = this->handle(); + auto callback = Nan::Get(handle, Nan::New("callback_overflow").ToLocalChecked()).ToLocalChecked(); + if(callback->IsFunction()) + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); + }); + + this->_own_handle->on_overflow = [&](size_t){ this->call_overflow(); }; + this->_own_handle->on_underflow = [&]{ this->call_underflow(); return false; }; + } +} + + +NAN_METHOD(AudioOutputStreamWrapper::_clear) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_own_handle; + if(!handle) { + Nan::ThrowError("invalid handle"); + return; + } + + handle->clear(); +} + +NAN_METHOD(AudioOutputStreamWrapper::_deleted) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + info.GetReturnValue().Set(!client->_own_handle || !client->_own_handle->handle); +} + +NAN_METHOD(AudioOutputStreamWrapper::_delete) { + auto client = ObjectWrap::Unwrap(info.Holder()); + client->drop_stream(); +} + +ssize_t AudioOutputStreamWrapper::write_data(const std::shared_ptr& handle, void *source, size_t samples, bool interleaved) { + ssize_t result = 0; + if(interleaved) { + result = handle->enqueue_samples(source, samples); + } else { + auto buffer = SampleBuffer::allocate(handle->channel_count, samples); + auto src_buffer = (float*) source; + auto target_buffer = (float*) buffer->sample_data; + + while (samples-- > 0) { + *target_buffer = *src_buffer; + *(target_buffer + 1) = *(src_buffer + buffer->sample_size); + + target_buffer += 2; + src_buffer++; + } + + result = handle->enqueue_samples(buffer); + } + return result; +} + +NAN_METHOD(AudioOutputStreamWrapper::_write_data) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_own_handle; + if(!handle) { + Nan::ThrowError("invalid handle"); + return; + } + + if(info.Length() != 2 || !info[0]->IsArrayBuffer() || !info[1]->IsBoolean()) { + Nan::ThrowError("Invalid arguments"); + return; + } + + auto interleaved = info[1]->BooleanValue(info.GetIsolate()); + auto js_buffer = info[0].As()->GetContents(); + + if(js_buffer.ByteLength() % (handle->channel_count * 4) != 0) { + Nan::ThrowError("input buffer invalid size"); + return; + } + + auto samples = js_buffer.ByteLength() / handle->channel_count / 4; + info.GetReturnValue().Set((int32_t) write_data(handle, js_buffer.Data(), samples, interleaved)); +} + +NAN_METHOD(AudioOutputStreamWrapper::_write_data_rated) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_own_handle; + if(!handle) { + Nan::ThrowError("invalid handle"); + return; + } + + if(info.Length() != 3 || !info[0]->IsArrayBuffer() || !info[1]->IsBoolean() || !info[2]->IsNumber()) { + Nan::ThrowError("Invalid arguments"); + return; + } + + auto sample_rate = info[2]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0); + auto interleaved = info[1]->BooleanValue(info.GetIsolate()); + auto js_buffer = info[0].As()->GetContents(); + + auto samples = js_buffer.ByteLength() / handle->channel_count / 4; + if(sample_rate == handle->sample_rate) { + info.GetReturnValue().Set((int32_t) write_data(handle, js_buffer.Data(), samples, interleaved)); + } else { + if(!client->_resampler || client->_resampler->input_rate() != sample_rate) + client->_resampler = make_unique(sample_rate, handle->sample_rate, handle->channel_count); + + if(!client->_resampler || !client->_resampler->valid()) { + Nan::ThrowError("Resampling failed (invalid resampler)"); + return; + } + + ssize_t target_samples = client->_resampler->estimated_output_size(samples); + auto buffer = SampleBuffer::allocate(handle->channel_count, max((size_t) samples, (size_t) target_samples)); + auto source_buffer = js_buffer.Data(); + if(!interleaved) { + auto src_buffer = (float*) js_buffer.Data(); + auto target_buffer = (float*) buffer->sample_data; + + auto samples_count = samples; + while (samples_count-- > 0) { + *target_buffer = *src_buffer; + *(target_buffer + 1) = *(src_buffer + samples); + + target_buffer += 2; + src_buffer++; + } + source_buffer = buffer->sample_data; + } + + target_samples = client->_resampler->process(buffer->sample_data, source_buffer, samples); + if(target_samples < 0) { + Nan::ThrowError("Resampling failed"); + return; + } + + buffer->sample_index = 0; + buffer->sample_size = target_samples; + info.GetReturnValue().Set((int32_t) handle->enqueue_samples(buffer)); + } +} + +NAN_METHOD(AudioOutputStreamWrapper::_get_buffer_latency) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + info.GetReturnValue().Set((float) handle->min_buffer / (float) handle->sample_rate); +} + +NAN_METHOD(AudioOutputStreamWrapper::_set_buffer_latency) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("Invalid arguments"); + return; + } + + handle->min_buffer = (size_t) ceil(handle->sample_rate * info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); +} + +NAN_METHOD(AudioOutputStreamWrapper::_get_buffer_max_latency) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + info.GetReturnValue().Set((float) handle->max_latency / (float) handle->sample_rate); +} + +NAN_METHOD(AudioOutputStreamWrapper::_set_buffer_max_latency) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("Invalid arguments"); + return; + } + + handle->max_latency = (size_t) ceil(handle->sample_rate * info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioOutputStream.h b/native/serverconnection/src/audio/js/AudioOutputStream.h new file mode 100644 index 0000000..a0686ad --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioOutputStream.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +namespace tc { + namespace audio { + class AudioResampler; + class AudioOutputSource; + + class AudioOutputStreamWrapper : public Nan::ObjectWrap { + public: + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + AudioOutputStreamWrapper(const std::shared_ptr& /* stream */, bool /* own */); + virtual ~AudioOutputStreamWrapper(); + + void do_wrap(const v8::Local&); + void drop_stream(); + private: + static ssize_t write_data(const std::shared_ptr&, void* source, size_t samples, bool interleaved); + + /* general methods */ + static NAN_METHOD(_get_buffer_latency); + static NAN_METHOD(_set_buffer_latency); + static NAN_METHOD(_get_buffer_max_latency); + static NAN_METHOD(_set_buffer_max_latency); + + /* methods for owned streams only */ + static NAN_METHOD(_write_data); + static NAN_METHOD(_write_data_rated); + + static NAN_METHOD(_clear); + static NAN_METHOD(_deleted); + static NAN_METHOD(_delete); + + std::unique_ptr _resampler; + std::shared_ptr _own_handle; + std::weak_ptr _handle; + + Nan::callback_t<> call_underflow; + Nan::callback_t<> call_overflow; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioPlayer.cpp b/native/serverconnection/src/audio/js/AudioPlayer.cpp new file mode 100644 index 0000000..3e4d3c1 --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioPlayer.cpp @@ -0,0 +1,113 @@ +#include +#include +#include "AudioPlayer.h" +#include "../AudioOutput.h" +#include "../AudioDevice.h" +#include "AudioOutputStream.h" + +using namespace tc; +using namespace tc::audio; + +extern tc::audio::AudioOutput* global_audio_output; + +NAN_MODULE_INIT(player::init_js) { + Nan::Set(target, Nan::New("current_device").ToLocalChecked(), Nan::GetFunction(Nan::New(player::current_playback_device)).ToLocalChecked()); + Nan::Set(target, Nan::New("set_device").ToLocalChecked(), Nan::GetFunction(Nan::New(player::set_playback_device)).ToLocalChecked()); + + Nan::Set(target, Nan::New("create_stream").ToLocalChecked(), Nan::GetFunction(Nan::New(player::create_stream)).ToLocalChecked()); + + Nan::Set(target, Nan::New("get_master_volume").ToLocalChecked(), Nan::GetFunction(Nan::New(player::get_master_volume)).ToLocalChecked()); + Nan::Set(target, Nan::New("set_master_volume").ToLocalChecked(), Nan::GetFunction(Nan::New(player::set_master_volume)).ToLocalChecked()); +} + +NAN_METHOD(audio::available_devices) { + auto devices = audio::devices(); + auto result = Nan::New(devices.size()); + + for(size_t index = 0; index < devices.size(); index++) { + auto device_info = Nan::New(); + auto device = devices[index]; + + Nan::Set(device_info, Nan::New("name").ToLocalChecked(), Nan::New(device->name).ToLocalChecked()); + Nan::Set(device_info, Nan::New("driver").ToLocalChecked(), Nan::New(device->driver).ToLocalChecked()); + Nan::Set(device_info, Nan::New("device_id").ToLocalChecked(), Nan::New(base64::encode(digest::sha1(device->name + device->driver))).ToLocalChecked()); + + Nan::Set(device_info, Nan::New("input_supported").ToLocalChecked(), Nan::New(device->input_supported)); + Nan::Set(device_info, Nan::New("output_supported").ToLocalChecked(), Nan::New(device->output_supported)); + + Nan::Set(device_info, Nan::New("input_default").ToLocalChecked(), Nan::New(device->is_default_input)); + Nan::Set(device_info, Nan::New("output_default").ToLocalChecked(), Nan::New(device->is_default_output)); + + Nan::Set(device_info, Nan::New("device_index").ToLocalChecked(), Nan::New(device->device_id)); + + result->Set(index, device_info); + } + + info.GetReturnValue().Set(result); +} + +NAN_METHOD(player::current_playback_device) { + if(!global_audio_output) { + info.GetReturnValue().Set(paNoDevice); + return; + } + + info.GetReturnValue().Set(global_audio_output->current_device()); +} + +NAN_METHOD(player::set_playback_device) { + if(!global_audio_output) { + Nan::ThrowError("Global audio output hasn't been yet initialized!"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid arguments"); + return; + } + + std::string error; + if(!global_audio_output->open_device(error, info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0))) { + Nan::ThrowError(Nan::New("failed to open device (" + error + ")").ToLocalChecked()); + return; + } + + if(!global_audio_output->playback()) { + Nan::ThrowError("failed to open playback stream"); + return; + } +} + +NAN_METHOD(player::create_stream) { + if(!global_audio_output) { + Nan::ThrowError("Global audio output hasn't been yet initialized!"); + return; + } + + auto wrapper = new audio::AudioOutputStreamWrapper(global_audio_output->create_source(), true); + auto object = Nan::NewInstance(Nan::New(audio::AudioOutputStreamWrapper::constructor()), 0, nullptr).ToLocalChecked(); + wrapper->do_wrap(object); + info.GetReturnValue().Set(object); +} + + +NAN_METHOD(player::get_master_volume) { + if(!global_audio_output) { + Nan::ThrowError("Global audio output hasn't been yet initialized!"); + return; + } + info.GetReturnValue().Set(global_audio_output->volume()); +} + +NAN_METHOD(player::set_master_volume) { + if(!global_audio_output) { + Nan::ThrowError("Global audio output hasn't been yet initialized!"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid arguments"); + return; + } + global_audio_output->set_volume(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioPlayer.h b/native/serverconnection/src/audio/js/AudioPlayer.h new file mode 100644 index 0000000..4194d74 --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioPlayer.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +namespace tc { + namespace audio { + extern NAN_METHOD(available_devices); + + namespace player { + extern NAN_MODULE_INIT(init_js); + + extern NAN_METHOD(current_playback_device); + extern NAN_METHOD(set_playback_device); + + extern NAN_METHOD(create_stream); + + extern NAN_METHOD(get_master_volume); + extern NAN_METHOD(set_master_volume); + /* + export function get_master_volume() : number; + export function set_master_volume(volume: number); + + export function set_device(device: AudioDevice) : Promise; + export function current_device() : AudioDevice; + + export function available_devices() : AudioDevice[]; + + export function create_stream() : OwnedAudioOutputStream; + export function delete_stream(stream: OwnedAudioOutputStream) : number; + */ + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioRecorder.cpp b/native/serverconnection/src/audio/js/AudioRecorder.cpp new file mode 100644 index 0000000..69c036b --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioRecorder.cpp @@ -0,0 +1,266 @@ +#include + +#include "AudioRecorder.h" +#include "AudioConsumer.h" +#include "../AudioInput.h" +#include "../../logger.h" + +using namespace std; +using namespace tc::audio; +using namespace tc::audio::recorder; + +NAN_MODULE_INIT(recorder::init_js) { + Nan::Set(target, Nan::New("create_recorder").ToLocalChecked(), Nan::GetFunction(Nan::New(recorder::create_recorder)).ToLocalChecked()); +} + +NAN_METHOD(recorder::create_recorder) { + auto input = make_shared(2, 48000); + auto wrapper = new AudioRecorderWrapper(input); + auto js_object = Nan::NewInstance(Nan::New(AudioRecorderWrapper::constructor())).ToLocalChecked(); + wrapper->do_wrap(js_object); + info.GetReturnValue().Set(js_object); +} + + +NAN_MODULE_INIT(AudioRecorderWrapper::Init) { + auto klass = Nan::New(AudioRecorderWrapper::NewInstance); + klass->SetClassName(Nan::New("AudioRecorder").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "get_device", AudioRecorderWrapper::_get_device); + Nan::SetPrototypeMethod(klass, "set_device", AudioRecorderWrapper::_set_device); + + Nan::SetPrototypeMethod(klass, "start", AudioRecorderWrapper::_start); + Nan::SetPrototypeMethod(klass, "started", AudioRecorderWrapper::_started); + Nan::SetPrototypeMethod(klass, "stop", AudioRecorderWrapper::_stop); + + Nan::SetPrototypeMethod(klass, "get_volume", AudioRecorderWrapper::_get_volume); + Nan::SetPrototypeMethod(klass, "set_volume", AudioRecorderWrapper::_set_volume); + + Nan::SetPrototypeMethod(klass, "get_consumers", AudioRecorderWrapper::_get_consumers); + Nan::SetPrototypeMethod(klass, "create_consumer", AudioRecorderWrapper::_create_consumer); + Nan::SetPrototypeMethod(klass, "delete_consumer", AudioRecorderWrapper::_delete_consumer); + + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(AudioRecorderWrapper::NewInstance) { + if(!info.IsConstructCall()) + Nan::ThrowError("invalid invoke!"); +} + + +AudioRecorderWrapper::AudioRecorderWrapper(std::shared_ptr handle) : _input(std::move(handle)) { + log_allocate("AudioRecorderWrapper", this); +} +AudioRecorderWrapper::~AudioRecorderWrapper() { + if(this->_input) { + this->_input->stop(); + this->_input->close_device(); + this->_input = nullptr; + } + { + lock_guard lock(this->_consumer_lock); + this->_consumers.clear(); + } + log_free("AudioRecorderWrapper", this); +} + +std::shared_ptr AudioRecorderWrapper::create_consumer() { + auto result = shared_ptr(new AudioConsumerWrapper(this, this->_input->create_consumer(960)), [](AudioConsumerWrapper* ptr) { + assert(v8::Isolate::GetCurrent()); + ptr->Unref(); + }); + + /* wrap into object */ + { + auto js_object = Nan::NewInstance(Nan::New(AudioConsumerWrapper::constructor()), 0, nullptr).ToLocalChecked(); + result->do_wrap(js_object); + result->Ref(); + } + + { + lock_guard lock(this->_consumer_lock); + this->_consumers.push_back(result); + } + + return result; +} + +void AudioRecorderWrapper::delete_consumer(const AudioConsumerWrapper* consumer) { + shared_ptr handle; /* need to keep the handle 'till everything has been finished */ + { + lock_guard lock(this->_consumer_lock); + for(auto& c : this->_consumers) { + if(&*c == consumer) { + handle = c; + break; + } + } + if(!handle) + return; + + { + auto it = find(this->_consumers.begin(), this->_consumers.end(), handle); + if(it != this->_consumers.end()) + this->_consumers.erase(it); + } + } + + { + lock_guard lock(handle->execute_lock); /* if we delete the consumer while executing strange stuff could happen */ + handle->unbind(); + this->_input->delete_consumer(handle->_handle); + } +} + +void AudioRecorderWrapper::do_wrap(const v8::Local &obj) { + this->Wrap(obj); +} + +NAN_METHOD(AudioRecorderWrapper::_get_device) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto input = handle->_input; + + info.GetReturnValue().Set(input->current_device()); +} + +NAN_METHOD(AudioRecorderWrapper::_set_device) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto input = handle->_input; + + if(info.Length() != 2 || !info[0]->IsNumber() || !info[1]->IsFunction()) { + Nan::ThrowError("invalid arguments"); + return; + } + + auto device_id = info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + + unique_ptr> _callback = make_unique>(info[1].As()); + unique_ptr> _recorder = make_unique>(info.Holder()); + + auto _async_callback = Nan::async_callback([call = std::move(_callback), recorder = move(_recorder)](bool result, std::string error) mutable { + Nan::HandleScope scope; + auto callback_function = call->Get(Nan::GetCurrentContext()->GetIsolate()); + + v8::Local argv[1]; + if(result) + argv[0] = v8::Boolean::New(Nan::GetCurrentContext()->GetIsolate(), result); + else + argv[0] = Nan::NewOneByteString((uint8_t*) error.data(), error.length()).ToLocalChecked(); + callback_function->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, argv); + + recorder->Reset(); + call->Reset(); + }).option_destroyed_execute(true); + + std::thread([_async_callback, input, device_id]{ + string error; + auto flag = input->open_device(error, device_id); + _async_callback(std::forward(flag), std::forward(error)); + }).detach(); +} + +NAN_METHOD(AudioRecorderWrapper::_start) { + if(info.Length() != 1) { + Nan::ThrowError("missing callback"); + return; + } + + if(!info[0]->IsFunction()) { + Nan::ThrowError("not a function"); + return; + } + + unique_ptr> _callback = make_unique>(info[0].As()); + unique_ptr> _recorder = make_unique>(info.Holder()); + + auto _async_callback = Nan::async_callback([call = std::move(_callback), recorder = move(_recorder)](bool result) mutable { + Nan::HandleScope scope; + auto callback_function = call->Get(Nan::GetCurrentContext()->GetIsolate()); + + v8::Local argv[1]; + argv[0] = v8::Boolean::New(Nan::GetCurrentContext()->GetIsolate(), result); + callback_function->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, argv); + + recorder->Reset(); + call->Reset(); + }).option_destroyed_execute(true); + + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto input = handle->_input; + std::thread([_async_callback, input]{ + _async_callback(input->record()); + }).detach(); +} + +NAN_METHOD(AudioRecorderWrapper::_started) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto input = handle->_input; + + info.GetReturnValue().Set(input->recording()); +} + +NAN_METHOD(AudioRecorderWrapper::_stop) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto input = handle->_input; + + input->stop(); +} + +NAN_METHOD(AudioRecorderWrapper::_create_consumer) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto consumer = handle->create_consumer(); + + if(!consumer) { + Nan::ThrowError("failed to create consumer"); + return; + } + + info.GetReturnValue().Set(consumer->handle()); +} + +NAN_METHOD(AudioRecorderWrapper::_get_consumers) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + auto consumers = handle->consumers(); + + auto result = Nan::New(consumers.size()); + + for(size_t index = 0; index < consumers.size(); index++) + result->Set(index, consumers[index]->handle()); + + info.GetReturnValue().Set(result); +} + +NAN_METHOD(AudioRecorderWrapper::_delete_consumer) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + + if(info.Length() != 1 || !info[0]->IsObject()) { + Nan::ThrowError("invalid argument"); + return; + } + + if(!Nan::New(AudioConsumerWrapper::constructor_template())->HasInstance(info[0])) { + Nan::ThrowError("invalid consumer"); + return; + } + + auto consumer = ObjectWrap::Unwrap(info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked()); + handle->delete_consumer(consumer); +} + +NAN_METHOD(AudioRecorderWrapper::_set_volume) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("invalid argument"); + return; + } + + handle->_input->set_volume(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); +} + +NAN_METHOD(AudioRecorderWrapper::_get_volume) { + auto handle = ObjectWrap::Unwrap(info.Holder()); + info.GetReturnValue().Set(handle->_input->volume()); +} \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioRecorder.h b/native/serverconnection/src/audio/js/AudioRecorder.h new file mode 100644 index 0000000..4d3f12d --- /dev/null +++ b/native/serverconnection/src/audio/js/AudioRecorder.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include + +namespace tc { + namespace audio { + class AudioInput; + + namespace recorder { + class AudioConsumerWrapper; + + extern NAN_MODULE_INIT(init_js); + + extern NAN_METHOD(create_recorder); + + class AudioRecorderWrapper : public Nan::ObjectWrap { + public: + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + explicit AudioRecorderWrapper(std::shared_ptr /* input */); + ~AudioRecorderWrapper() override; + + static NAN_METHOD(_get_device); + static NAN_METHOD(_set_device); + + static NAN_METHOD(_start); + static NAN_METHOD(_started); + static NAN_METHOD(_stop); + + static NAN_METHOD(_create_consumer); + static NAN_METHOD(_get_consumers); + static NAN_METHOD(_delete_consumer); + + static NAN_METHOD(_set_volume); + static NAN_METHOD(_get_volume); + + std::shared_ptr create_consumer(); + void delete_consumer(const AudioConsumerWrapper*); + + inline std::deque> consumers() { + std::lock_guard lock(this->_consumer_lock); + return this->_consumers; + } + + void do_wrap(const v8::Local& /* obj */); + + inline void js_ref() { this->Ref(); } + inline void js_unref() { this->Unref(); } + private: + std::shared_ptr _input; + + std::mutex _consumer_lock; + std::deque> _consumers; + }; + } + } +} \ No newline at end of file diff --git a/native/serverconnection/src/bindings.cpp b/native/serverconnection/src/bindings.cpp new file mode 100644 index 0000000..38659cc --- /dev/null +++ b/native/serverconnection/src/bindings.cpp @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "logger.h" +#include "NanException.h" +#include "NanEventCallback.h" +#include "connection/ServerConnection.h" +#include "connection/audio/VoiceConnection.h" +#include "connection/audio/VoiceClient.h" +#include "connection/ft/FileTransferManager.h" +#include "connection/ft/FileTransferObject.h" +#include "audio/AudioOutput.h" +#include "audio/AudioDevice.h" +#include "audio/js/AudioOutputStream.h" +#include "audio/js/AudioPlayer.h" +#include "audio/js/AudioRecorder.h" +#include "audio/js/AudioConsumer.h" +#include "audio/js/AudioFilter.h" +#include "connection/audio/AudioEventLoop.h" + +#ifndef WIN32 + #include +#endif + +extern "C" { + #include + #include + + #include +}; + +using namespace std; +using namespace tc; +using namespace tc::connection; +using namespace tc::ft; + +void testTomMath(){ + mp_int x{}; + mp_init(&x); + mp_read_radix(&x, "2280880776330203449294339386427307168808659578661428574166839717243346815923951250209099128371839254311904649344289668000305972691071196233379180504231889", 10); + + mp_int n{}; + mp_init(&n); + mp_read_radix(&n, "436860662135489324843442078840868871476482593772359054106809367217662215065650065606351911592188139644751920724885335056877706082800496073391354240530016", 10); + + mp_int exp{}; + mp_init(&exp); + mp_2expt(&exp, 1000); + + + mp_int r{}; + mp_init(&r); + + if(mp_exptmod(&x, &exp, &n, &r) == CRYPT_OK) { + log_warn(category::general, tr("TomCrypt check failed. Server connects main fail due to this mistake!")); + //Nan::ThrowError("Tomcrypt library is too modern. Use an oder one!"); + //return; + } + //assert(mp_exptmod(&x, &exp, &n, &r) != CRYPT_OK); //if this method succeed than tommath failed. Unknown why but it is so + + mp_clear_multi(&x, &n, &exp, &r, nullptr); +} + +tc::audio::AudioOutput* global_audio_output; +#define ENUM_SET(object, key, value) \ + Nan::DefineOwnProperty(object, Nan::New(key).ToLocalChecked(), Nan::New(value), v8::DontDelete); \ + Nan::Set(object, value, Nan::New(key).ToLocalChecked()); + +NAN_MODULE_INIT(init) { + logger::initialize_node(); +#ifndef WIN32 + logger::info(category::general, tr("Hello World from C. PPID: {}, PID: {}"), getppid(), getpid()); +#else + logger::info(category::general, tr("Hello World from C. PID: {}"), _getpid()); +#endif + + /* + { + auto data = (uint8_t*) "Hello World"; + auto hash_result = digest::sha1((const char*) data, 11); + if(hash_result.length() != 20) + Nan::ThrowError("digest::sha1 test failed"); + log_error(category::connection, tr("Hash result: {}"), hash_result.length()); + } + */ + { + auto data = (uint8_t*) "Hello World"; + auto hash_result = digest::sha1(std::string("Hello World")); + if(hash_result.length() != 20) + Nan::ThrowError("digest::sha1 test failed"); + } + { + auto data = (uint8_t*) "Hello World"; + + uint8_t result[SHA_DIGEST_LENGTH]; + digest::tomcrypt::sha1((char*) data, 11, result); + auto hash_result = std::string((const char*) result, SHA_DIGEST_LENGTH); + log_error(category::connection, tr("Hash result: {}"), hash_result.length()); + } + + string error; + //TODO here + //PaJack_SetClientName("TeaClient"); + Pa_Initialize(); + + std::thread(audio::devices).detach(); /* cache the devices */ + + logger::info(category::general, "Loading crypt modules"); + std::string descriptors = "LTGE"; + { + int crypt_init = false; + for(const auto& c : descriptors) + if((crypt_init = crypt_mp_init(&c) == CRYPT_OK)) + break; + if(!crypt_init) { + Nan::ThrowError("failed to init tomcrypt"); + return; + } + if(register_prng(&sprng_desc) == -1) { + Nan::ThrowError("could not setup prng"); + return; + } + if (register_cipher(&rijndael_desc) == -1) { + Nan::ThrowError("could not setup rijndael"); + return; + } + + testTomMath(); + } + logger::info(category::general, "Crypt modules loaded"); + +#ifdef WIN32 + evthread_use_windows_threads(); +#else + evthread_use_pthreads(); +#endif + + tc::audio::init_event_loops(); + /* TODO: Test error codes and make the audi playback device configurable */ + global_audio_output = new tc::audio::AudioOutput(2, 48000); //48000 44100 + if(!global_audio_output->open_device(error, Pa_GetDefaultOutputDevice())) { + logger::error(category::audio, "Failed to initialize default audio playback: {}", error); + } else { + if(!global_audio_output->playback()) { + logger::error(category::audio, "Failed to start audio playback"); + } + } + + { + auto namespace_audio = Nan::New(); + Nan::Set(namespace_audio, Nan::New("available_devices").ToLocalChecked(), Nan::GetFunction(Nan::New(audio::available_devices)).ToLocalChecked()); + { + auto namespace_playback = Nan::New(); + audio::player::init_js(namespace_playback); + audio::AudioOutputStreamWrapper::Init(namespace_playback); + Nan::Set(namespace_audio, Nan::New("playback").ToLocalChecked(), namespace_playback); + } + { + auto namespace_record = Nan::New(); + audio::recorder::init_js(namespace_record); + audio::recorder::AudioRecorderWrapper::Init(namespace_record); + audio::recorder::AudioConsumerWrapper::Init(namespace_record); + audio::recorder::AudioFilterWrapper::Init(namespace_record); + Nan::Set(namespace_audio, Nan::New("record").ToLocalChecked(), namespace_record); + } + Nan::Set(target, Nan::New("audio").ToLocalChecked(), namespace_audio); + } + + VoiceClientWrap::Init(target); + VoiceConnectionWrap::Init(target); + { + auto enum_object = Nan::New(); + ENUM_SET(enum_object, "BUFFERING", tc::connection::VoiceClient::state::buffering); + ENUM_SET(enum_object, "PLAYING", tc::connection::VoiceClient::state::playing); + ENUM_SET(enum_object, "STOPPING", tc::connection::VoiceClient::state::stopping); + ENUM_SET(enum_object, "STOPPED", tc::connection::VoiceClient::state::stopped); + Nan::DefineOwnProperty(target, Nan::New("PlayerState").ToLocalChecked(), enum_object, v8::DontDelete); + } + + transfer_manager = new tc::ft::FileTransferManager(); + transfer_manager->initialize(); + + ServerConnection::Init(target); + Nan::Set(target, Nan::New("spawn_server_connection").ToLocalChecked(), Nan::GetFunction(Nan::New(ServerConnection::new_instance)).ToLocalChecked()); + + /* ft namespace */ + { + auto ft_namespace = Nan::New(); + + TransferObjectWrap::Init(ft_namespace); + Nan::Set(ft_namespace, + Nan::New("upload_transfer_object_from_buffer").ToLocalChecked(), + Nan::GetFunction(Nan::New(TransferJSBufferSource::create_from_buffer)).ToLocalChecked() + ); + Nan::Set(ft_namespace, + Nan::New("download_transfer_object_from_buffer").ToLocalChecked(), + Nan::GetFunction(Nan::New(TransferJSBufferTarget::create_from_buffer)).ToLocalChecked() + ); + Nan::Set(ft_namespace, + Nan::New("upload_transfer_object_from_file").ToLocalChecked(), + Nan::GetFunction(Nan::New(TransferFileSource::create)).ToLocalChecked() + ); + + //spawn_file_connection destroy_file_connection + JSTransfer::Init(ft_namespace); + Nan::Set(ft_namespace, Nan::New("spawn_connection").ToLocalChecked(), Nan::GetFunction(Nan::New(JSTransfer::NewInstance)).ToLocalChecked()); + Nan::Set(ft_namespace, Nan::New("destroy_connection").ToLocalChecked(), Nan::GetFunction(Nan::New(JSTransfer::destory_transfer)).ToLocalChecked()); + + Nan::Set(target, Nan::New("ft").ToLocalChecked(), ft_namespace); + } + + /* setup server types */ + { + auto enum_object = Nan::New(); + ENUM_SET(enum_object, "UNKNOWN", tc::connection::server_type::UNKNOWN); + ENUM_SET(enum_object, "TEASPEAK", tc::connection::server_type::TEASPEAK); + ENUM_SET(enum_object, "TEAMSPEAK", tc::connection::server_type::TEAMSPEAK); + Nan::DefineOwnProperty(target, Nan::New("ServerType").ToLocalChecked(), enum_object, v8::DontDelete); + } +} + +NODE_MODULE(MODULE_NAME, init) \ No newline at end of file diff --git a/native/serverconnection/src/connection/ProtocolHandler.cpp b/native/serverconnection/src/connection/ProtocolHandler.cpp new file mode 100644 index 0000000..b19f95d --- /dev/null +++ b/native/serverconnection/src/connection/ProtocolHandler.cpp @@ -0,0 +1,535 @@ +#ifdef WIN32 + #include +#endif + +#include "ProtocolHandler.h" +#include "ServerConnection.h" +#include "Socket.h" +#include "../logger.h" +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; +using namespace tc::connection; +using namespace ts::protocol; +using namespace ts; + +ProtocolHandler::ProtocolHandler(ServerConnection* handle) : handle(handle) { + this->compression_handler.max_packet_size = 128 * 1024; /* max 128Kb */ +} + +ProtocolHandler::~ProtocolHandler() { +} + + +void ProtocolHandler::reset() { + this->server_type = server_type::UNKNOWN; + this->disconnect_id++; /* we've been resetted any pending disconnects are not from interest anymore */ + this->client_id = 0; + this->acknowledge_handler.reset(); + this->connection_state = connection_state::INITIALIZING; + + { /* initialize pow handler */ + this->pow.state = pow_state::COOKIE_SET; + this->pow.last_buffer = pipes::buffer{}; + this->pow.last_resend = system_clock::time_point{}; + this->pow.last_response = system_clock::time_point{}; + + this->pow.client_control_data[0] = 0; /* clear set flag, so the client generates a new pack */ + } + + { + this->crypto.alpha[0] = 0; + this->crypto.initiv_command = ""; + this->crypto.beta_length = 0; + + if(this->crypto.identity.k) + ecc_free(&this->crypto.identity); + memset(&this->crypto.identity, 0, sizeof(this->crypto.identity)); + } + + for(auto& buffer : this->_packet_buffers) { + lock_guard lock(buffer.buffer_lock); + buffer.reset(); + } + + this->_packet_id_manager.reset(); + this->crypt_handler.reset(); + + this->ping.ping_received_timestamp = system_clock::time_point{}; +} + +void ProtocolHandler::connect() { + this->connection_state = connection_state::INIT_LOW; + this->connect_timestamp = system_clock::now(); + this->pow_send_cookie_get(); + + { + auto command = this->generate_client_initiv(); + auto packet = make_shared(PacketTypeInfo::Command, pipes::buffer_view{command.data(), command.size()}); + packet->enable_flag(PacketFlag::NewProtocol); + this->send_packet(packet); + } +} + +void ProtocolHandler::execute_tick() { + auto now = system_clock::now(); + if(this->connection_state < connection_state::DISCONNECTED) { + if(!this->pow.last_buffer.empty() && this->pow.last_resend < now - seconds(1)) { + this->pow.last_resend = now; + this->send_packet(make_shared(PacketTypeInfo::Init1, PacketFlag::Unencrypted, this->pow.last_buffer)); + } + + if(this->connection_state == connection_state::INIT_LOW || this->connection_state == connection_state::INIT_HIGH) { + if(this->connect_timestamp < now - seconds(15)) { + this->handle->call_connect_result.call(this->handle->errors.register_error("timeout (" + to_string(this->connection_state) + ")"), true); + this->handle->close_connection(); + return; + } + } + + if(this->connection_state == connection_state::DISCONNECTING) { + if(this->disconnect_timestamp < now - seconds(5)) { /* disconnect timeout */ + this->handle->close_connection(); + return; + } + } + + this->execute_resend(); + + /* ping */ + if(this->connection_state == connection_state::CONNECTED) { + if(this->ping.ping_send_timestamp + seconds(1) < now) + this->ping_send_request(); + + if(this->ping.ping_received_timestamp.time_since_epoch().count() > 0) { + if(now - this->ping.ping_received_timestamp > seconds(30)) { + this->handle->execute_callback_disconnect.call(tr("ping timeout"), true); + this->handle->close_connection(); + return; + } + } else + this->ping.ping_received_timestamp = now; + } + } +} + +void ProtocolHandler::execute_resend() { + if(this->connection_state >= connection_state::DISCONNECTED) + return; + + deque buffers; + auto now = system_clock::now(); + system_clock::time_point next = now + seconds(5); /* in real we're doing it all 500ms */ + string error; + + auto resended = this->acknowledge_handler.execute_resend(now, next, buffers, error); + if(resended < 0) { + log_error(category::connection, tr("Failed to receive acknowledge: {}"), error); + + this->handle->execute_callback_disconnect(tr("packet resend failed")); + this->handle->close_connection(); + return; + } + + auto socket = this->handle->get_socket(); + if(socket) { + for(const auto& buffer : buffers) + socket->send_message(buffer); + } + + this->handle->schedule_resend(next); +} + +void ProtocolHandler::progress_packet(const pipes::buffer_view &buffer) { + if(this->connection_state >= connection_state::DISCONNECTED) + return; + + if(buffer.length() < ServerPacket::META_SIZE) { + log_error(category::connection, tr("Received a packet which is too small. ({})"), buffer.length()); + return; + } + + auto packet = std::shared_ptr(ts::protocol::ServerPacket::from_buffer(buffer).release()); + auto packet_type = packet->type(); + auto packet_id = packet->packetId(); + auto ordered = packet_type.type() == protocol::COMMAND || packet_type.type() == protocol::COMMAND_LOW; + + /* special handling */ + if(packet_type.type() == protocol::INIT1) { + this->handlePacketInit(packet); + return; + } + + if(packet_type.type() < 0 || packet_type.type() >= this->_packet_buffers.size()) { + log_error(category::connection, tr("Received packet with invalid type. ({})"), packet_type.type()); + return; + } + + auto& read_queue = this->_packet_buffers[packet_type.type()]; + packet->generationId(read_queue.generation(packet_id)); + + if(ordered) { + unique_lock queue_lock(read_queue.buffer_lock); + auto result = read_queue.accept_index(packet_id); + if(result != 0) { /* packet index is ahead buffer index */ + log_error(category::connection, tr("Failed to verify command packet: {} (Index: {} Current index: {})"), result, packet_id, read_queue.current_index()); + + if(result == -1) { /* underflow */ + /* we've already got the packet, but the client dosn't know that so we've to send the acknowledge again */ + if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow) + this->send_acknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow); + } + return; + } + } + + packet->setEncrypted(!packet->has_flag(PacketFlag::Unencrypted)); + if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){ + packet->setCompressed(packet->has_flag(PacketFlag::Compressed)); + } + //NOTICE I found out that the Compressed flag is set if the packet contains an audio header + + string error = "success"; + if(!this->crypt_handler.progressPacketIn(packet.get(), error, false)){ + if(!this->crypt_handler.use_default()) { + if(!this->crypt_handler.progressPacketIn(packet.get(), error, true)){ + log_error(category::connection, tr("Failed to decrypt packet ({}), even with default key: {}"), packet_type.name(), error); + return; + } else { + log_error(category::connection, tr("Successfully decrypt packet ({} | {}) with default key."), packet_type.name(), packet_id); + //FIXME Test if we're in init high + } + } else { + log_error(category::connection, tr("Failed to decrypt packet ({}) with default key: {}"), packet_type.name(), error); + return; + } + } + + if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){ + if(packet->has_flag(PacketFlag::Unencrypted)) + return; + } + + if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow) + this->send_acknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow); + + { + unique_lock queue_lock(read_queue.buffer_lock); + + if(ordered) { /* ordered */ + if(!read_queue.insert_index(packet_id, std::forward>(packet))) { + log_warn(category::connection, tr("Failed to insert ordered packet into queue. ({} | {} | {})"), packet_type.name(), read_queue.current_index(), packet_id); + } + } else { + if(!read_queue.push_back(std::forward>(packet))) { + log_warn(category::connection, tr("Failed to insert unordered packet into queue. ({} | {} | {})"), packet_type.name(), read_queue.current_index(), packet_id); + /* return; dont stop here because we've to progress the packets */ + } else { + read_queue.index_set(packet_id); /* may we've skipped one packet id */ + } + } + } + + while(this->handle_packets()); +} + +bool ProtocolHandler::handle_packets() { + if(this->connection_state >= connection_state::DISCONNECTED) + return false; + + bool reexecute_handle = false; + shared_ptr current_packet = nullptr; + + packet_buffer_t* buffer = nullptr; + unique_lock buffer_lock; + unique_lock buffer_execute_lock; + std::string error = "success"; + + + { + auto base_index = this->_packet_buffers_index; + auto select_index = base_index; + auto max_index = this->_packet_buffers.size(); + for(uint8_t index = 0; index < max_index; index++) { + if(!buffer) select_index++; + + auto& buf = this->_packet_buffers[base_index++ % max_index]; + unique_lock ring_lock(buf.buffer_lock, try_to_lock); + if(!ring_lock.owns_lock()) continue; + + if(buf.front_set()) { + if(!buffer) { /* lets still test for reexecute */ + buffer_execute_lock = unique_lock(buf.execute_lock, try_to_lock); + if(!buffer_execute_lock.owns_lock()) continue; + + buffer_lock = move(ring_lock); + buffer = &buf; + } else { + reexecute_handle |= true; + break; + } + } + } + this->_packet_buffers_index = select_index % max_index; /* garante that we will not hangup with commands! */ + } + + if(buffer){ + uint16_t sequence_length = 0; + current_packet = buffer->slot_value(sequence_length++); + + if(current_packet) { + if((current_packet->type() == PacketTypeInfo::Command || current_packet->type() == PacketTypeInfo::CommandLow) && current_packet->has_flag(PacketFlag::Fragmented)) { + do { + if(sequence_length >= buffer->capacity()) { + log_warn(category::connection, tr("Received fragmented packets which have a too long order. Dropping queue, which will cause a client drop.")); + buffer->clear(); + return false; + } + current_packet = buffer->slot_value(sequence_length++); + } while(current_packet && !current_packet->has_flag(PacketFlag::Fragmented)); + } + } else { + log_critical(category::connection, tr("buffer->slot_value(sequence_length++) returned nullptr!")); + //FIXME! + //logCritical(this->client->getServer()->getServerId(), "buffer->slot_value(sequence_length++) returned nullptr!") + }; + + if(current_packet) { //We could reconstruct a new packet! + if(sequence_length > 1) { //We have to merge + vector append; + append.reserve(sequence_length - 1); + + uint16_t packet_count = 0; + current_packet = buffer->pop_front(); + packet_count++; + do { + auto packet = buffer->pop_front(); + packet_count++; + if(!packet) { + log_critical(category::connection, tr("readQueue->peekNext(seqIndex++) => nullptr_t!")); + return false; + } + + append.push_back(packet->data()); + if(packet->has_flag(PacketFlag::Fragmented)) break; + } while(packet_count < sequence_length); + + if(packet_count != sequence_length) { + log_critical(category::connection, tr("seqIndex != index failed! seqIndex: {} seqLength: {} This may cause a application crash!"), packet_count, sequence_length); + sequence_length = packet_count; + current_packet = nullptr; + } else { + current_packet->append_data(append); + } + } else { + if(buffer->pop_front() != current_packet) { + log_critical(category::connection, tr("buffer->pop_front() != current_packet failed.")); + } + } + reexecute_handle |= buffer->front_set(); + buffer_lock.unlock(); //We got our packet so release it + + if(current_packet) { + if(!this->compression_handler.progressPacketIn(current_packet.get(), error)) { + log_error(category::connection, tr("Failed to decompress received packet. Error: {}"), error); + current_packet = nullptr; + } + } + } + } + + if(current_packet){ + auto startTime = chrono::system_clock::now(); + try { + if(current_packet->type() == PacketTypeInfo::Command || current_packet->type() == PacketTypeInfo::CommandLow) + this->handlePacketCommand(current_packet); + else if(current_packet->type() == PacketTypeInfo::Ack || current_packet->type() == PacketTypeInfo::AckLow) + this->handlePacketAck(current_packet); + else if(current_packet->type() == PacketTypeInfo::Voice || current_packet->type() == PacketTypeInfo::VoiceWhisper) + this->handlePacketVoice(current_packet); + else if(current_packet->type() == PacketTypeInfo::Ping || current_packet->type() == PacketTypeInfo::Pong) + this->handlePacketPing(current_packet); + } catch (std::exception& ex) { + log_critical(category::connection, tr("Exception reached root tree! {}"), ex.what()); + } + + auto end = chrono::system_clock::now(); + if(end - startTime > chrono::milliseconds(10)) { + if(current_packet->type() != PacketTypeInfo::Command && current_packet->type() != PacketTypeInfo::CommandLow) { + //FIXME! + /* + logError(this->client->getServerId(), + "{} Handling of packet {} needs more than 10ms ({}ms)", + CLIENT_STR_LOG_PREFIX_(this->client), + current_packet->type().name(), + duration_cast(end - startTime).count() + ); + */ + } + } + } + if(buffer_execute_lock.owns_lock()) + buffer_execute_lock.unlock(); + + return reexecute_handle; +} + +bool ProtocolHandler::create_datagram_packets(std::vector &result, const std::shared_ptr &packet) { + string error = "success"; + + if(packet->type().compressable() && !packet->memory_state.fragment_entry) { + packet->enable_flag(PacketFlag::Compressed); + if(!this->compression_handler.progressPacketOut(packet.get(), error)) { + log_error(category::connection, tr("Could not compress outgoing packet.\nThis could cause fatal failed for the client.\nError: {}"), error); + return false; + } + } + if(packet->data().length() > packet->type().max_length()){ + if(!packet->type().fragmentable()) { + log_error(category::connection, tr("We've tried to send a too long, not fragmentable packet. Dropping packet of type {} with length {}"), packet->type().name(), packet->data().length()); + return false; + } + + std::vector> siblings; + siblings.reserve(8); + + + { //Split packets + auto buffer = packet->data(); + + const auto max_length = packet->type().max_length(); + while(buffer.length() > max_length * 2) { + siblings.push_back(make_shared(packet->type(), buffer.view(0, max_length).dup(ts::buffer::allocate_buffer(max_length)))); + buffer = buffer.range(max_length); + } + + if(buffer.length() > max_length) { //Divide rest by 2 + siblings.push_back(make_shared(packet->type(), buffer.view(0, buffer.length() / 2).dup(ts::buffer::allocate_buffer(buffer.length() / 2)))); + buffer = buffer.range(buffer.length() / 2); + } + siblings.push_back(make_shared(packet->type(), buffer)); + + for(const auto& frag : siblings) { + frag->setFragmentedEntry(true); + frag->enable_flag(PacketFlag::NewProtocol); + } + } + + assert(siblings.size() >= 2); + siblings.front()->enable_flag(PacketFlag::Fragmented); + if(packet->has_flag(PacketFlag::Compressed)) + siblings.front()->enable_flag(PacketFlag::Compressed); + + siblings.back()->enable_flag(PacketFlag::Fragmented); + + if(packet->getListener()) + siblings.back()->setListener(std::move(packet->getListener())); //Move the listener to the last :) + + result.reserve(siblings.size()); + for(const auto& frag : siblings) + create_datagram_packets(result, frag); + return true; + } + + if(!packet->memory_state.id_branded) { + packet->clientId(this->client_id); + if(packet->type().type() == PacketType::INIT1) { + packet->applyPacketId(101, 0); + } else { + packet->applyPacketId(this->_packet_id_manager); + } + //log_trace(category::connection, tr("Packet {} got packet id {}"), packet->type().name(), packet->packetId()); + } + if(!this->crypt_handler.progressPacketOut(packet.get(), error, false)) { + log_error(category::connection, tr("Failed to encrypt packet: {}"), error); + return false; + } + + /* +#ifndef CONNECTION_NO_STATISTICS + if(this->client && this->client->getServer()) + this->client->connectionStatistics->logOutgoingPacket(packet); +#endif + */ + result.push_back(packet->buffer()); + + this->acknowledge_handler.process_packet(*packet); + return true; +} + +void ProtocolHandler::send_command(const ts::Command &cmd, const std::function &ack_callback) { + auto data = cmd.build(); + auto packet = make_shared(PacketTypeInfo::Command, pipes::buffer_view{data.data(), data.size()}); + if(ack_callback) { + auto begin = chrono::system_clock::now(); + packet->setListener(make_unique>()); + packet->getListener()->waitAndGetLater([ack_callback, begin](bool f) { + auto end = chrono::system_clock::now(); + if(ack_callback) + ack_callback(f); + + log_trace(category::connection, tr("Time needed for command: {}"), chrono::duration_cast(end - begin).count()); + }); + } + packet->enable_flag(PacketFlag::NewProtocol); + this->send_packet(packet); +} + +void ProtocolHandler::send_packet(const std::shared_ptr &packet) { + std::vector result; + if(!this->create_datagram_packets(result, packet) || result.empty()) { + log_error(category::connection, tr("Failed to create datagram packets!")); + return; + } + + auto socket = this->handle->get_socket(); + if(!socket) { + log_error(category::connection, tr("Failed to get socket!")); + return; + } + + for(const auto& buffer : result) + socket->send_message(buffer); +} + +void ProtocolHandler::send_acknowledge(uint16_t packet_id, bool low) { + char buffer[2]; + le2be16(packet_id, buffer); + auto packet = make_shared(low ? protocol::PacketTypeInfo::AckLow : protocol::PacketTypeInfo::Ack, 0, pipes::buffer_view{buffer, 2}); + if(this->connection_state >= connection_state::CONNECTING) { + ;//packet->toggle(protocol::PacketFlag::NewProtocol, !low); + //LivingBots DDOS protection dont want a new protocol here! + } + this->send_packet(packet); +} + +void ProtocolHandler::do_close_connection() { + this->connection_state = connection_state::DISCONNECTED; + for(auto& buffer : this->_packet_buffers) { + lock_guard lock(buffer.buffer_lock); + buffer.clear(); + } +} + +void ProtocolHandler::disconnect(const std::string &reason) { + if(this->connection_state >= connection_state::DISCONNECTING) + return; + + this->connection_state = connection_state::DISCONNECTING; + this->disconnect_timestamp = system_clock::now(); + + auto did = ++this->disconnect_id; + Command cmd("clientdisconnect"); + cmd["reasonmsg"] = reason; + this->send_command(cmd, [&, did](bool success){ + /* if !success then we'll have prop already triggered the timeout and this here is obsolete */ + if(success && this->connection_state == connection_state::DISCONNECTING && this->disconnect_id == did) + this->handle->close_connection(); + }); +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/ProtocolHandler.h b/native/serverconnection/src/connection/ProtocolHandler.h new file mode 100644 index 0000000..b53507c --- /dev/null +++ b/native/serverconnection/src/connection/ProtocolHandler.h @@ -0,0 +1,148 @@ +#pragma once + +#include +#include + +#define NO_LOG +#ifdef WIN32 + #include //Needs to be included; No clue why +#endif + +#include +#include +#include +#include +#include +#include "ServerConnection.h" + +namespace ts { + namespace connection { + class CryptionHandler; + class CompressionHandler; + } +} + +namespace tc { + namespace connection { + class ServerConnection; + + namespace connection_state { + enum value { + INITIALIZING, + INIT_LOW, + INIT_HIGH, + CONNECTING, + CONNECTED, + DISCONNECTING, + DISCONNECTED + }; + }; + namespace pow_state { + enum value : uint8_t { + COOKIE_GET, + COOKIE_SET, + PUZZLE_GET, + PUZZLE_SET, + PUZZLE_SOLVE, + PUZZLE_RESET, + COMPLETED, + COMMAND_RESET = 127, + UNSET = 0xFB + }; + }; + + class ProtocolHandler { + typedef ts::protocol::PacketRingBuffer packet_buffer_t; + typedef std::array packet_buffers_t; + friend class ServerConnection; + public: + ProtocolHandler(ServerConnection*); + ~ProtocolHandler(); + + void reset(); + void connect(); + void execute_tick(); + void execute_resend(); + + void progress_packet(const pipes::buffer_view& /* buffer */); + bool handle_packets(); /* if true we have more left */ + void send_packet(const std::shared_ptr& /* packet */); + void send_command(const ts::Command& /* command */, const std::function & /* acknowledge callback */ = NULL); + + void disconnect(const std::string& /* message */); + + void send_acknowledge(uint16_t /* packet id */, bool /* low */); + + ecc_key& get_identity_key() { return this->crypto.identity; } + + inline std::chrono::microseconds current_ping() { return this->ping.value; } + + connection_state::value connection_state = connection_state::INITIALIZING; + server_type::value server_type = server_type::TEASPEAK; + private: + void do_close_connection(); /* only call from ServerConnection. Close all connections via ServerConnection! */ + + void handlePacketCommand(const std::shared_ptr&); + void handlePacketAck(const std::shared_ptr&); + void handlePacketVoice(const std::shared_ptr&); + void handlePacketPing(const std::shared_ptr&); + void handlePacketInit(const std::shared_ptr&); + + bool create_datagram_packets(std::vector &result, const std::shared_ptr &packet); + + ServerConnection* handle; + + std::chrono::system_clock::time_point connect_timestamp; + std::chrono::system_clock::time_point disconnect_timestamp; + uint8_t disconnect_id = 0; + + struct { + pow_state::value state; + + uint32_t client_ts3_build_timestamp = 173265950 /* TS3 */; /* needs to be lower than 173265950 for old stuff, else new protocol */ + uint8_t client_control_data[4] = {0,0,0,0}; + uint8_t server_control_data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t server_data[100]; + + std::chrono::system_clock::time_point last_response; + std::chrono::system_clock::time_point last_resend; + pipes::buffer last_buffer; + } pow; + void pow_send_cookie_get(); + + struct { + uint8_t alpha[10]; + uint8_t beta[54]; + uint8_t beta_length; /* 10 or 54 */ + + ecc_key identity{}; + + std::string initiv_command; + } crypto; + std::string generate_client_initiv(); + + uint16_t client_id = 0; + ts::protocol::PacketIdManager _packet_id_manager; + packet_buffers_t _packet_buffers; + uint8_t _packet_buffers_index = 0; + + ts::connection::CryptionHandler crypt_handler; + ts::connection::CompressionHandler compression_handler; + ts::connection::AcknowledgeManager acknowledge_handler; + + void handleCommandInitIVExpend(ts::Command&); + void handleCommandInitIVExpend2(ts::Command&); + void handleCommandInitServer(ts::Command&); + + struct { + std::chrono::system_clock::time_point ping_send_timestamp; + std::chrono::system_clock::time_point ping_received_timestamp; + std::chrono::microseconds value; + uint16_t ping_id; + + std::chrono::microseconds interval = std::chrono::microseconds(2500); + } ping; + void ping_send_request(); + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/ProtocolHandlerCommands.cpp b/native/serverconnection/src/connection/ProtocolHandlerCommands.cpp new file mode 100644 index 0000000..2fa3f94 --- /dev/null +++ b/native/serverconnection/src/connection/ProtocolHandlerCommands.cpp @@ -0,0 +1,18 @@ +#include "ProtocolHandler.h" +#include "ServerConnection.h" +#include "../logger.h" +#include +#include + + +using namespace std; +using namespace tc::connection; +using namespace ts::protocol; +using namespace ts; + +void ProtocolHandler::handleCommandInitServer(ts::Command &cmd) { + this->client_id = cmd["aclid"]; + this->connection_state = connection_state::CONNECTED; + + log_info(category::connection, tr("Received own client id: {}"), this->client_id); +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/ProtocolHandlerCrypto.cpp b/native/serverconnection/src/connection/ProtocolHandlerCrypto.cpp new file mode 100644 index 0000000..7cea312 --- /dev/null +++ b/native/serverconnection/src/connection/ProtocolHandlerCrypto.cpp @@ -0,0 +1,216 @@ +#include "ProtocolHandler.h" +#include "ServerConnection.h" +#include "Socket.h" +#include "../logger.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace tc::connection; +using namespace ts::protocol; +using namespace ts; + +inline void generate_random(uint8_t *destination, size_t length) { + while(length-- > 0) + *(destination++) = (uint8_t) rand(); +} + +std::string ProtocolHandler::generate_client_initiv() { + if(!this->crypto.initiv_command.empty()) + return this->crypto.initiv_command; + + /* setup basic parameters */ + if((this->crypto.alpha[0] & 0x01) == 0) { + generate_random(this->crypto.alpha, 10); + this->crypto.alpha[0] |= 0x01; + } + + Command command("clientinitiv"); + command["alpha"] = base64::encode((char*) this->crypto.alpha, 10); + command["ot"] = 1; + command["ip"] = "unknown"; + + if(this->server_type != server_type::TEAMSPEAK) /* if TEAMSPEAK then TS3 has been enforced */ + command.enableParm("teaspeak"); /* using "old" encryption system, we expect a teaspeak=1 within the response */ + { + size_t buffer_length = 265; + char buffer[265]; + auto result = ecc_export((unsigned char *) buffer, (unsigned long*) &buffer_length, PK_PUBLIC, &this->crypto.identity); + if(result == CRYPT_OK) + command["omega"] = base64::encode(buffer, buffer_length); + else + log_error(category::connection, tr("Failed to export identiry ({})"), result); + } + + this->crypto.initiv_command = command.build(true); + return this->crypto.initiv_command; +} + +void ProtocolHandler::handleCommandInitIVExpend(ts::Command &cmd) { + this->pow.last_buffer = pipes::buffer{}; + + auto alpha = base64::decode(cmd["alpha"]); + auto beta = base64::decode(cmd["beta"]); + auto omega = base64::decode(cmd["omega"]); + + if(alpha.length() != 10 || memcmp(alpha.data(), this->crypto.alpha, 10) != 0) { + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("alpha key missmatch")), true); + this->handle->close_connection(); + + log_error(category::connection, tr("InitIVExpend contains invalid alpha")); + return; + } + + ecc_key server_key{}; + if(ecc_import((u_char*) omega.data(), omega.length(), &server_key) != CRYPT_OK) { + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to import server key")), true); + this->handle->close_connection(); + + log_error(category::connection, tr("InitIVExpend contains invalid key")); + return; + } + + string error; + if(!this->crypt_handler.setupSharedSecret(alpha, beta, &server_key, &this->crypto.identity, error)) { + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to setup encryption")), true); + this->handle->close_connection(); + + log_error(category::connection, tr("Failed to setup crypto ({})"), error); + return; + } + + if(this->server_type == server_type::UNKNOWN) { + if(cmd[0].has("teaspeak") && cmd["teaspeak"].as()) { + this->server_type = server_type::TEASPEAK; + } else { + this->server_type = server_type::TEAMSPEAK; + } + } + + this->handle->call_connect_result.call(0, true); + this->connection_state = connection_state::CONNECTING; +} + + +int __ed_sha512_init(sha512_context* ctx) { + ctx->context = new hash_state{}; + return sha512_init((hash_state*) ctx->context) == CRYPT_OK; +} + +int __ed_sha512_final(sha512_context* ctx, unsigned char *out) { + assert(ctx->context); + + auto result = sha512_done((hash_state*) ctx->context, out) == CRYPT_OK; + delete (hash_state*) ctx->context; + return result; +} +int __ed_sha512_update(sha512_context* ctx, const unsigned char *msg, size_t len) { + assert(ctx->context); + return sha512_process((hash_state*) ctx->context, msg, len) == CRYPT_OK; +} + +static sha512_functions __ed_sha512_functions { + __ed_sha512_init, + __ed_sha512_final, + __ed_sha512_update +}; + +void ProtocolHandler::handleCommandInitIVExpend2(ts::Command &cmd) { + this->pow.last_buffer = pipes::buffer{}; + + /* setup ed functions */ + if(&__ed_sha512_functions != &_ed_sha512_functions) + _ed_sha512_functions = __ed_sha512_functions; + + auto beta = base64::decode(cmd["beta"]); + auto omega = base64::decode(cmd["omega"]); + auto proof = base64::decode(cmd["proof"]); + + auto crypto_chain_data = base64::decode(cmd["l"]); + auto crypto_root = cmd[0].has("root") ? base64::decode(cmd["root"]) : string((char*) license::teamspeak::public_root, 32); + auto crypto_hash = digest::sha256(crypto_chain_data); + + /* suspecius, tries the server to hide himself? We dont know */ + if(this->server_type == server_type::UNKNOWN) { + if(cmd[0].has("root")) + this->server_type = server_type::TEASPEAK; + else + this->server_type = server_type::TEAMSPEAK; + } + + ecc_key server_key{}; + if(ecc_import((u_char*) omega.data(), omega.length(), &server_key) != CRYPT_OK) { + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to import server key")), true); + this->handle->close_connection(); + + log_error(category::connection, tr("InitIVExpend contains invalid key")); + return; + } + + int result, crypt_result; + if((crypt_result = ecc_verify_hash((u_char*) proof.data(), proof.length(), (u_char*) crypto_hash.data(), crypto_hash.length(), &result, &server_key)) != CRYPT_OK || result != 1) { + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to verify server integrity")), true); + this->handle->close_connection(); + return; + } + + string error; + auto crypto_chain = license::teamspeak::LicenseChain::parse(crypto_chain_data, error, false); + if(!crypto_chain) { + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to read crypto chain")), true); + this->handle->close_connection(); + return; + } + + auto server_public_key = crypto_chain->generatePublicKey(*(license::teamspeak::LicensePublicKey*) crypto_root.data()); + crypto_chain->print(); + + u_char seed[32]; + ed25519_create_seed(seed); + u_char public_key[32], private_key[64]; /* We need 64 bytes because we're doing some SHA512 actions */ + ed25519_create_keypair(public_key, private_key, seed); + + /* send clientek response */ + { + size_t sign_buffer_length = 200; + char sign_buffer[200]; + + prng_state prng_state{}; + memset(&prng_state, 0, sizeof(prng_state)); + + auto proof_data = digest::sha256(string((char*) public_key, 32) + beta); + if(ecc_sign_hash((uint8_t*) proof_data.data(), proof_data.length(), (uint8_t*) sign_buffer, (unsigned long*) &sign_buffer_length, &prng_state, find_prng("sprng"), &this->crypto.identity) != CRYPT_OK) { + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to generate proof of identity")), true); + this->handle->close_connection(); + return; + } + + Command response("clientek"); + response["ek"] = base64::encode((char*) public_key, 32); + response["proof"] = base64::encode(sign_buffer, sign_buffer_length); + /* no need to send this because we're sending the clientinit as the begin packet along with the POW init */ + //this->_packet_id_manager.nextPacketId(PacketTypeInfo::Command); /* skip the first because we've send our first command within the low level handshake packets */ + this->send_command(response, [&](bool success){ + if(success) { + /* trigger connected; because the connection has been established on protocol layer */ + this->handle->call_connect_result.call(0, true); + this->connection_state = connection_state::CONNECTING; + } + }); /* needs to be encrypted at the time! */ + } + + + if(!this->crypt_handler.setupSharedSecretNew(string((char*) this->crypto.alpha, 10), beta, (char*) private_key, server_public_key.data())) { + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to setup encryption")), true); + this->handle->close_connection(); + return; + } +} diff --git a/native/serverconnection/src/connection/ProtocolHandlerPOW.cpp b/native/serverconnection/src/connection/ProtocolHandlerPOW.cpp new file mode 100644 index 0000000..3679673 --- /dev/null +++ b/native/serverconnection/src/connection/ProtocolHandlerPOW.cpp @@ -0,0 +1,168 @@ +#include "ProtocolHandler.h" +#include "ServerConnection.h" +#include "Socket.h" +#include "../logger.h" +#include "Error.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; +using namespace tc::connection; +using namespace ts::protocol; +using namespace ts; + +inline void generate_random(uint8_t *destination, size_t length) { + while(length-- > 0) + *(destination++) = (uint8_t) rand(); +} + +inline void write_reversed(uint8_t* destination, uint8_t* source, size_t length) { + destination += length; + while(length-- > 0) + *(--destination) = *(source++); +} + +inline bool solve_puzzle(mp_int& x, mp_int& n, mp_int& result, uint32_t level) { + mp_int exp{}; + mp_init(&exp); + mp_2expt(&exp, level); + + + if (mp_exptmod(&x, &exp, &n, &result) != CRYPT_OK) { //Sometimes it fails (unknown why :D) + mp_clear(&exp); + return false; + } + + mp_clear(&exp); + return true; +} + +void ProtocolHandler::handlePacketInit(const std::shared_ptr &packet) { + this->pow.last_response = system_clock::now(); + + auto data = packet->data(); + auto packet_state = static_cast(data[0]); + + if(packet_state == pow_state::COMMAND_RESET) { + log_trace(category::connection, tr("[POW] Received reset")); + this->pow.state = pow_state::COOKIE_SET; /* next expected packet state */ + this->pow_send_cookie_get(); + return; + } + + log_trace(category::connection, tr("[POW] State {} | {}"), packet_state, data.length()); + if(packet_state != this->pow.state) + return; //TODO handle error? + this->acknowledge_handler.reset(); /* we don't need an ack anymore for our init packet */ + + if(packet_state == pow_state::COOKIE_SET) { + if(data.length() != 21 && data.length() != 5) { + log_trace(category::connection, tr("[POW] Dropping cookie packet (got {} bytes expect 21 or 5 bytes)"), data.length()); + return; + } + + if(data.length() == 21) { + memcpy(&this->pow.server_control_data[0], &data[1], 16); + //TODO test client data reserved bytes + } else { + auto errc = ntohl(*(uint32_t*) &data[1]); + auto err = ts::findError(errc); + + log_error(category::connection, tr("[POW] Received error code: {:x} ({})"), errc, err.message); + this->handle->call_connect_result.call(this->handle->errors.register_error(tr("received error: ") + to_string(errc) + " (" + err.message + ")"), true); + this->handle->close_connection(); + return; + } + + /* send puzzle get request */ + { + this->pow.state = pow_state::PUZZLE_SET; /* next expected packet state */ + + uint8_t response_buffer[25]; + le2be32(this->pow.client_ts3_build_timestamp, &response_buffer[0]); + response_buffer[4] = pow_state::PUZZLE_GET; + + memcpy(&response_buffer[5], this->pow.server_control_data, 16); + memcpy(&response_buffer[21], &data[17], 4); + + this->pow.last_buffer = pipes::buffer_view{response_buffer, 25}.own_buffer(); + this->pow.last_resend = system_clock::now(); + + this->send_packet(make_shared(PacketTypeInfo::Init1, PacketFlag::Unencrypted, this->pow.last_buffer)); + } + + return; + } else if(packet_state == pow_state::PUZZLE_SET) { + constexpr auto expected_bytes = 1 + 64 * 2 + 4 + 100; + if(data.length() != 1 + 64 * 2 + 4 + 100) { + log_trace(category::connection, tr("[POW] Dropping puzzle packet (got {} bytes expect {} bytes)"), data.length(), expected_bytes); + return; + } + + mp_int point_x{}, point_n{}, result{}; + if(mp_read_unsigned_bin(&point_x, (u_char*) &data[1], 64) < 0) + return; //TODO handle error + + if(mp_read_unsigned_bin(&point_n, (u_char*) &data[65], 64) < 0) { + mp_clear_multi(&point_x, nullptr); + return; //TODO handle error + } + + log_trace(category::connection, tr("[POW] Received puzzle with level {}"), be2le32(&data[1 + 64 + 64])); + if(!solve_puzzle(point_x, point_n, result, be2le32(&data[1 + 64 + 64]))) { + mp_clear_multi(&point_x, &point_n, nullptr); + log_trace(connection, tr("[POW] Failed to solve puzzle!")); + return; //TODO handle error + } + + { + auto command = this->generate_client_initiv(); + size_t response_buffer_length = 301 + command.size(); + auto response_buffer = buffer::allocate_buffer(response_buffer_length); + + le2be32(this->pow.client_ts3_build_timestamp, &response_buffer[0]); + response_buffer[4] = pow_state::PUZZLE_SOLVE; + memcpy(&response_buffer[5], &data[1], 64 * 2 + 100 + 4); + + auto offset = 4 + 1 + 2 * 64 + 04 + 100; + memset(&response_buffer[offset], 0, 64); + mp_to_unsigned_bin(&result, (u_char*) &response_buffer[offset]); + + memcpy(&response_buffer[301], command.data(), command.size()); + + this->pow.last_buffer = response_buffer; + this->pow.last_resend = system_clock::now(); + this->send_packet(make_shared(PacketTypeInfo::Init1, PacketFlag::Unencrypted, this->pow.last_buffer)); + } + mp_clear_multi(&point_x, &point_n, &result, nullptr); + this->connection_state = connection_state::INIT_HIGH; + } +} + +void ProtocolHandler::pow_send_cookie_get() { + this->pow.state = pow_state::COOKIE_SET; /* next expected packet state */ + + if((this->pow.client_control_data[0] & 0x01U) == 0) { + generate_random(this->pow.client_control_data, 4); + this->pow.client_control_data[0] |= 0x01U; + } + + this->pow.client_ts3_build_timestamp = floor < seconds > ((system_clock::now() - hours{24}).time_since_epoch()).count(); + + uint8_t response_buffer[21]; + le2be32(this->pow.client_ts3_build_timestamp, &response_buffer[0]); + response_buffer[4] = pow_state::COOKIE_GET; + memset(&response_buffer[5], 0, 4); + memcpy(&response_buffer[9], &this->pow.client_control_data, 4); + memset(&response_buffer[13], 0, 8); + + this->pow.last_buffer = pipes::buffer_view{response_buffer, 21}.own_buffer(); + this->pow.last_resend = system_clock::now(); + this->send_packet(make_shared(PacketTypeInfo::Init1, PacketFlag::Unencrypted, this->pow.last_buffer)); +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/ProtocolHandlerPackets.cpp b/native/serverconnection/src/connection/ProtocolHandlerPackets.cpp new file mode 100644 index 0000000..a74b663 --- /dev/null +++ b/native/serverconnection/src/connection/ProtocolHandlerPackets.cpp @@ -0,0 +1,97 @@ +#include "ProtocolHandler.h" +#include "ServerConnection.h" +#include "Socket.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audio/VoiceConnection.h" +#include "../logger.h" + +using namespace std; +using namespace tc::connection; +using namespace ts::protocol; +using namespace ts; + +//#define LOG_PING + +void ProtocolHandler::handlePacketAck(const std::shared_ptr &ack) { + string error; + log_trace(category::connection, tr("Handle packet acknowledge for {}"), be2le16(&ack->data()[0])); + if(!this->acknowledge_handler.process_acknowledge(*ack, error)) { } +} + +void ProtocolHandler::handlePacketCommand(const std::shared_ptr &packet) { + //cout << "Received command: " << packet->data().string() << endl; + + std::unique_ptr command; + try { + command = make_unique(packet->asCommand()); + } catch(const std::invalid_argument& ex) { + log_error(category::connection, tr("Failed to parse command (invalid_argument): {}"), ex.what()); + return; + } catch(const ts::command_malformed_exception& ex) { + log_error(category::connection, tr("Failed to parse command (command_malformed_exception): {}@{}"), ex.what(), ex.index()); + return; + } catch(const std::exception& ex) { + log_error(category::connection, tr("Failed to parse command (exception): {}"), ex.what()); + return; + } + + if(command->command() == "initivexpand") { + this->handleCommandInitIVExpend(*command); + } else if(command->command() == "initivexpand2") { + this->handleCommandInitIVExpend2(*command); + } else if(command->command() == "initserver") { + this->handleCommandInitServer(*command); + } + + { + lock_guard lock(this->handle->pending_commands_lock); + this->handle->pending_commands.push_back(move(command)); + } + this->handle->execute_pending_commands(); +} + +void ProtocolHandler::handlePacketVoice(const std::shared_ptr &packet) { + this->handle->voice_connection->process_packet(packet); +} + +void ProtocolHandler::handlePacketPing(const std::shared_ptr &packet) { + if(packet->type() == PacketTypeInfo::Pong) { + uint16_t id = be2le16((char*) packet->data().data_ptr()); +#ifdef LOG_PING + cout << "Received pong (" << id << "|" << this->ping.ping_id << ")" << endl; +#endif + if(id == this->ping.ping_id) { + this->ping.ping_received_timestamp = chrono::system_clock::now(); + this->ping.value = chrono::duration_cast(this->ping.ping_received_timestamp - this->ping.ping_send_timestamp); +#ifdef LOG_PING + cout << "Updating client ping: " << chrono::duration_cast(this->ping.value).count() << "us" << endl; +#endif + } + } else { +#ifdef LOG_PING + cout << "Received ping, sending pong" << endl; +#endif + + char buffer[2]; + le2be16(packet->packetId(), buffer); + this->send_packet(make_shared(PacketTypeInfo::Pong, PacketFlag::Unencrypted, pipes::buffer_view{buffer, 2})); + } +} + +void ProtocolHandler::ping_send_request() { + auto packet = make_shared(PacketTypeInfo::Ping, pipes::buffer_view{}); + packet->enable_flag(PacketFlag::Unencrypted); + this->send_packet(packet); + assert(packet->memory_state.id_branded); + + this->ping.ping_send_timestamp = chrono::system_clock::now(); + this->ping.ping_id = packet->packetId(); +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/ServerConnection.cpp b/native/serverconnection/src/connection/ServerConnection.cpp new file mode 100644 index 0000000..f5e4980 --- /dev/null +++ b/native/serverconnection/src/connection/ServerConnection.cpp @@ -0,0 +1,727 @@ +#include "ServerConnection.h" +#include "ProtocolHandler.h" +#include "Socket.h" +#include "audio/VoiceConnection.h" +#include "audio/AudioSender.h" +#include "../logger.h" +#include "../hwuid.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +//#define FUZZ_VOICE +//#define SHUFFLE_VOICE + +using namespace std; +using namespace std::chrono; +using namespace tc::connection; + +string ErrorHandler::get_message(ErrorHandler::error_id id) { + if(id == 0) + return "success"; + + auto index = (-id - 1) % this->error_varianz; + assert(index >= 0 && index < this->error_varianz); + return this->error_messages[index]; +} + +ErrorHandler::error_id ErrorHandler::register_error(const string &message) { + auto index = this->error_index++ % this->error_varianz; + this->error_messages[index] = message; + return -index - 1; +} + +ServerConnection::ServerConnection() { + logger::debug(category::connection, tr("Allocated ServerConnection {}."), (void*) this); +} + +ServerConnection::~ServerConnection() { + logger::debug(category::connection, tr("Begin deallocating ServerConnection {}."), (void*) this); + if(this->protocol_handler && this->protocol_handler->connection_state == connection_state::CONNECTED) + this->protocol_handler->disconnect("server connection has been destoryed"); + this->close_connection(); + this->finalize(); + + logger::debug(category::connection, tr("Finished deallocating ServerConnection {}."), (void*) this); +} + +NAN_MODULE_INIT(ServerConnection::Init) { + auto klass = Nan::New(ServerConnection::new_instance); + klass->SetClassName(Nan::New("NativeServerConnection").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "connect", ServerConnection::_connect); + Nan::SetPrototypeMethod(klass, "connected", ServerConnection::_connected); + Nan::SetPrototypeMethod(klass, "disconnect", ServerConnection::_disconnect); + Nan::SetPrototypeMethod(klass, "error_message", ServerConnection::_error_message); + Nan::SetPrototypeMethod(klass, "send_command", ServerConnection::_send_command); + Nan::SetPrototypeMethod(klass, "send_voice_data", ServerConnection::_send_voice_data); + Nan::SetPrototypeMethod(klass, "send_voice_data_raw", ServerConnection::_send_voice_data_raw); + Nan::SetPrototypeMethod(klass, "current_ping", ServerConnection::_current_ping); + + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(ServerConnection::new_instance) { + //info.GetReturnValue().Set(Nan::New("Hello World").ToLocalChecked()); + + if (info.IsConstructCall()) { + auto instance = new ServerConnection(); + instance->Wrap(info.This()); + instance->initialize(); + //Nan::Set(info.This(), New("type").ToLocalChecked(), New(type)); + info.GetReturnValue().Set(info.This()); + } else { + v8::Local cons = Nan::New(constructor()); + + Nan::TryCatch try_catch; + auto result = Nan::NewInstance(cons, 0, nullptr); + if(try_catch.HasCaught()) { + try_catch.ReThrow(); + return; + } + info.GetReturnValue().Set(result.ToLocalChecked()); + } +} + +void ServerConnection::initialize() { + this->event_loop_exit = false; + this->event_thread = thread(&ServerConnection::event_loop, this); + this->protocol_handler = make_unique(this); + this->voice_connection = make_shared(this); + this->voice_connection->_ref = this->voice_connection; + this->voice_connection->initialize_js_object(); + + this->execute_pending_commands = Nan::async_callback([&]{ + Nan::HandleScope scope; + this->_execute_callback_commands(); + }); + this->execute_pending_voice = Nan::async_callback([&]{ + Nan::HandleScope scope; + this->_execute_callback_voice(); + }); + this->execute_callback_disconnect = Nan::async_callback([&](std::string reason){ + Nan::HandleScope scope; + this->_execute_callback_disconnect(reason); + }); + + + this->call_connect_result = Nan::async_callback([&](ErrorHandler::error_id error_id) { + Nan::HandleScope scope; + /* lets update the server type */ + { + auto js_this = this->handle(); + Nan::Set(js_this, Nan::New("server_type").ToLocalChecked(), Nan::New(this->protocol_handler->server_type)); + } + + /* lets call the connect callback */ + { + v8::Local argv[1]; + argv[0] = Nan::New(error_id); + + if(this->callback_connect) + Nan::Call(*this->callback_connect, 1, argv); + this->callback_connect = nullptr; + } + }); + + + this->call_disconnect_result = Nan::async_callback([&](ErrorHandler::error_id error_id) { + Nan::HandleScope scope; + v8::Local argv[1]; + argv[0] = Nan::New(error_id); + + if(this->callback_disconnect) + Nan::Call(*this->callback_disconnect, 1, argv); + this->callback_disconnect = nullptr; + }); + + auto js_this = this->handle(); + Nan::Set(js_this, Nan::New("_voice_connection").ToLocalChecked(), this->voice_connection->js_handle()); + +} + +void ServerConnection::finalize() { + this->event_loop_exit = true; + this->event_condition.notify_all(); + this->event_thread.join(); +} + +void ServerConnection::event_loop() { + auto eval_timeout = [&]{ + auto best = this->next_tick; + if(this->next_resend < best) + best = this->next_resend; + if(this->event_loop_execute_connection_close) + return system_clock::time_point{}; + return best; + }; + + while(!this->event_loop_exit) { + auto timeout = eval_timeout(); + { + unique_lock lock(this->event_lock); + this->event_condition.wait_until(lock, timeout, [&]{ + if(eval_timeout() != timeout) + return true; + return this->event_loop_exit; + }); + + if(this->event_loop_exit) + break; + } + if(this->event_loop_execute_connection_close) { + this->close_connection(); + this->event_loop_execute_connection_close = false; + } + auto date = chrono::system_clock::now(); + if(this->next_tick <= date) { + this->next_tick = date + chrono::milliseconds(500); + this->execute_tick(); + } + if(this->next_resend <= date) { + this->next_resend = date + chrono::seconds(5); + if(this->protocol_handler) + this->protocol_handler->execute_resend(); + } + } +} + +void ServerConnection::schedule_resend(const std::chrono::system_clock::time_point &timeout) { + if(this->next_resend > timeout) { + this->next_resend = timeout; + this->event_condition.notify_one(); + } +} +NAN_METHOD(ServerConnection::connect) { + if(!this->protocol_handler) { + Nan::ThrowError("ServerConnection not initialized"); + return; + } + if(info.Length() != 1) { + Nan::ThrowError(tr("Invalid argument count")); + return; + } + + v8::Local arguments = info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked(); + + if(!arguments->IsObject()) { + Nan::ThrowError(tr("Invalid argument")); + return; + } + + auto remote_host = Nan::Get(arguments, Nan::New("remote_host").ToLocalChecked()).ToLocalChecked(); + auto remote_port = Nan::Get(arguments, Nan::New("remote_port").ToLocalChecked()).ToLocalChecked(); + auto timeout = Nan::Get(arguments, Nan::New("timeout").ToLocalChecked()).ToLocalChecked(); + + auto callback = Nan::Get(arguments, Nan::New("callback").ToLocalChecked()).ToLocalChecked(); + + auto identity_key = Nan::Get(arguments, Nan::New("identity_key").ToLocalChecked()).ToLocalChecked(); + auto teamspeak = Nan::Get(arguments, Nan::New("teamspeak").ToLocalChecked()).ToLocalChecked(); + + if(!identity_key->IsString() && !identity_key->IsNullOrUndefined()) { + Nan::ThrowError(tr("Invalid identity")); + return; + } + + if(!remote_host->IsString() || !remote_port->IsNumber()) { + Nan::ThrowError(tr("Invalid argument host/port")); + return; + } + + if(!callback->IsFunction() ) { + Nan::ThrowError(tr("Invalid callback")); + return; + } + + unique_lock _disconnect_lock(this->disconnect_lock, defer_lock); + if(!_disconnect_lock.try_lock_for(chrono::milliseconds(500))) { + Nan::ThrowError(tr("failed to acquire disconnect lock")); + return; + } + + this->callback_connect = make_unique(callback.As()); + + this->voice_connection->reset(); + this->protocol_handler->reset(); + if(identity_key->IsString()) { + auto& identity = this->protocol_handler->get_identity_key(); + auto key = base64::decode(*Nan::Utf8String(identity_key->ToString(Nan::GetCurrentContext()).ToLocalChecked())); + if(ecc_import((u_char*) key.data(), (unsigned long) key.length(), &identity) != CRYPT_OK) { + Nan::ThrowError(tr("failed to import identity")); + return; + } + } else { + auto& identity = this->protocol_handler->get_identity_key(); + prng_state rndState{}; + memset(&rndState, 0, sizeof(prng_state)); + int err; + + if((err = ecc_make_key_ex(&rndState, find_prng("sprng"), &identity, <c_ecc_sets[5])) != CRYPT_OK) { + Nan::ThrowError(tr("failed to generate ephemeral identity")); + return; + } + } + + sockaddr_storage remote_address{}; + /* resolve address */ + { + addrinfo hints{}, *result; + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + + auto _remote_host = Nan::Utf8String(remote_host->ToString(Nan::GetCurrentContext()).ToLocalChecked()); + if(getaddrinfo(*_remote_host, nullptr, &hints, &result) != 0 || !result) { + this->call_connect_result(this->errors.register_error(tr("failed to resolve hostname"))); + return; + } + + memcpy(&remote_address, result->ai_addr, result->ai_addrlen); + freeaddrinfo(result); + } + switch(remote_address.ss_family) { + case AF_INET: + ((sockaddr_in*) &remote_address)->sin_port = htons(remote_port->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); + case AF_INET6: + ((sockaddr_in6*) &remote_address)->sin6_port = htons(remote_port->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); + default:break; + } + + logger::info(category::connection, tr("Connecting to {}."), net::to_string(remote_address)); + this->socket = make_shared(remote_address); + if(!this->socket->initialize()) { + this->call_connect_result(this->errors.register_error("failed to initialize socket")); + this->socket = nullptr; + return; + } + + this->socket->on_data = [&](const pipes::buffer_view& buffer) { this->protocol_handler->progress_packet(buffer); }; + if(teamspeak->IsBoolean() && teamspeak->BooleanValue(info.GetIsolate())) + this->protocol_handler->server_type = server_type::TEAMSPEAK; + this->protocol_handler->connect(); +} + +NAN_METHOD(ServerConnection::_connected) { + return ObjectWrap::Unwrap(info.Holder())->connected(info); +} + + +NAN_METHOD(ServerConnection::_connect) { + return ObjectWrap::Unwrap(info.Holder())->connect(info); +} +NAN_METHOD(ServerConnection::connected) { + bool result = this->protocol_handler && this->protocol_handler->connection_state >= connection_state::CONNECTING && this->protocol_handler->connection_state < connection_state::DISCONNECTING; + info.GetReturnValue().Set(result); +} + + +NAN_METHOD(ServerConnection::_disconnect) { + return ObjectWrap::Unwrap(info.Holder())->disconnect(info); +} +NAN_METHOD(ServerConnection::disconnect) { + if(info.Length() != 2) { + Nan::ThrowError("Invalid argument count"); + return; + } + + if(!info[1]->IsFunction() || !info[0]->IsString()) { + Nan::ThrowError("Invalid argument"); + return; + } + this->callback_disconnect = make_unique(info[1].As()); + if(!this->socket) { + this->call_disconnect_result(0); /* this->errors.register_error("not connected") */ + return; + } + + if(this->protocol_handler) { + this->protocol_handler->disconnect(*Nan::Utf8String(info[0])); + } +} + +NAN_METHOD(ServerConnection::_error_message) { + return ObjectWrap::Unwrap(info.Holder())->error_message(info); +} +NAN_METHOD(ServerConnection::error_message) { + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("Invalid argument"); + return; + } + + auto error = this->errors.get_message((ErrorHandler::error_id) info[0]->IntegerValue(Nan::GetCurrentContext()).FromMaybe(0)); + info.GetReturnValue().Set(Nan::New(error).ToLocalChecked()); +} + +//send_command(command: string, arguments: any[], switches: string[]); +template +std::string _to_string(const T value) { + std::string result(15, '\0'); + auto written = std::snprintf(&result[0], result.size(), "%.6f", value); + if(written < 0) { + log_warn(general, "Failed to format float value: {}; {}", value, written); + return "0"; + } + result.resize(written); + return result; +} + +NAN_METHOD(ServerConnection::_send_command) { + return ObjectWrap::Unwrap(info.Holder())->send_command(info); +} + +struct TS3VersionSettings { + std::string build; + std::string platform; + std::string sign; +}; +NAN_METHOD(ServerConnection::send_command) { + if(!this->protocol_handler) { + Nan::ThrowError("ServerConnection not initialized"); + return; + } + + if(info.Length() != 3) { + Nan::ThrowError("invalid argument count"); + return; + } + + if(!info[0]->IsString() || !info[1]->IsArray() || !info[2]->IsArray()) { + Nan::ThrowError("invalid argument type"); + return; + } + + auto begin = chrono::system_clock::now(); + auto command = info[0]->ToString(Nan::GetCurrentContext()).ToLocalChecked(); + auto arguments = info[1].As(); + auto switches = info[2].As(); + + ts::Command cmd(*Nan::Utf8String(command)); + for(size_t index = 0; index < arguments->Length(); index++) { + auto object = arguments->Get((uint32_t) index); + if(!object->IsObject()) { + Nan::ThrowError(Nan::New("invalid parameter (" + to_string(index) + ")").ToLocalChecked()); + return; + } + + v8::Local properties = object->ToObject(Nan::GetCurrentContext()).ToLocalChecked()->GetOwnPropertyNames(Nan::GetCurrentContext()).ToLocalChecked(); + for(uint32_t i = 0; i < properties->Length(); i++) { + auto key = properties->Get(i)->ToString(Nan::GetCurrentContext()).ToLocalChecked(); + auto value = object->ToObject(Nan::GetCurrentContext()).ToLocalChecked()->Get(Nan::GetCurrentContext(), key).ToLocalChecked(); + + string key_string = *Nan::Utf8String(key); + if(value->IsInt32()) + cmd[index][key_string] = value->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + else if(value->IsNumber() || value->IsNumberObject()) + cmd[index][key_string] = _to_string(value->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); /* requires our own conversation because node overrides stuff to 0,0000*/ + else if(value->IsString()) + cmd[index][key_string] = *Nan::Utf8String(value->ToString(Nan::GetCurrentContext()).ToLocalChecked()); + else if(value->IsBoolean() || value->IsBooleanObject()) + cmd[index][key_string] = value->BooleanValue(info.GetIsolate()); + else if(value->IsNullOrUndefined()) + cmd[index][key_string] = ""; + else { + Nan::ThrowError(Nan::New("invalid parameter (" + to_string(index) + ":" + key_string + ")").ToLocalChecked()); + return; + } + } + } + + + for(size_t index = 0; index < switches->Length(); index++) { + auto object = switches->Get((uint32_t) index); + if(!object->IsString()) { + Nan::ThrowError(Nan::New("invalid switch (" + to_string(index) + ")").ToLocalChecked()); + return; + } + + cmd.enableParm(*Nan::Utf8String(object)); + } + + if(this->protocol_handler->server_type == server_type::TEAMSPEAK) { + if(cmd.command() == "clientinit") { + /* If we have a return code here some strange stuff happens (Ghost client) */ + if(cmd[0].has("return_code")) + cmd["return_code"] = nullptr; + + TS3VersionSettings ts_version{}; +#ifdef WIN32 + /* + ts_version = { + "0.0.1 [Build: 1549713549]", + "Linux", + "7XvKmrk7uid2ixHFeERGqcC8vupeQqDypLtw2lY9slDNPojEv//F47UaDLG+TmVk4r6S0TseIKefzBpiRtLDAQ==" + }; + */ + + ts_version = { + "3.?.? [Build: 5680278000]", + "Windows", + "DX5NIYLvfJEUjuIbCidnoeozxIDRRkpq3I9vVMBmE9L2qnekOoBzSenkzsg2lC9CMv8K5hkEzhr2TYUYSwUXCg==" + }; +#else + /* + ts_version = { + "0.0.1 [Build: 1549713549]", + "Linux", + "7XvKmrk7uid2ixHFeERGqcC8vupeQqDypLtw2lY9slDNPojEv//F47UaDLG+TmVk4r6S0TseIKefzBpiRtLDAQ==" + }; + */ + ts_version = { + "3.?.? [Build: 5680278000]", + "Linux", + "Hjd+N58Gv3ENhoKmGYy2bNRBsNNgm5kpiaQWxOj5HN2DXttG6REjymSwJtpJ8muC2gSwRuZi0R+8Laan5ts5CQ==" + }; +#endif + if(std::getenv("teaclient_ts3_build") && std::getenv("teaclient_ts3_platform") && std::getenv("teaclient_ts3_sign")) { + ts_version = { + std::getenv("teaclient_ts3_build"), + std::getenv("teaclient_ts3_platform"), + std::getenv("teaclient_ts3_sign") + }; + } + + cmd["client_version"] = ts_version.build; + cmd["client_platform"] = ts_version.platform; + cmd["client_version_sign"] = ts_version.sign; + cmd[strobf("hwid").string()] = system_uuid(); /* we dont want anybody to patch this out */ + } + } + this->protocol_handler->send_command(cmd); + auto end = chrono::system_clock::now(); +} +NAN_METHOD(ServerConnection::_send_voice_data) { + return ObjectWrap::Unwrap(info.Holder())->send_voice_data(info); +} + +NAN_METHOD(ServerConnection::send_voice_data) { + if(!this->protocol_handler) { + Nan::ThrowError("ServerConnection not initialized"); + return; + } + + if(info.Length() != 3) { + Nan::ThrowError("invalid argument count"); + return; + } + + if(!info[0]->IsUint8Array() || !info[1]->IsInt32() || !info[2]->IsBoolean()) { + Nan::ThrowError("invalid argument type"); + return; + } + + + auto voice_data = info[0].As()->Buffer(); + this->send_voice_data(voice_data->GetContents().Data(), voice_data->GetContents().ByteLength(), (uint8_t) info[1]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0), info[2]->BooleanValue(info.GetIsolate())); +} + + +NAN_METHOD(ServerConnection::_send_voice_data_raw) { + return ObjectWrap::Unwrap(info.Holder())->send_voice_data_raw(info); +} + +NAN_METHOD(ServerConnection::send_voice_data_raw) { + //send_voice_data_raw(buffer: Float32Array, channels: number, sample_rate: number, header: boolean); + + if(info.Length() != 4) { + Nan::ThrowError("invalid argument count"); + return; + } + + if(!info[0]->IsFloat32Array() || !info[1]->IsInt32() || !info[2]->IsInt32()) { + Nan::ThrowError("invalid argument type"); + return; + } + + auto channels = info[1]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + auto sample_rate = info[2]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + auto flag_head = info[2]->BooleanValue(info.GetIsolate()); + + auto voice_data = info[0].As()->Buffer(); + auto vs = this->voice_connection ? this->voice_connection->voice_sender() : nullptr; + if(vs) vs->send_data(voice_data->GetContents().Data(), voice_data->GetContents().ByteLength() / (4 * channels), sample_rate, channels); +} + +#ifdef SHUFFLE_VOICE +static shared_ptr shuffle_cached_packet; +#endif +void ServerConnection::send_voice_data(const void *buffer, size_t buffer_length, uint8_t codec, bool head) { + auto _buffer = pipes::buffer{ts::protocol::ClientPacket::META_SIZE + buffer_length + 3}; + auto packet = ts::protocol::ClientPacket::from_buffer(_buffer); + memset(&_buffer[ts::protocol::ClientPacket::META_MAC_SIZE], 0, ts::protocol::ClientPacket::META_HEADER_SIZE); /* reset all header data */ + packet->type(ts::protocol::PacketTypeInfo::Voice); + + auto data_buffer = packet->data(); + le2be16(this->voice_packet_id++, &data_buffer[0]); /* set voice packet id */ + data_buffer[2] = (uint8_t) codec; /* set voice codec */ + if(buffer_length > 0 && buffer) + memcpy(&data_buffer[3], buffer, buffer_length); + + if(head) /* head packet */ + packet->enable_flag(ts::protocol::PacketFlag::Compressed); + packet->enable_flag(ts::protocol::PacketFlag::Unencrypted); + +#ifdef FUZZ_VOICE + if((rand() % 10) < 2) { + log_info(category::connection, tr("Dropping voice packet")); + } else { + this->protocol_handler->send_packet(packet); + } +#elif defined(SHUFFLE_VOICE) + if(shuffle_cached_packet) { + this->protocol_handler->send_packet(packet); + this->protocol_handler->send_packet(std::exchange(shuffle_cached_packet, nullptr)); + } else { + shuffle_cached_packet = packet; + } +#else + this->protocol_handler->send_packet(std::shared_ptr(packet.release())); +#endif +} + +void ServerConnection::close_connection() { + lock_guard lock(this->disconnect_lock); + if(this->socket && this_thread::get_id() == this->socket->io_thread().get_id()) { + logger::debug(category::connection, tr("close_connection() called in IO thread. Closing connection within event loop!")); + if(!this->event_loop_execute_connection_close) { + this->event_loop_execute_connection_close = true; + this->event_condition.notify_one(); + } + return; + } + + this->event_loop_execute_connection_close = false; + if(this->socket) + this->socket->finalize(); + if(this->protocol_handler) + this->protocol_handler->do_close_connection(); + this->socket = nullptr; + this->call_disconnect_result.call(0, true); +} + +void ServerConnection::execute_tick() { + if(this->protocol_handler) + this->protocol_handler->execute_tick(); +} + +void ServerConnection::_execute_callback_commands() { + unique_ptr next_command; + v8::Local callback; + + while(true) { + { + lock_guard lock(this->pending_commands_lock); + if(this->pending_commands.empty()) + return; + next_command = move(this->pending_commands.front()); + this->pending_commands.pop_front(); + } + if(!next_command) + continue; + + if(callback.IsEmpty()) { + callback = Nan::Get(this->handle(), Nan::New("callback_command").ToLocalChecked()).ToLocalChecked().As(); + if(callback.IsEmpty()) { + logger::warn(category::connection, tr("Missing command callback! Dropping commands.")); + lock_guard lock(this->pending_commands_lock); + this->pending_commands.clear(); + return; + } + } + + v8::Local arguments[3]; + arguments[0] = Nan::New(next_command->command()).ToLocalChecked(); + + auto parameters = Nan::New((int) next_command->bulkCount()); + for(size_t index = 0; index < next_command->bulkCount(); index++) { + auto object = Nan::New(); + auto& bulk = next_command->operator[](index); + + for(const auto& key : bulk.keys()) + Nan::Set(object, Nan::New(key).ToLocalChecked(), Nan::New(bulk[key].string()).ToLocalChecked()); + + parameters->Set((uint32_t) index, object); + } + arguments[1] = parameters; + + + auto switched = Nan::New((int) next_command->parms().size()); + for(size_t index = 0; index < next_command->parms().size(); index++) { + auto& key = next_command->parms()[index]; + parameters->Set((uint32_t) index, Nan::New(key).ToLocalChecked()); + } + arguments[2] = switched; + + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 3, arguments); + } +} + +void ServerConnection::_execute_callback_voice() { + unique_ptr next_packet; + v8::Local callback; + + while(true) { + { + lock_guard lock(this->pending_voice_lock); + if(this->pending_voice.empty()) + return; + next_packet = move(this->pending_voice.front()); + this->pending_voice.pop_front(); + } + if(!next_packet) + continue; + + if(callback.IsEmpty()) { + auto _callback = Nan::Get(this->handle(), Nan::New("callback_voice_data").ToLocalChecked()).ToLocalChecked(); + if(_callback.IsEmpty() || _callback->IsUndefined()) { + logger::warn(category::audio, tr("Missing voice callback! Dropping packets!")); + lock_guard lock(this->pending_voice_lock); + this->pending_voice.clear(); + return; + } + callback = _callback.As(); + } + + v8::Local arguments[5]; + + v8::Local buffer = v8::ArrayBuffer::New( + Nan::GetCurrentContext()->GetIsolate(), + next_packet->voice_data.length() + ); + memcpy(buffer->GetContents().Data(), next_packet->voice_data.data_ptr(), next_packet->voice_data.length()); + arguments[0] = v8::Uint8Array::New(buffer, 0, buffer->ByteLength()); + arguments[1] = Nan::New(next_packet->client_id); + arguments[2] = Nan::New(next_packet->codec_id); + arguments[3] = Nan::New(next_packet->flag_head); + arguments[4] = Nan::New(next_packet->packet_id); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 5, arguments); + } +} + +void ServerConnection::_execute_callback_disconnect(const std::string &reason) { + auto callback = Nan::Get(this->handle(), Nan::New("callback_disconnect").ToLocalChecked()).ToLocalChecked().As(); + if(callback.IsEmpty()) { + cout << "Missing disconnect callback!" << endl; + return; + } + + v8::Local arguments[1]; + arguments[0] = Nan::New(reason).ToLocalChecked(); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, arguments); + +} + +NAN_METHOD(ServerConnection::_current_ping) { + auto connection = ObjectWrap::Unwrap(info.Holder()); + auto& phandler = connection->protocol_handler; + if(phandler) + info.GetReturnValue().Set((uint32_t) chrono::floor(phandler->current_ping()).count()); + else + info.GetReturnValue().Set(-1); +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/ServerConnection.h b/native/serverconnection/src/connection/ServerConnection.h new file mode 100644 index 0000000..69fded3 --- /dev/null +++ b/native/serverconnection/src/connection/ServerConnection.h @@ -0,0 +1,131 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ts { + class Command; +} + +namespace tc { + namespace connection { + namespace server_type { + enum value : uint8_t { + UNKNOWN, + TEASPEAK, + TEAMSPEAK + }; + } + + class UDPSocket; + class ProtocolHandler; + class VoiceConnection; + + class ErrorHandler { + public: + typedef int16_t error_id; + static constexpr error_id error_success = 0; + static constexpr error_id error_varianz = 5; + + + std::array error_messages; + error_id error_index = 0; + + std::string get_message(error_id); + error_id register_error(const std::string& /* message */); + }; + + class ServerConnection : public Nan::ObjectWrap { + friend class ProtocolHandler; + public: + static NAN_MODULE_INIT(Init); + + static NAN_METHOD(new_instance); + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + ServerConnection(); + ~ServerConnection() override; + + NAN_METHOD(connect); + NAN_METHOD(connected); + NAN_METHOD(disconnect); + + NAN_METHOD(error_message); + NAN_METHOD(send_command); + NAN_METHOD(send_voice_data); + void send_voice_data(const void* /* buffer */, size_t /* buffer length */, uint8_t /* codec */, bool /* head */); + + NAN_METHOD(send_voice_data_raw); + + void initialize(); + void finalize(); + + void close_connection(); /* directly closes connection without notify etc */ + std::shared_ptr get_socket() { return this->socket; } + private: + struct VoicePacket { + pipes::buffer voice_data; + uint16_t client_id; + uint16_t packet_id; + uint8_t codec_id; + bool flag_head; + }; + + static NAN_METHOD(_connect); + static NAN_METHOD(_connected); + static NAN_METHOD(_disconnect); + static NAN_METHOD(_send_command); + static NAN_METHOD(_send_voice_data); + static NAN_METHOD(_send_voice_data_raw); + static NAN_METHOD(_error_message); + static NAN_METHOD(_current_ping); + + std::unique_ptr callback_connect; + std::unique_ptr callback_disconnect; + Nan::callback_t call_connect_result; + Nan::callback_t call_disconnect_result; + Nan::callback_t<> execute_pending_commands; + Nan::callback_t<> execute_pending_voice; + Nan::callback_t execute_callback_disconnect; + + ErrorHandler errors; + std::shared_ptr socket; + std::unique_ptr protocol_handler; + std::recursive_timed_mutex disconnect_lock; + + std::thread event_thread; + std::mutex event_lock; + std::condition_variable event_condition; + bool event_loop_exit = false; /* set to true if we want to exit */ + void event_loop(); + + bool event_loop_execute_connection_close = false; + + std::chrono::system_clock::time_point next_tick; + std::chrono::system_clock::time_point next_resend; + void execute_tick(); + + void schedule_resend(const std::chrono::system_clock::time_point& /* timestamp */); + + std::mutex pending_commands_lock; + std::deque> pending_commands; + void _execute_callback_commands(); + + std::mutex pending_voice_lock; + std::deque> pending_voice; + void _execute_callback_voice(); + uint16_t voice_packet_id = 0; + + void _execute_callback_disconnect(const std::string&); + + std::shared_ptr voice_connection; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/Socket.cpp b/native/serverconnection/src/connection/Socket.cpp new file mode 100644 index 0000000..558c200 --- /dev/null +++ b/native/serverconnection/src/connection/Socket.cpp @@ -0,0 +1,180 @@ +#include "Socket.h" +#include "../logger.h" +#include +#include +#include +#include + +#ifdef WIN32 + #include + typedef int socklen_t; +#else + #include + #include +#endif + +using namespace std; +using namespace tc::connection; + +UDPSocket::UDPSocket(const sockaddr_storage &address) { + memcpy(&this->_remote_address, &address, sizeof(sockaddr_storage)); +} + +UDPSocket::~UDPSocket() { + this->finalize(); +} + +bool UDPSocket::initialize() { + if(this->file_descriptor > 0) + return false; + + this->file_descriptor = socket(this->_remote_address.ss_family, SOCK_DGRAM, 0); + if(this->file_descriptor < 2) { + this->file_descriptor = 0; + return false; + } + + /* + * TODO: Make configurable + */ + //uint8_t value = IPTOS_DSCP_EF; + //if(setsockopt(this->file_descriptor, IPPROTO_IP, IP_TOS, &value, sizeof(value)) < 0) + // log_warn(category::connection, "Failed to set TOS high priority on socket"); + + this->io_base = event_base_new(); + if(!this->io_base) { /* may too many file descriptors already open */ + this->finalize(); + return false; + } + this->event_read = event_new(this->io_base, this->file_descriptor, EV_READ | EV_PERSIST, &UDPSocket::_callback_read, this); + this->event_write = event_new(this->io_base, this->file_descriptor, EV_WRITE, &UDPSocket::_callback_write, this); + event_add(this->event_read, nullptr); + + this->_io_thread = thread(&UDPSocket::_io_execute, this); +#ifdef WIN32 + //TODO set thread name +#else + auto handle = this->_io_thread.native_handle(); + pthread_setname_np(handle, "UDPSocket loop"); +#endif + return true; +} + +void UDPSocket::finalize() { + if(this->file_descriptor == 0) + return; + + unique_lock lock(this->io_lock); + auto event_read = this->event_read, event_write = this->event_write; + auto io_base = this->io_base; + this->io_base = nullptr; + this->event_read = nullptr; + this->event_write = nullptr; + lock.unlock(); + + assert(this_thread::get_id() != this->_io_thread.get_id()); + if(event_read) + event_del_block(event_read); + if(event_write) + event_del_block(event_write); + + if(event_write) + event_del(event_write); + if(event_read) + event_del(event_read); + + if(io_base) { + timeval seconds{1, 0}; + event_base_loopexit(io_base, &seconds); + event_base_loopexit(io_base, nullptr); + } + + if(this->_io_thread.joinable()) + this->_io_thread.join(); + + if(io_base) + event_base_free(io_base); + +#ifdef WIN32 + if(::closesocket(this->file_descriptor) != 0) { +#else + if(::close(this->file_descriptor) != 0) { +#endif + if(errno != EBADF) + logger::warn(category::socket, tr("Failed to close file descriptor ({}/{})"), to_string(errno), strerror(errno)); + } + this->file_descriptor = 0; +} + +void UDPSocket::_callback_write(evutil_socket_t fd, short, void *_ptr_socket) { + ((UDPSocket*) _ptr_socket)->callback_write(fd); +} + +void UDPSocket::_callback_read(evutil_socket_t fd, short, void *_ptr_socket) { + ((UDPSocket*) _ptr_socket)->callback_read(fd); +} + +void UDPSocket::_io_execute(void *_ptr_socket) { + ((UDPSocket*) _ptr_socket)->io_execute(); +} + +void UDPSocket::io_execute() { + while(this->io_base) { + event_base_loop(this->io_base, 0); + } +} +void UDPSocket::callback_read(evutil_socket_t fd) { + sockaddr source_address{}; + socklen_t source_address_length = sizeof(sockaddr); + + ssize_t buffer_length = 1600; /* IPv6 MTU is ~1.5k */ + char buffer[1600]; + + buffer_length = recvfrom(fd, (char*) buffer, buffer_length, 0, &source_address, &source_address_length); + if(buffer_length <= 0) { + if(errno == EAGAIN) + return; + + logger::warn(category::socket, tr("Failed to receive data: {}/{}"), errno, strerror(errno)); + return; /* this should never happen! */ + } + + if(this->on_data) + this->on_data(pipes::buffer_view{buffer, (size_t) buffer_length}); +} + +void UDPSocket::callback_write(evutil_socket_t fd) { + unique_lock lock(this->io_lock); + if(this->write_queue.empty()) + return; + + auto buffer = this->write_queue.front(); + this->write_queue.pop_front(); + lock.unlock(); + + auto written = sendto(fd, buffer.data_ptr(), buffer.length(), 0, (sockaddr*) &this->_remote_address, sizeof(this->_remote_address)); + if(written != buffer.length()) { + if(errno == EAGAIN) { + lock.lock(); + this->write_queue.push_front(buffer); + if(this->event_write) + event_add(this->event_write, nullptr); + return; + } + + return; /* this should never happen! */ + } + + lock.lock(); + if(!this->write_queue.empty() && this->event_write) + event_add(this->event_write, nullptr); +} + +void UDPSocket::send_message(const pipes::buffer_view &buffer) { + auto buf = buffer.own_buffer(); + + unique_lock lock(this->io_lock); + this->write_queue.push_back(buf); + if(this->event_write) + event_add(this->event_write, nullptr); +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/Socket.h b/native/serverconnection/src/connection/Socket.h new file mode 100644 index 0000000..605cb0b --- /dev/null +++ b/native/serverconnection/src/connection/Socket.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef WIN32 + #include +#else + #include +#endif + +namespace tc { + namespace connection { + class UDPSocket { + public: + UDPSocket(const sockaddr_storage& /* target */); + ~UDPSocket(); + + const sockaddr_storage& remote_address() { return this->_remote_address; } + + bool initialize(); + void finalize(); + + void send_message(const pipes::buffer_view& /* message */); + + std::function on_data; + + const std::thread& io_thread() { return this->_io_thread; } + private: + static void _io_execute(void *_ptr_socket); + static void _callback_read(evutil_socket_t, short, void*); + static void _callback_write(evutil_socket_t, short, void*); + + void io_execute(); + void callback_read(evutil_socket_t); + void callback_write(evutil_socket_t); + + sockaddr_storage _remote_address; + + int file_descriptor = 0; + + std::recursive_mutex io_lock; + std::thread _io_thread; + event_base* io_base = nullptr; + + event* event_read = nullptr; + event* event_write = nullptr; + + std::deque write_queue; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/audio/AudioEventLoop.cpp b/native/serverconnection/src/connection/audio/AudioEventLoop.cpp new file mode 100644 index 0000000..86c1666 --- /dev/null +++ b/native/serverconnection/src/connection/audio/AudioEventLoop.cpp @@ -0,0 +1,27 @@ +// +// Created by wolverindev on 19.06.19. +// + +#include "AudioEventLoop.h" +using namespace tc; + +event::EventExecutor* audio::decode_event_loop = nullptr; +event::EventExecutor* audio::encode_event_loop = nullptr; + +void audio::init_event_loops() { + audio::shutdown_event_loops(); /* just to ensure */ + + audio::decode_event_loop = new event::EventExecutor("a en/decode "); + audio::encode_event_loop = audio::decode_event_loop; + + audio::decode_event_loop->initialize(2); +} + +void audio::shutdown_event_loops() { + if(audio::decode_event_loop) { + delete audio::decode_event_loop; + audio::decode_event_loop = nullptr; + } + audio::encode_event_loop = nullptr; + +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/audio/AudioEventLoop.h b/native/serverconnection/src/connection/audio/AudioEventLoop.h new file mode 100644 index 0000000..83ae434 --- /dev/null +++ b/native/serverconnection/src/connection/audio/AudioEventLoop.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../../EventLoop.h" + +namespace tc { + namespace audio { + extern event::EventExecutor* encode_event_loop; + extern event::EventExecutor* decode_event_loop; + + extern void init_event_loops(); + extern void shutdown_event_loops(); + } +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/audio/AudioSender.cpp b/native/serverconnection/src/connection/audio/AudioSender.cpp new file mode 100644 index 0000000..1ba2230 --- /dev/null +++ b/native/serverconnection/src/connection/audio/AudioSender.cpp @@ -0,0 +1,224 @@ +#include "AudioSender.h" +#include "VoiceConnection.h" +#include "../ServerConnection.h" +#include "../../logger.h" +#include "AudioEventLoop.h" +#include "../../audio/AudioMerger.h" + +using namespace std; +using namespace tc; +using namespace tc::audio; +using namespace tc::audio::codec; +using namespace tc::connection; + +VoiceSender::VoiceSender(tc::connection::VoiceConnection *handle) : handle(handle) {} + +VoiceSender::~VoiceSender() { + audio::encode_event_loop->cancel(static_pointer_cast(this->_ref.lock())); + this->clear_buffer(); /* buffer might be accessed within encode_raw_frame, but this could not be trigered while this will be deallocated! */ +} + +bool VoiceSender::initialize_codec(std::string& error, connection::codec::value codec, size_t channels, size_t rate, bool reset_encoder) { + auto& data = this->codec[codec]; + bool new_allocated = !data; + if(new_allocated) { + data = make_unique(); + data->packet_counter = 0; + data->last_packet = chrono::system_clock::now(); + } + + auto info = codec::get_info(codec); + if(!info || !info->supported) { + if(new_allocated) + log_error(category::voice_connection, tr("Tried to send voice packet but we dont support the current codec ({})"), codec); + return false; + } + + if(!data->converter) { + data->converter = info->new_converter(error); + if(!data->converter) + return false; + } else if(reset_encoder) { + data->converter->reset_encoder(); + } + + if(!data->resampler || data->resampler->input_rate() != rate) + data->resampler = make_shared(rate, data->converter->sample_rate(), data->converter->channels()); + + if(!data->resampler->valid()) { + error = "resampler is invalid"; + return false; + } + + return true; +} + +void VoiceSender::set_voice_send_enabled(bool flag) { + this->voice_send_enabled = flag; +} + +void VoiceSender::send_data(const void *data, size_t samples, size_t rate, size_t channels) { + unique_lock lock(this->_execute_lock); + if(!this->handle) { + log_warn(category::voice_connection, tr("Dropping raw audio frame because of an invalid handle.")); + return; + } + lock.unlock(); + + if(!this->voice_send_enabled) { + log_warn(category::voice_connection, tr("Dropping raw audio frame because voice sending has been disabled!")); + return; + } + + auto frame = make_unique(); + frame->sample_rate = rate; + frame->channels = channels; + frame->buffer = pipes::buffer{(void*) data, samples * channels * 4}; + frame->timestamp = chrono::system_clock::now(); + + { + lock_guard buffer_lock(this->raw_audio_buffer_lock); + this->raw_audio_buffers.push_back(move(frame)); + } + + audio::encode_event_loop->schedule(static_pointer_cast(this->_ref.lock())); +} + +void VoiceSender::send_stop() { + unique_lock lock(this->_execute_lock); + if(!this->handle) { + log_warn(category::voice_connection, tr("Dropping audio end frame because of an invalid handle.")); + return; + } + lock.unlock(); + + + auto frame = make_unique(); + frame->sample_rate = 0; + frame->channels = 0; + frame->buffer = pipes::buffer{nullptr, 0}; + frame->timestamp = chrono::system_clock::now(); + + { + lock_guard buffer_lock(this->raw_audio_buffer_lock); + this->raw_audio_buffers.push_back(move(frame)); + } + + audio::encode_event_loop->schedule(static_pointer_cast(this->_ref.lock())); +} + +void VoiceSender::finalize() { + lock_guard lock(this->_execute_lock); + this->handle = nullptr; +} + +void VoiceSender::event_execute(const std::chrono::system_clock::time_point &point) { + static auto max_time = chrono::milliseconds(10); + + bool reschedule = false; + auto now = chrono::system_clock::now(); + while(true) { + unique_lock buffer_lock(this->raw_audio_buffer_lock); + if(this->raw_audio_buffers.empty()) + break; + + if(chrono::system_clock::now() - now > max_time) { + reschedule = true; + break; + } + + auto entry = move(this->raw_audio_buffers.front()); + this->raw_audio_buffers.pop_front(); + buffer_lock.unlock(); + + //TODO: Drop too old buffers! + this->encode_raw_frame(entry); + } + + if(reschedule) { + log_warn(category::voice_connection, tr("Audio data decode will take longer than {} us. Enqueueing for later"), chrono::duration_cast(max_time).count()); + audio::decode_event_loop->schedule(static_pointer_cast(this->_ref.lock())); + } +} + +void VoiceSender::encode_raw_frame(const std::unique_ptr &frame) { + auto codec = this->_current_codec; + auto& codec_data = this->codec[codec]; + + bool flag_head = true, flag_reset = true; + if(codec_data) { + if(codec_data->last_packet + chrono::seconds(1) < frame->timestamp) + codec_data->packet_counter = 0; + + flag_head = codec_data->packet_counter < 5; + flag_reset = codec_data->packet_counter == 0; + + codec_data->packet_counter++; + codec_data->last_packet = frame->timestamp; + } + + if(frame->channels == 0 || frame->sample_rate == 0 || frame->buffer.empty()) { + lock_guard lock(this->_execute_lock); + if(!this->handle) { + log_warn(category::voice_connection, tr("Dropping audio end because of an invalid handle.")); + return; + } + + if(codec_data) + codec_data->packet_counter = 0; + auto server = this->handle->handle(); + server->send_voice_data(this->_buffer, 0, codec, flag_head); + return; + } + + string error; + if(flag_reset) { + log_trace(category::voice_connection, tr("Resetting encoder for voice sender")); + } + if(!this->initialize_codec(error, codec, frame->channels, frame->sample_rate, flag_reset)) { + log_error(category::voice_connection, tr("Failed to initialize codec: {}"), error); + return; + } + + auto merged_channel_byte_size = codec_data->converter->channels() * (frame->buffer.length() / frame->channels); + auto estimated_resampled_byte_size = codec_data->resampler->estimated_output_size(merged_channel_byte_size); + this->ensure_buffer(max(estimated_resampled_byte_size, merged_channel_byte_size)); + + auto codec_channels = codec_data->converter->channels(); + if(!audio::merge::merge_channels_interleaved(this->_buffer, codec_channels, frame->buffer.data_ptr(), frame->channels, frame->buffer.length() / frame->channels / 4)) { + log_warn(category::voice_connection, tr("Failed to merge channels to output stream channel count! Dropping local voice packet")); + return; + } + + auto resampled_samples = codec_data->resampler->process(this->_buffer, this->_buffer, merged_channel_byte_size / codec_channels / 4); + if(resampled_samples <= 0) { + log_error(category::voice_connection, tr("Resampler returned {}"), resampled_samples); + return; + } + + if(resampled_samples * codec_channels * 4 != codec_data->converter->bytes_per_frame()) { + log_error(category::voice_connection, + tr("Could not encode audio frame. Frame length is not equal to code frame length! Codec: {}, Packet: {}"), + codec_data->converter->bytes_per_frame(), resampled_samples * codec_channels * 4 + ); + return; + } + + char _packet_buffer[512]; + auto encoded_bytes = codec_data->converter->encode(error, this->_buffer, _packet_buffer, 512); + if(encoded_bytes <= 0) { + log_error(category::voice_connection, tr("Failed to encode voice: {}"), error); + return; + } + + { + lock_guard lock(this->_execute_lock); + if(!this->handle) { + log_warn(category::voice_connection, tr("Dropping audio frame because of an invalid handle.")); + return; + } + + auto server = this->handle->handle(); + server->send_voice_data(_packet_buffer, encoded_bytes, codec, flag_head); + } +} diff --git a/native/serverconnection/src/connection/audio/AudioSender.h b/native/serverconnection/src/connection/audio/AudioSender.h new file mode 100644 index 0000000..75e1391 --- /dev/null +++ b/native/serverconnection/src/connection/audio/AudioSender.h @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include "VoiceClient.h" + +namespace tc { + namespace audio { + namespace codec { + class Converter; + } + + class AudioResampler; + class AudioOutputSource; + } + + namespace connection { + class VoiceConnection; + class VoiceSender : private event::EventEntry { + template + friend inline std::shared_ptr<_Tp> std::static_pointer_cast(const std::shared_ptr<_Up>& __r) noexcept; + friend class VoiceConnection; + public: + VoiceSender(VoiceConnection*); + virtual ~VoiceSender(); + + codec::value get_codec() { return this->_current_codec; } + void set_codec(codec::value value) { this->_current_codec = value; } + + + void finalize(); + void send_data(const void* /* buffer */, size_t /* samples */, size_t /* sample rate */, size_t /* channels */); + void send_stop(); + + void set_voice_send_enabled(bool /* flag */); + private: + std::weak_ptr _ref; + VoiceConnection* handle; + + struct AudioCodec { + size_t packet_counter = 0; + std::chrono::system_clock::time_point last_packet; + + std::shared_ptr converter; + std::shared_ptr resampler; + }; + std::array, codec::MAX + 1> codec{nullptr}; + + bool initialize_codec(std::string&, codec::value /* codec */, size_t /* channels */, size_t /* source sample rate */, bool /* reset decoder */); + + codec::value _current_codec = codec::OPUS_VOICE; + + std::mutex _execute_lock; + + void* _buffer = nullptr; + size_t _buffer_size = 0; + void clear_buffer() { + if(this->_buffer) + ::free(this->_buffer); + this->_buffer = nullptr; + this->_buffer_size = 0; + } + + void ensure_buffer(size_t length) { + if(!this->_buffer || this->_buffer_size < length) { + if(this->_buffer) + ::free(this->_buffer); + this->_buffer = malloc(length); + this->_buffer_size = length; + } + } + + struct AudioFrame { + pipes::buffer buffer; + size_t sample_rate; + size_t channels; + + std::chrono::system_clock::time_point timestamp; + }; + + std::mutex raw_audio_buffer_lock; + std::deque> raw_audio_buffers; + + bool voice_send_enabled = false; + + void encode_raw_frame(const std::unique_ptr&); + void event_execute(const std::chrono::system_clock::time_point &point) override; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/audio/VoiceClient.cpp b/native/serverconnection/src/connection/audio/VoiceClient.cpp new file mode 100644 index 0000000..7a47aec --- /dev/null +++ b/native/serverconnection/src/connection/audio/VoiceClient.cpp @@ -0,0 +1,569 @@ +#include "VoiceClient.h" +#include "../../audio/AudioOutput.h" +#include "../../audio/codec/Converter.h" +#include "../../audio/codec/OpusConverter.h" +#include "../../audio/AudioMerger.h" +#include "../../audio/js/AudioOutputStream.h" +#include "AudioEventLoop.h" +#include "../../logger.h" + +using namespace std; +using namespace tc; +using namespace tc::audio::codec; +using namespace tc::connection; + +extern tc::audio::AudioOutput* global_audio_output; + +#define DEBUG_PREMATURE_PACKETS + +#ifdef WIN32 + #define _field_(name, value) value +#else + #define _field_(name, value) .name = value +#endif +const codec::condec_info codec::info[6] = { + { + _field_(supported, false), + _field_(name, "speex_narrowband"), + _field_(new_converter, nullptr) + }, + { + _field_(supported, false), + _field_(name, "speex_wideband"), + _field_(new_converter, nullptr) + }, + { + _field_(supported, false), + _field_(name, "speex_ultra_wideband"), + _field_(new_converter, nullptr) + }, + { + _field_(supported, false), + _field_(name, "celt_mono"), + _field_(new_converter, nullptr) + }, + { + _field_(supported, true), + _field_(name, "opus_voice"), + _field_(new_converter, [](string& error) -> shared_ptr { + auto result = make_shared(1, 48000, 960); + if(!result->initialize(error, OPUS_APPLICATION_VOIP)) + return nullptr; + return dynamic_pointer_cast(result); + }) + }, + { + _field_(supported, true), + _field_(name, "opus_music"), + _field_(new_converter, [](string& error) -> shared_ptr { + auto result = make_shared(2, 48000, 960); + if(!result->initialize(error, OPUS_APPLICATION_AUDIO)) + return nullptr; + return dynamic_pointer_cast(result); + }) + } +}; + +void VoiceClientWrap::do_wrap(const v8::Local &object) { + this->Wrap(object); + + auto handle = this->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + Nan::Set(object, Nan::New("client_id").ToLocalChecked(), Nan::New(handle->client_id())); + handle->on_state_changed = [&]{ this->call_state_changed(); }; + + this->call_state_changed = Nan::async_callback([&]{ + Nan::HandleScope scope; + this->_call_state_changed(); + }); +} + +void VoiceClientWrap::_call_state_changed() { + auto handle = this->_handle.lock(); + if(!handle) { + log_warn(category::voice_connection, tr("State changed on invalid handle!")); + return; + } + + auto state = handle->state(); + auto call_playback_callback = state == VoiceClient::state::playing && !this->_currently_playing; + auto call_stopped_callback = state == VoiceClient::state::stopped && this->_currently_playing; + + if(state == VoiceClient::state::stopped) + this->_currently_playing = false; + if(state == VoiceClient::state::playing) + this->_currently_playing = true; + + if(call_playback_callback) { + auto callback = Nan::Get(this->handle(), Nan::New("callback_playback").ToLocalChecked()).ToLocalChecked(); + if(callback->IsFunction()) + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); + } + if(call_stopped_callback) { + auto callback = Nan::Get(this->handle(), Nan::New("callback_stopped").ToLocalChecked()).ToLocalChecked(); + if(callback->IsFunction()) + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); + } + + auto callback = Nan::Get(this->handle(), Nan::New("callback_state_changed").ToLocalChecked()).ToLocalChecked(); + if(callback->IsFunction()) { + v8::Local argv[1] = { + Nan::New(state) + }; + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, argv); + } +} + +NAN_MODULE_INIT(VoiceClientWrap::Init) { + auto klass = Nan::New(VoiceClientWrap::NewInstance); + klass->SetClassName(Nan::New("VoiceConnection").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "get_state", VoiceClientWrap::_get_state); + Nan::SetPrototypeMethod(klass, "get_volume", VoiceClientWrap::_get_volume); + Nan::SetPrototypeMethod(klass, "set_volume", VoiceClientWrap::_set_volume); + Nan::SetPrototypeMethod(klass, "abort_replay", VoiceClientWrap::_abort_replay); + Nan::SetPrototypeMethod(klass, "get_stream", VoiceClientWrap::_get_stream); + + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(VoiceClientWrap::NewInstance) { + if(!info.IsConstructCall()) + Nan::ThrowError("invalid invoke!"); +} + +NAN_METHOD(VoiceClientWrap::_get_volume) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + info.GetReturnValue().Set(handle->get_volume()); +} + +NAN_METHOD(VoiceClientWrap::_set_volume) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("Invalid arguments"); + return; + } + + handle->set_volume(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); +} +NAN_METHOD(VoiceClientWrap::_abort_replay) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + handle->cancel_replay(); +} + +NAN_METHOD(VoiceClientWrap::_get_state) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + info.GetReturnValue().Set(handle->state()); +} + + +NAN_METHOD(VoiceClientWrap::_get_stream) { + auto client = ObjectWrap::Unwrap(info.Holder()); + + auto handle = client->_handle.lock(); + if(!handle) { + Nan::ThrowError("weak handle"); + return; + } + + auto wrapper = new audio::AudioOutputStreamWrapper(handle->output_stream(), false); + auto object = Nan::NewInstance(Nan::New(audio::AudioOutputStreamWrapper::constructor()), 0, nullptr).ToLocalChecked(); + wrapper->do_wrap(object); + info.GetReturnValue().Set(object); +} + +VoiceClientWrap::VoiceClientWrap(const std::shared_ptr& client) : _handle(client) { } + +VoiceClientWrap::~VoiceClientWrap() {} + +VoiceClient::VoiceClient(const std::shared_ptr&, uint16_t client_id) : _client_id(client_id) { + this->output_source = global_audio_output->create_source(); + this->output_source->overflow_strategy = audio::overflow_strategy::ignore; + this->output_source->max_latency = (size_t) ceil(this->output_source->sample_rate * 1); + this->output_source->min_buffer = (size_t) ceil(this->output_source->sample_rate * 0.04); + + this->output_source->on_underflow = [&]{ + if(this->_state == state::stopping) + this->set_state(state::stopped); + else if(this->_state != state::stopped) { + if(this->_last_received_packet + chrono::seconds(1) < chrono::system_clock::now()) { + this->set_state(state::stopped); + log_warn(category::audio, tr("Client {} has a audio buffer underflow and not received any data for one second. Stopping replay."), this->_client_id); + } else { + if(this->_state != state::buffering) { + log_warn(category::audio, tr("Client {} has a audio buffer underflow. Buffer again and try to replay prematured packets."), this->_client_id); + this->set_state(state::buffering); + } + + play_premature_packets = true; /* try to replay any premature packets because we assume that the other packets got lost */ + audio::decode_event_loop->schedule(static_pointer_cast(this->ref())); + } + } + + return false; + }; + this->output_source->on_overflow = [&](size_t count){ + log_warn(category::audio, tr("Client {} has a audio buffer overflow of {}."), this->_client_id, count); + }; +} + +VoiceClient::~VoiceClient() { + if(v8::Isolate::GetCurrent()) + this->finalize_js_object(); + else { + assert(this->_js_handle.IsEmpty()); + } + + this->output_source->on_underflow = nullptr; /* to ensure */ + global_audio_output->delete_source(this->output_source); +} + +void VoiceClient::initialize_js_object() { + if(!this->_js_handle.IsEmpty()) + return; + + auto object_wrap = new VoiceClientWrap(this->ref()); + auto object = Nan::NewInstance(Nan::New(VoiceClientWrap::constructor()), 0, nullptr).ToLocalChecked(); + Nan::TryCatch tc; + object_wrap->do_wrap(object); + if(tc.HasCaught()) { + tc.ReThrow(); + return; + } + + this->_js_handle.Reset(Nan::GetCurrentContext()->GetIsolate(), object); +} + +void VoiceClient::finalize_js_object() { + this->_js_handle.Reset(); +} + +#define target_buffer_length 16384 +void VoiceClient::process_packet(uint16_t packet_id, const pipes::buffer_view& buffer, codec::value codec, bool head) { + if(this->_volume == 0) + return; + + if(codec < 0 || codec > this->codec.size()) { + log_warn(category::voice_connection, tr("Received voice packet from client {} with unknown codec ({})"), this->_client_id, codec); + return; + } + + auto encoded_buffer = make_unique(); + encoded_buffer->packet_id = packet_id; + encoded_buffer->codec = codec; + encoded_buffer->receive_timestamp = chrono::system_clock::now(); + encoded_buffer->buffer = buffer.own_buffer(); + encoded_buffer->head = head; + + this->_last_received_packet = encoded_buffer->receive_timestamp; + { + lock_guard lock(this->audio_decode_queue_lock); + this->audio_decode_queue.push_back(move(encoded_buffer)); + } + + audio::decode_event_loop->schedule(static_pointer_cast(this->ref())); +} + +void VoiceClient::cancel_replay() { + log_trace(category::voice_connection, tr("Cancel replay for client {}"), this->_client_id); + this->output_source->clear(); + this->set_state(state::stopped); +} + +void VoiceClient::event_execute(const std::chrono::system_clock::time_point &scheduled) { + static auto max_time = chrono::milliseconds(10); + + bool reschedule = false; + auto now = chrono::system_clock::now(); + while(true) { + unique_lock buffer_lock(this->audio_decode_queue_lock); + if(this->play_premature_packets) { + this->play_premature_packets = false; + + for(auto& codec_data : this->codec) { + if(!codec_data) continue; + + if(!codec_data->premature_packets.empty()) { + size_t play_count = 0; + while(!codec_data->premature_packets.empty()) { + auto& packet = codec_data->premature_packets.front(); + + //Test if we're able to replay stuff again + if((uint16_t) (codec_data->last_packet_id + 1) < packet.packet_id && play_count > 0) //Only check for the order if we replayed one already + break; //Nothing new + + this->output_source->enqueue_samples(packet.buffer); + codec_data->last_packet_id = packet.packet_id; + codec_data->premature_packets.pop_front(); + play_count++; + } + +#ifdef DEBUG_PREMATURE_PACKETS + if(play_count > 0) + log_debug(category::audio, tr("Replayed (buffer underflow) {} premature packets for client {}"), play_count, this->_client_id); +#endif + break; + } + } + } + + if(this->audio_decode_queue.empty()) + break; + + if(chrono::system_clock::now() - now > max_time) { + reschedule = true; + break; + } + + auto entry = move(this->audio_decode_queue.front()); + this->audio_decode_queue.pop_front(); + buffer_lock.unlock(); + + //TODO: Drop too old buffers! + this->process_encoded_buffer(entry); + } + + if(audio_decode_event_dropped.exchange(false) && !reschedule) { + //Is not really a warning, it happens all the time and isn't really an issue + //log_warn(category::voice_connection, tr("Dropped auto enqueue event execution for client {}. No reschedulling planned, hopefully we processed all buffers."), this->_client_id); + } + + if(reschedule) { + log_warn(category::voice_connection, tr("Audio data decode will take longer than {} us. Enqueueing for later"), chrono::duration_cast(max_time).count()); + audio::decode_event_loop->schedule(static_pointer_cast(this->ref())); + } +} + +#define MAX_LOST_PACKETS (6) +//Note: This function must be executed single threaded +void VoiceClient::process_encoded_buffer(const std::unique_ptr &buffer) { + string error; + + auto& codec_data = this->codec[buffer->codec]; + + if(!codec_data) { + auto info = codec::get_info(buffer->codec); + if(!info || !info->supported) { + log_warn(category::voice_connection, tr("Received voice packet from client {}, but we dont support it ({})"), this->_client_id, buffer->codec); + return; + } + + auto instance = make_unique(); + instance->successfully_initialized = false; + + instance->last_packet_id = (uint16_t) (buffer->packet_id - 1); /* could be 0xFFFF */ + instance->converter = info->new_converter(error); + if(!instance->converter) { + codec_data = move(instance); + + log_warn(category::voice_connection, tr("Failed to initialize new codec {} for client {}: {}"), buffer->codec, this->_client_id, error); + return; + } + + instance->resampler = make_shared(instance->converter->sample_rate(), this->output_source->sample_rate, instance->converter->channels()); + if(!instance->resampler->valid()) { + codec_data = move(instance); + + log_warn(category::voice_connection, tr("Failed to initialize new codec resampler {} for client {}"), buffer->codec, this->_client_id); + return; + } + instance->successfully_initialized = true; + codec_data = move(instance); + } else if(!codec_data->successfully_initialized) { + return; /* already failed ignore that stuff */ + } + + uint16_t diff; + bool premature = false; + + if(codec_data->last_packet_timestamp + chrono::seconds(1) < buffer->receive_timestamp || this->_state >= state::stopping) { + diff = 0xFFFF; + } else { + if(codec_data->last_packet_id > buffer->packet_id) { + auto local_index = (uint16_t) (codec_data->last_packet_id + MAX_LOST_PACKETS); + if(local_index < buffer->packet_id) + diff = 0xFF; /* we got in a new generation */ + else { + log_warn(category::audio, + tr("Received voice packet for client {} with is older than the last we received (Current index: {}, Packet index: {}). Dropping packet."), + this->_client_id, buffer->packet_id, codec_data->last_packet_id + ); + return; + } + } else { + diff = buffer->packet_id - codec_data->last_packet_id; + } + } + + const auto old_packet_id = codec_data->last_packet_id; + codec_data->last_packet_timestamp = buffer->receive_timestamp; + + if(buffer->buffer.empty()) { + /* lets playback the last samples and we're done */ + this->set_state(state::stopping); + + /* enqueue all premature packets (list should be already ordered!) */ + { + unique_lock buffer_lock(this->audio_decode_queue_lock); + for(const auto& packet : codec_data->premature_packets) + this->output_source->enqueue_samples(packet.buffer); + codec_data->premature_packets.clear(); + } + + log_trace(category::voice_connection, tr("Stopping replay for client {}. Empty buffer!"), this->_client_id); + return; + } + + if(diff == 0) { + //Duplicated packets + log_warn(category::audio, tr("Received voice packet with the same ID then the last one. Dropping packet.")); + return; + } else + diff--; /* because the diff is normally 1 (ofc) */ + + if(diff <= MAX_LOST_PACKETS) { + if(diff > 0) { + /* lets first handle packet as "lost", even thou we're enqueueing it as premature */ + //auto status = codec_data->converter->decode_lost(error, diff); + //if(status < 0) + // log_warn(category::voice_connection, tr("Failed to decode (skip) dropped packets. Return code {} => {}"), status, error); + premature = !buffer->head && this->state() != state::stopped; + + log_debug(category::voice_connection, + tr("Client {} dropped one or more audio packets. Old packet id: {}, New packet id: {}, Diff: {}. Head: {}. Flagging chunk as premature: {}"), + this->_client_id, old_packet_id, buffer->packet_id, diff, buffer->head, premature); + } + } else { + log_debug(category::voice_connection, tr("Client {} resetted decoder. Old packet id: {}, New packet id: {}, diff: {}"), this->_client_id, old_packet_id, buffer->packet_id, diff); + codec_data->converter->reset_decoder(); + if(!codec_data->converter) { + log_warn(category::voice_connection, tr("Failed to reset codec decoder {} for client {}: {}"), buffer->codec, this->_client_id, error); + return; + } + } + if(!premature) + codec_data->last_packet_id = buffer->packet_id; + + char target_buffer[target_buffer_length]; + if(target_buffer_length < codec_data->converter->expected_decoded_length(buffer->buffer.data_ptr(), buffer->buffer.length())) { + log_warn(category::voice_connection, tr("Failed to decode audio data. Target buffer is smaller then expected bytes ({} < {})"), target_buffer_length, codec_data->converter->expected_decoded_length(buffer->buffer.data_ptr(), buffer->buffer.length())); + return; + } + auto samples = codec_data->converter->decode(error, buffer->buffer.data_ptr(), buffer->buffer.length(), target_buffer); + if(samples < 0) { + log_warn(category::voice_connection, tr("Failed to decode audio data: {}"), error); + return; + } + if(target_buffer_length < codec_data->resampler->estimated_output_size(samples) * codec_data->resampler->channels() * 4) { + log_warn(category::voice_connection, tr("Failed to resample audio data. Target buffer is smaller then expected bytes ({} < {})"), target_buffer_length, (codec_data->resampler->estimated_output_size(samples) * codec_data->resampler->channels() * 4)); + return; + } + + auto resampled_samples = codec_data->resampler->process(target_buffer, target_buffer, samples); + if(resampled_samples <= 0) { + log_warn(category::voice_connection, tr("Failed to resample audio data. Resampler resulted in {}"), resampled_samples); + return; + } + + if(!audio::merge::merge_channels_interleaved(target_buffer, this->output_source->channel_count, target_buffer, codec_data->resampler->channels(), resampled_samples)) { + log_warn(category::voice_connection, tr("Failed to merge channels to output stream channel count!")); + return; + } + + if(this->_volume != 1) { + auto buf = (float*) target_buffer; + auto count = this->output_source->channel_count * resampled_samples; + while(count-- > 0) + *(buf++) *= this->_volume; + } + + if(premature) { + auto audio_buffer = audio::SampleBuffer::allocate((uint8_t) this->output_source->channel_count, (uint16_t) resampled_samples); + + audio_buffer->sample_index = 0; + memcpy(audio_buffer->sample_data, target_buffer, this->output_source->channel_count * resampled_samples * 4); + + { + unique_lock buffer_lock(this->audio_decode_queue_lock); + auto it = codec_data->premature_packets.begin(); + for(; it != codec_data->premature_packets.end(); it++) { + if(it->packet_id > buffer->packet_id) { + break; /* it is set to the right position */ + } + } + codec_data->premature_packets.insert(it, { + buffer->packet_id, + move(audio_buffer) + }); + std::stable_sort(codec_data->premature_packets.begin(), codec_data->premature_packets.end(), [](const PrematureAudioPacket& a, const PrematureAudioPacket& b) { + return a.packet_id < b.packet_id; + }); + } + } else { + auto enqueued = this->output_source->enqueue_samples(target_buffer, resampled_samples); + if(enqueued != resampled_samples) + log_warn(category::voice_connection, tr("Failed to enqueue all samples for client {}. Enqueued {} of {}"), this->_client_id, enqueued, resampled_samples); + this->set_state(state::playing); + + /* test if any premature got its original place */ + { + unique_lock buffer_lock(this->audio_decode_queue_lock); + + size_t play_count = 0; + while(!codec_data->premature_packets.empty()) { + auto& packet = codec_data->premature_packets[0]; + + //Test if we're able to replay stuff again + if((uint16_t) (codec_data->last_packet_id + 1) < packet.packet_id) + break; //Nothing new + + this->output_source->enqueue_samples(packet.buffer); + codec_data->last_packet_id = packet.packet_id; + codec_data->premature_packets.pop_front(); + play_count++; + } +#ifdef DEBUG_PREMATURE_PACKETS + if(play_count > 0) + log_debug(category::audio, tr("Replayed (id match) {} premature packets for client {}"), play_count, this->_client_id); +#endif + } + } +} + +void VoiceClient::event_execute_dropped(const std::chrono::system_clock::time_point &point) { + if(audio_decode_event_dropped.exchange(true)) + //Is not really a warning, it happens all the time and isn't really an issue + ;//log_warn(category::voice_connection, tr("Dropped auto enqueue event execution two or more times in a row for client {}"), this->_client_id); +} diff --git a/native/serverconnection/src/connection/audio/VoiceClient.h b/native/serverconnection/src/connection/audio/VoiceClient.h new file mode 100644 index 0000000..0400e1a --- /dev/null +++ b/native/serverconnection/src/connection/audio/VoiceClient.h @@ -0,0 +1,178 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "../../audio/AudioResampler.h" +#include "../../audio/codec/Converter.h" +#include "../../audio/AudioOutput.h" +#include "../../EventLoop.h" + +namespace tc { + namespace connection { + class ServerConnection; + class VoiceConnection; + class VoiceClient; + + namespace codec { + enum value { + MIN = 0, + + SPEEX_NARROWBAND = 0, + SPEEX_WIDEBAND = 1, + SPEEX_ULTRA_WIDEBAND = 2, + + CELT_MONO = 3, + + OPUS_VOICE = 4, + OPUS_MUSIC = 5, + + MAX = 5, + }; + + struct condec_info { + bool supported; + std::string name; + std::function(std::string&)> new_converter; + }; + + extern const condec_info info[6]; + inline const condec_info* get_info(value codec) { + if(codec > value::MAX || codec < value::MIN) + return nullptr; + return &info[codec]; + } + } + + class VoiceClient : private event::EventEntry { + friend class VoiceConnection; + + template + friend inline std::shared_ptr<_Tp> std::static_pointer_cast(const std::shared_ptr<_Up>& __r) noexcept; + public: + struct state { + enum value { + buffering, /* this state is never active */ + playing, + stopping, + stopped + }; + }; + VoiceClient(const std::shared_ptr& /* connection */, uint16_t /* client id */); + virtual ~VoiceClient(); + + inline uint16_t client_id() { return this->_client_id; } + + void initialize_js_object(); + void finalize_js_object(); + + v8::Local js_handle() { + assert(v8::Isolate::GetCurrent()); + return this->_js_handle.Get(Nan::GetCurrentContext()->GetIsolate()); + } + + inline std::shared_ptr ref() { return this->_ref.lock(); } + + void process_packet(uint16_t packet_id, const pipes::buffer_view& /* buffer */, codec::value /* codec */, bool /* head */); + + inline float get_volume() { return this->_volume; } + inline void set_volume(float value) { this->_volume = value; } + + inline state::value state() { return this->_state; } + + void cancel_replay(); + + std::function on_state_changed; + + inline std::shared_ptr output_stream() { return this->output_source; } + private: + struct PrematureAudioPacket { + uint16_t packet_id = 0; + std::shared_ptr buffer{}; + }; + + struct AudioCodec { + uint16_t last_packet_id = 0; + std::chrono::system_clock::time_point last_packet_timestamp; + + bool successfully_initialized; + std::shared_ptr converter; + std::shared_ptr resampler; + + std::deque premature_packets; + }; + + std::array, codec::MAX + 1> codec{ + nullptr, + nullptr, + nullptr, + nullptr, + nullptr + }; + std::shared_ptr output_source; + + std::weak_ptr _ref; + v8::Persistent _js_handle; + + uint16_t _client_id; + float _volume = 1.f; + + bool play_premature_packets = false; + + std::chrono::system_clock::time_point _last_received_packet; + state::value _state = state::stopped; + inline void set_state(state::value value) { + if(value == this->_state) + return; + this->_state = value; + if(this->on_state_changed) + this->on_state_changed(); + } + + struct EncodedBuffer { + bool head; + uint16_t packet_id; + pipes::buffer buffer; + codec::value codec; + std::chrono::system_clock::time_point receive_timestamp; + }; + + std::atomic_bool audio_decode_event_dropped{false}; + std::mutex audio_decode_queue_lock; + std::deque> audio_decode_queue; + void event_execute(const std::chrono::system_clock::time_point &point) override; + void event_execute_dropped(const std::chrono::system_clock::time_point &point) override; + void process_encoded_buffer(const std::unique_ptr& /* buffer */); + }; + + + class VoiceClientWrap : public Nan::ObjectWrap { + public: + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + VoiceClientWrap(const std::shared_ptr&); + virtual ~VoiceClientWrap(); + + void do_wrap(const v8::Local&); + private: + static NAN_METHOD(_get_state); + static NAN_METHOD(_get_volume); + static NAN_METHOD(_set_volume); + static NAN_METHOD(_abort_replay); + static NAN_METHOD(_get_stream); + + std::weak_ptr _handle; + + bool _currently_playing = false; + Nan::callback_t<> call_state_changed; + void _call_state_changed(); + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/audio/VoiceConnection.cpp b/native/serverconnection/src/connection/audio/VoiceConnection.cpp new file mode 100644 index 0000000..e01b1c9 --- /dev/null +++ b/native/serverconnection/src/connection/audio/VoiceConnection.cpp @@ -0,0 +1,386 @@ +#include "VoiceConnection.h" +#include "VoiceClient.h" +#include "../ServerConnection.h" +#include "AudioSender.h" +#include "../../audio/js/AudioConsumer.h" +#include "../../audio/AudioInput.h" +#include "../../logger.h" +#include /* MUST be included as last file */ + +using namespace std; +using namespace tc; +using namespace tc::connection; +using namespace ts; +using namespace ts::protocol; +using namespace audio::recorder; + +VoiceConnectionWrap::VoiceConnectionWrap(const std::shared_ptr& handle) : handle(handle) {} +VoiceConnectionWrap::~VoiceConnectionWrap() { + if(!this->_voice_recoder_handle.IsEmpty()) { + auto old_consumer = this->_voice_recoder_ptr; + assert(old_consumer); + + lock_guard read_lock(old_consumer->native_consumer()->on_read_lock); + old_consumer->native_consumer()->on_read = nullptr; + } +} + +void VoiceConnectionWrap::do_wrap(const v8::Local &object) { + this->Wrap(object); +} + +NAN_MODULE_INIT(VoiceConnectionWrap::Init) { + auto klass = Nan::New(VoiceConnectionWrap::NewInstance); + klass->SetClassName(Nan::New("VoiceConnection").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "decoding_supported", VoiceConnectionWrap::_decoding_supported); + Nan::SetPrototypeMethod(klass, "encoding_supported", VoiceConnectionWrap::_encoding_supported); + + Nan::SetPrototypeMethod(klass, "register_client", VoiceConnectionWrap::_register_client); + Nan::SetPrototypeMethod(klass, "available_clients", VoiceConnectionWrap::_available_clients); + Nan::SetPrototypeMethod(klass, "unregister_client", VoiceConnectionWrap::_unregister_client); + + Nan::SetPrototypeMethod(klass, "audio_source", VoiceConnectionWrap::_audio_source); + Nan::SetPrototypeMethod(klass, "set_audio_source", VoiceConnectionWrap::_set_audio_source); + + Nan::SetPrototypeMethod(klass, "get_encoder_codec", VoiceConnectionWrap::_get_encoder_codec); + Nan::SetPrototypeMethod(klass, "set_encoder_codec", VoiceConnectionWrap::_set_encoder_codec); + + Nan::SetPrototypeMethod(klass, "enable_voice_send", VoiceConnectionWrap::_enable_voice_send); + + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(VoiceConnectionWrap::NewInstance) { + if(!info.IsConstructCall()) + Nan::ThrowError("invalid invoke!"); +} + +NAN_METHOD(VoiceConnectionWrap::_connected) { + info.GetReturnValue().Set(true); +} + +NAN_METHOD(VoiceConnectionWrap::_encoding_supported) { + if(info.Length() != 1) { + Nan::ThrowError("invalid argument count"); + return; + } + auto codec = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + + info.GetReturnValue().Set(codec >= 4 && codec <= 5); /* ignore SPEX currently :/ */ +} + +NAN_METHOD(VoiceConnectionWrap::_decoding_supported) { + if(info.Length() != 1) { + Nan::ThrowError("invalid argument count"); + return; + } + auto codec = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + + info.GetReturnValue().Set(codec >= 4 && codec <= 5); /* ignore SPEX currently :/ */ +} + +NAN_METHOD(VoiceConnectionWrap::_register_client) { + return ObjectWrap::Unwrap(info.Holder())->register_client(info); +} + +NAN_METHOD(VoiceConnectionWrap::register_client) { + if(info.Length() != 1) { + Nan::ThrowError("invalid argument count"); + return; + } + auto id = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + auto handle = this->handle.lock(); + if(!handle) { + Nan::ThrowError("handle has been deallocated"); + return; + } + + auto client = handle->register_client(id); + if(!client) { + Nan::ThrowError("failed to register client"); + return; + } + client->initialize_js_object(); + info.GetReturnValue().Set(client->js_handle()); +} + + +NAN_METHOD(VoiceConnectionWrap::_available_clients) { + return ObjectWrap::Unwrap(info.Holder())->available_clients(info); +} + + +NAN_METHOD(VoiceConnectionWrap::available_clients) { + auto handle = this->handle.lock(); + if(!handle) { + Nan::ThrowError("handle has been deallocated"); + return; + } + + auto client = handle->clients(); + + v8::Local result = Nan::New(client.size()); + for(size_t index = 0; index < client.size(); index++) + Nan::Set(result, index, client[index]->js_handle()); + + info.GetReturnValue().Set(result); +} + +NAN_METHOD(VoiceConnectionWrap::_unregister_client) { + return ObjectWrap::Unwrap(info.Holder())->unregister_client(info); +} +NAN_METHOD(VoiceConnectionWrap::unregister_client) { + if(info.Length() != 1) { + Nan::ThrowError("invalid argument count"); + return; + } + auto id = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); + auto handle = this->handle.lock(); + if(!handle) { + Nan::ThrowError("handle has been deallocated"); + return; + } + auto client = handle->find_client(id); + if(!client) { + Nan::ThrowError("missing client"); + return; + } + + client->finalize_js_object(); + handle->delete_client(client); +} + +NAN_METHOD(VoiceConnectionWrap::_audio_source) { + auto client = ObjectWrap::Unwrap(info.Holder()); + info.GetReturnValue().Set(client->_voice_recoder_handle.Get(info.GetIsolate())); +} + +NAN_METHOD(VoiceConnectionWrap::_set_audio_source) { + ObjectWrap::Unwrap(info.Holder())->set_audio_source(info); +} + +NAN_METHOD(VoiceConnectionWrap::set_audio_source) { + if(info.Length() != 1) { + Nan::ThrowError("invalid argument count"); + return; + } + + + if(!Nan::New(AudioConsumerWrapper::constructor_template())->HasInstance(info[0]) && !info[0]->IsNullOrUndefined()) { + Nan::ThrowError("invalid consumer (Consumer must be native!)"); + return; + } + + if(!this->handle.lock()) { + Nan::ThrowError("handle has been deallocated"); + return; + } + + this->release_recorder(); + if(!info[0]->IsNullOrUndefined()) { + this->_voice_recoder_ptr = ObjectWrap::Unwrap(info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked()); + this->_voice_recoder_handle.Reset(info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked()); + + auto native_consumer = this->_voice_recoder_ptr->native_consumer(); + + weak_ptr weak_handle = this->handle; + auto sample_rate = native_consumer->sample_rate; + auto channels = native_consumer->channel_count; + + lock_guard read_lock(this->_voice_recoder_ptr->native_read_callback_lock); + this->_voice_recoder_ptr->native_read_callback = [weak_handle, sample_rate, channels](const void* buffer, size_t length) { + auto handle = weak_handle.lock(); + if(!handle) { + log_warn(category::audio, tr("Missing voice connection handle. Dropping input!")); + return; + } + + shared_ptr sender = handle->voice_sender(); + if(sender) { + if(length > 0 && buffer) + sender->send_data(buffer, length, sample_rate, channels); + else + sender->send_stop(); + } else { + log_warn(category::audio, tr("Missing voice connection audio sender. Dropping input!")); + return; + } + }; + } +} + +NAN_METHOD(VoiceConnectionWrap::_get_encoder_codec) { + auto _this = ObjectWrap::Unwrap(info.Holder()); + auto handle = _this->handle.lock(); + if(!handle) { + Nan::ThrowError("handle has been deallocated"); + return; + } + + info.GetReturnValue().Set(handle->get_encoder_codec()); +} + +NAN_METHOD(VoiceConnectionWrap::_set_encoder_codec) { + auto _this = ObjectWrap::Unwrap(info.Holder()); + auto handle = _this->handle.lock(); + if(!handle) { + Nan::ThrowError("handle has been deallocated"); + return; + } + + + if(info.Length() != 1 || !info[0]->IsNumber()) { + Nan::ThrowError("Invalid arguments"); + return; + } + + handle->set_encoder_codec((uint8_t) info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); +} + +NAN_METHOD(VoiceConnectionWrap::_enable_voice_send) { + auto _this = ObjectWrap::Unwrap(info.Holder()); + auto handle = _this->handle.lock(); + if(!handle) { + Nan::ThrowError("handle has been deallocated"); + return; + } + + if(info.Length() != 1 || !info[0]->IsBoolean()) { + Nan::ThrowError("Invalid arguments"); + return; + } + + auto sender = handle->voice_sender(); + if(!sender) { + Nan::ThrowError("Voice sender has been deallocated"); + return; + } + + sender->set_voice_send_enabled(info[0]->BooleanValue(info.GetIsolate())); +} + + +void VoiceConnectionWrap::release_recorder() { + if(!this->_voice_recoder_handle.IsEmpty()) { + assert(v8::Isolate::GetCurrent()); + + auto old_consumer = this->_voice_recoder_ptr; + assert(old_consumer); + + lock_guard read_lock(this->_voice_recoder_ptr->native_read_callback_lock); + this->_voice_recoder_ptr->native_read_callback = nullptr; + } else { + assert(!this->_voice_recoder_ptr); + } + + this->_voice_recoder_ptr = nullptr; + this->_voice_recoder_handle.Reset(); +} + + +VoiceConnection::VoiceConnection(ServerConnection *handle) : _handle(handle) { + this->_voice_sender = make_shared(this); + this->_voice_sender->_ref = this->_voice_sender; + this->_voice_sender->set_codec(codec::OPUS_MUSIC); +} +VoiceConnection::~VoiceConnection() { + if(v8::Isolate::GetCurrent()) + this->finalize_js_object(); + else { + assert(this->_js_handle.IsEmpty()); + } + + this->_voice_sender->finalize(); +} + +void VoiceConnection::reset() { + lock_guard lock(this->_clients_lock); + this->_clients.clear(); +} + +void VoiceConnection::initialize_js_object() { + auto object_wrap = new VoiceConnectionWrap(this->ref()); + auto object = Nan::NewInstance(Nan::New(VoiceConnectionWrap::constructor()), 0, nullptr).ToLocalChecked(); + object_wrap->do_wrap(object); + + this->_js_handle.Reset(Nan::GetCurrentContext()->GetIsolate(), object); +} + +void VoiceConnection::finalize_js_object() { + this->_js_handle.Reset(); +} + +std::shared_ptr VoiceConnection::find_client(uint16_t client_id) { + lock_guard lock(this->_clients_lock); + for(const auto& client : this->_clients) + if(client->client_id() == client_id) + return client; + + return nullptr; +} + +std::shared_ptr VoiceConnection::register_client(uint16_t client_id) { + lock_guard lock(this->_clients_lock); + auto client = this->find_client(client_id); + if(client) return client; + + client = make_shared(this->ref(), client_id); + client->_ref = client; + this->_clients.push_back(client); + return client; +} + +void VoiceConnection::delete_client(const std::shared_ptr &client) { + { + lock_guard lock(this->_clients_lock); + auto it = find(this->_clients.begin(), this->_clients.end(), client); + if(it != this->_clients.end()) { + this->_clients.erase(it); + } + } + + //TODO deinitialize client +} + +void VoiceConnection::process_packet(const std::shared_ptr &packet) { + if(packet->type() == PacketTypeInfo::Voice) { + if(packet->data().length() < 5) { + //TODO log invalid voice packet + return; + } + auto packet_id = be2le16(&packet->data()[0]); + auto client_id = be2le16(&packet->data()[2]); + auto codec_id = (uint8_t) packet->data()[4]; + auto flag_head = packet->has_flag(PacketFlag::Compressed); + //container->voice_data = packet->data().length() > 5 ? packet->data().range(5) : pipes::buffer{}; + + //log_info(category::voice_connection, tr("Received voice packet from {}. Packet ID: {}"), client_id, packet_id); + auto client = this->find_client(client_id); + if(!client) { + log_warn(category::voice_connection, tr("Received voice packet from unknown client {}. Dropping packet!"), client_id); + return; + } + + if(packet->data().length() > 5) + client->process_packet(packet_id, packet->data().range(5), (codec::value) codec_id, flag_head); + else + client->process_packet(packet_id, pipes::buffer_view{nullptr, 0}, (codec::value) codec_id, flag_head); + } else { + //TODO implement whisper + } +} + +void VoiceConnection::set_encoder_codec(const uint8_t &codec) { + if(codec > codec::MAX) return; + + auto vs = this->_voice_sender; + if(vs) + vs->set_codec((codec::value) codec); +} + +uint8_t VoiceConnection::get_encoder_codec() { + auto vs = this->_voice_sender; + return vs ? vs->get_codec() : 0; +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/audio/VoiceConnection.h b/native/serverconnection/src/connection/audio/VoiceConnection.h new file mode 100644 index 0000000..9347dee --- /dev/null +++ b/native/serverconnection/src/connection/audio/VoiceConnection.h @@ -0,0 +1,109 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace tc { + namespace audio { + namespace recorder { + class AudioConsumerWrapper; + } + } + + namespace connection { + class ServerConnection; + class VoiceConnection; + class VoiceClient; + class VoiceSender; + + class VoiceConnectionWrap : public Nan::ObjectWrap { + public: + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + explicit VoiceConnectionWrap(const std::shared_ptr&); + virtual ~VoiceConnectionWrap(); + + void do_wrap(const v8::Local&); + private: + static NAN_METHOD(_connected); + static NAN_METHOD(_encoding_supported); + static NAN_METHOD(_decoding_supported); + + static NAN_METHOD(_register_client); + NAN_METHOD(register_client); + static NAN_METHOD(_available_clients); + NAN_METHOD(available_clients); + static NAN_METHOD(_unregister_client); + NAN_METHOD(unregister_client); + + static NAN_METHOD(_audio_source); + static NAN_METHOD(_set_audio_source); + NAN_METHOD(set_audio_source); + + static NAN_METHOD(_get_encoder_codec); + static NAN_METHOD(_set_encoder_codec); + static NAN_METHOD(_enable_voice_send); + + void release_recorder(); + + std::function _read_callback; + audio::recorder::AudioConsumerWrapper* _voice_recoder_ptr = nullptr; + Nan::Persistent _voice_recoder_handle; + std::weak_ptr handle; + }; + + class VoiceConnection { + friend class ServerConnection; + friend class VoiceConnectionWrap; + public: + explicit VoiceConnection(ServerConnection*); + virtual ~VoiceConnection(); + + void reset(); + + void initialize_js_object(); + void finalize_js_object(); + + ServerConnection* handle() { return this->_handle; } + v8::Local js_handle() { + assert(v8::Isolate::GetCurrent()); + return this->_js_handle.Get(Nan::GetCurrentContext()->GetIsolate()); + } + + inline std::shared_ptr ref() { return this->_ref.lock(); } + inline std::deque> clients() { + std::lock_guard lock(this->_clients_lock); + return this->_clients; + } + + inline std::shared_ptr voice_sender() { return this->_voice_sender; } + + std::shared_ptr find_client(uint16_t /* client id */); + std::shared_ptr register_client(uint16_t /* client id */); + void delete_client(const std::shared_ptr&); + + void process_packet(const std::shared_ptr&); + + void set_encoder_codec(const uint8_t& /* codec */); + uint8_t get_encoder_codec(); + private: + ServerConnection* _handle; + std::weak_ptr _ref; + + v8::Persistent _js_handle; + + std::recursive_mutex _clients_lock; + std::deque> _clients; + + std::shared_ptr _voice_sender; + }; + } +} \ No newline at end of file diff --git a/native/serverconnection/src/connection/ft/FileTransferManager.cpp b/native/serverconnection/src/connection/ft/FileTransferManager.cpp new file mode 100644 index 0000000..bfd5a41 --- /dev/null +++ b/native/serverconnection/src/connection/ft/FileTransferManager.cpp @@ -0,0 +1,773 @@ +#include "FileTransferManager.h" +#include "FileTransferObject.h" + +#include +#include +#include + +#ifndef WIN32 + #include + #include +#else + #include + #define SOCK_NONBLOCK (0) + #define MSG_DONTWAIT (0) +#endif + +using namespace tc; +using namespace tc::ft; +using namespace std; +using namespace std::chrono; + +tc::ft::FileTransferManager* transfer_manager = nullptr; + +Transfer::~Transfer() { + log_free("Transfer", this); +} + +bool Transfer::initialize(std::string &error) { + if(this->_state != state::UNINITIALIZED) { + error = tr("invalid state"); + return false; + } + + if(!this->_transfer_object->initialize(error)) { + error = tr("failed to initialize transfer object: ") + error; + return false; + } + this->_state = state::CONNECTING; + + /* resolve address */ + { + addrinfo hints{}, *result; + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + + if(getaddrinfo(this->_options->remote_address.data(), nullptr, &hints, &result) != 0 || !result) { + error = tr("failed to resolve hostname"); + this->_state = state::UNINITIALIZED; + return false; + } + + memcpy(&this->remote_address, result->ai_addr, result->ai_addrlen); + freeaddrinfo(result); + } + switch(this->remote_address.ss_family) { + case AF_INET: + ((sockaddr_in*) &this->remote_address)->sin_port = htons(this->_options->remote_port); + case AF_INET6: + ((sockaddr_in6*) &this->remote_address)->sin6_port = htons(this->_options->remote_port); + default: + break; + } + + log_info(category::file_transfer, tr("Setting remote port to {}"), this->_options->remote_port); + this->_socket = (int) ::socket(this->remote_address.ss_family, SOCK_STREAM | SOCK_NONBLOCK, 0); + if(this->_socket < 0) { + this->finalize(); + error = tr("failed to spawn socket"); + return false; + } + +#ifdef WIN32 + u_long enabled = 0; + auto non_block_rs = ioctlsocket(this->_socket, FIONBIO, &enabled); + if (non_block_rs != NO_ERROR) { + this->finalize(); + error = "failed to enable non blocking more"; + return false; + } +#endif + + { + + lock_guard lock(this->event_lock); + this->event_read = event_new(this->event_io, this->_socket, EV_READ | EV_PERSIST, &Transfer::_callback_read, this); + this->event_write = event_new(this->event_io, this->_socket, EV_WRITE, &Transfer::_callback_write, this); + } + return true; +} + +bool Transfer::connect() { + int result = ::connect(this->_socket, reinterpret_cast (&this->remote_address), sizeof(this->remote_address)); + if (result < 0) { +#ifdef WIN32 + auto error = WSAGetLastError(); + + if(error != WSAEWOULDBLOCK) { + wchar_t *s = nullptr; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&s, + 0, + nullptr + ); + fprintf(stdout, "Connect failed with code %d. Error: %ld/%S\n", result, error, s); + LocalFree(s); + return false; + } +#else + if(errno != EINPROGRESS) { + log_error(category::file_transfer, tr("Failed to connect with code: {} => {}/{}"), result, errno, strerror(errno)); + this->finalize(); + return false; + } +#endif + } else { + this->_state = state::CONNECTED; /* we're connected */ + } + log_debug(category::file_transfer, tr("Connect result: {} - {}"), result, errno); + + timeval connect_timeout{5, 0}; + event_add(this->event_write, &connect_timeout); /* enabled if socket is connected */ + ////event_add(this->event_read, &connect_timeout); /* enabled if socket is connected */ + this->handle()->execute_event_loop(); + + if(this->_state == state::CONNECTED) + this->handle_connected(); + return true; +} + +void Transfer::finalize(bool blocking) { + if(this->_state == state::UNINITIALIZED) + return; + + this->_state = state::UNINITIALIZED; + + { + unique_lock lock(this->event_lock); + auto event_read = this->event_read, event_write = this->event_write; + this->event_read = nullptr; + this->event_write = nullptr; + lock.unlock(); + if(event_read) { + if(blocking) + event_del_block(event_read); + else + event_del_noblock(event_read); + event_free(event_read); + } + if(event_write) { + if(blocking) + event_del_block(event_write); + else + event_del_noblock(event_write); + event_free(event_write); + } + } + + if(this->_socket > 0) { +#ifdef WIN32 + closesocket(this->_socket); +#else + shutdown(this->_socket, SHUT_RDWR); + close(this->_socket); +#endif + this->_socket = 0; + } + + this->_transfer_object->finalize(); + + this->_handle->remove_transfer(this); +} + +void Transfer::_callback_write(evutil_socket_t, short flags, void *_ptr_transfer) { + reinterpret_cast(_ptr_transfer)->callback_write(flags); +} + +void Transfer::_callback_read(evutil_socket_t, short flags, void *_ptr_transfer) { + reinterpret_cast(_ptr_transfer)->callback_read(flags); +} + +void Transfer::callback_read(short flags) { + if(this->_state < state::CONNECTING && this->_state > state::DISCONNECTING) + return; + + if(flags & EV_TIMEOUT) { + auto target = dynamic_pointer_cast(this->_transfer_object); + if(target) { + if(this->last_target_write.time_since_epoch().count() == 0) + this->last_target_write = system_clock::now(); + else if(system_clock::now() - this->last_target_write > seconds(5)) { + this->call_callback_failed("timeout (write)"); + this->finalize(false); + return; + } + } else { + if(this->last_source_read.time_since_epoch().count() == 0) + this->last_source_read = system_clock::now(); + else if(system_clock::now() - this->last_source_read > seconds(5)) { + this->call_callback_failed("timeout (read)"); + this->finalize(false); + return; + } + } + + { + lock_guard lock(this->event_lock); + if(this->event_read) { + event_add(this->event_read, &this->alive_check_timeout); + this->handle()->execute_event_loop(); + } + } + } + + if(flags & EV_READ) { + if(this->_state == state::CONNECTING) { + log_debug(category::file_transfer, tr("Connected (read event)")); + this->handle_connected(); + } + + int64_t buffer_length = 1024; + char buffer[1024]; + + buffer_length = recv(this->_socket, buffer, (int) buffer_length, MSG_DONTWAIT); + if(buffer_length < 0) { +#ifdef WIN32 + auto error = WSAGetLastError(); + + if(error != WSAEWOULDBLOCK) + return; +#else + if(errno == EAGAIN) + return; +#endif + + log_error(category::file_transfer, tr("Received an error while receivig data: {}/{}"), errno, strerror(errno)); + //TODO may handle this error message? + this->handle_disconnect(); + return; + } else if(buffer_length == 0) { + log_info(category::file_transfer, tr("Received an disconnect")); + this->handle_disconnect(); + return; + } + + auto target = dynamic_pointer_cast(this->_transfer_object); + if(target) { + log_trace(category::file_transfer, tr("Read {} bytes"), buffer_length); + string error; + auto state = target->write_bytes(error, (uint8_t*) buffer, buffer_length); + this->last_target_write = system_clock::now(); + if(state == error::out_of_space) { + log_error(category::file_transfer, tr("Failed to write read data (out of space)")); + this->call_callback_failed(tr("out of local space")); + this->finalize(true); + return; + } else if(state == error::custom) { + log_error(category::file_transfer, tr("Failed to write read data ({})"), error); + this->call_callback_failed(error); + this->finalize(true); + return; + } else if(state == error::custom_recoverable) { + log_error(category::file_transfer, tr("Failed to write read data ({})"), error); + } else if(state != error::success) { + log_error(category::file_transfer, tr("invalid local write return code! ({})"), state); + } + + auto stream_index = target->stream_index(); + auto expected_bytes = target->expected_length(); + if(stream_index >= expected_bytes) { + this->call_callback_finished(false); + this->finalize(false); + } + this->call_callback_process(stream_index, expected_bytes); + } else { + log_warn(category::file_transfer, tr("Read {} bytes, but we're not in download mode"), buffer_length); + } + } +} + +void Transfer::callback_write(short flags) { + if(this->_state < state::CONNECTING && this->_state > state::DISCONNECTING) + return; + + if(flags & EV_TIMEOUT) { + //we received a timeout! (May just for creating buffers) + if(this->_state == state::CONNECTING) { + this->call_callback_failed(tr("failed to connect")); + this->finalize(false); + return; + } + } + + bool readd_write = false, readd_write_for_read = false; + if(flags & EV_WRITE) { + if(this->_state == state::CONNECTING) + this->handle_connected(); + + pipes::buffer buffer; + while(true) { + { + lock_guard lock(this->queue_lock); + auto size = this->write_queue.size(); + if(size == 0) + break; + + buffer = this->write_queue.front(); + this->write_queue.pop_front(); + + readd_write = size > 1; + } + + auto written = send(this->_socket, buffer.data_ptr(), buffer.length(), MSG_DONTWAIT); + if(written <= 0) { + { + lock_guard lock(this->queue_lock); + this->write_queue.push_front(buffer); + readd_write = true; + } +#ifdef WIN32 + auto _error = WSAGetLastError(); +#else + auto _error = errno; + #define WSAEWOULDBLOCK (0) + #define WSAECONNREFUSED (0) + #define WSAECONNRESET (0) + #define WSAENOTCONN (0) +#endif + if(_error == EAGAIN || _error == WSAEWOULDBLOCK) { + break; /* event will be added with e.g. a timeout */ + } else if(_error == ECONNREFUSED || _error == WSAECONNREFUSED) { + this->call_callback_failed("connection refused"); + this->finalize(false); + } else if(_error == ECONNRESET || _error == WSAECONNRESET) { + this->call_callback_failed("connection reset"); + this->finalize(false); + } else if(_error == ENOTCONN || _error == WSAENOTCONN) { + this->call_callback_failed("not connected"); + this->finalize(false); + } else if(written == 0) { + this->handle_disconnect(); + } else { + log_error(category::file_transfer, "Encountered write error: {}/{}", _error, strerror(_error)); + this->handle_disconnect(); + } + return; + } + + if(written < buffer.length()) { + lock_guard lock(this->queue_lock); + this->write_queue.push_front(buffer.range(written)); + readd_write = true; + } + } + } + + if(this->_state == state::CONNECTED) { + auto source = dynamic_pointer_cast(this->_transfer_object); + if(source) { + size_t queue_length = 0; + { + lock_guard lock(this->queue_lock); + queue_length = this->write_queue.size(); + } + + + string error; + auto total_bytes = source->byte_length(); + auto bytes_to_write = total_bytes - source->stream_index(); + + while(queue_length < 8 && bytes_to_write > 0) { + uint64_t buffer_size = 1400; /* best TCP packet size (equal to the MTU) */ + pipes::buffer buffer{buffer_size}; + auto read_status = source->read_bytes(error, buffer.data_ptr(), buffer_size); + this->last_source_read = system_clock::now(); + if(read_status != error::success) { + if(read_status == error::would_block) { + readd_write_for_read = true; + break; + } else if(read_status == error::custom) { + this->call_callback_failed(tr("failed to read from source: ") + error); + this->finalize(false); + return; + } else if(read_status == error::custom_recoverable) { + log_warn(category::file_transfer, tr("Failed to read from source (but its recoverable): {}"), error); + break; + } else { + log_error(category::file_transfer, tr("invalid source read status ({})"), read_status); + this->finalize(false); + return; + } + } else if(buffer_size == 0) { + log_warn(category::file_transfer, tr("Invalid source read size! ({})"), buffer_size); + break; + } + + { + lock_guard lock(this->queue_lock); + this->write_queue.push_back(buffer.range(0, buffer_size)); + queue_length = this->write_queue.size(); + } + + bytes_to_write -= buffer_size; + } + + this->call_callback_process(total_bytes - bytes_to_write, total_bytes); + if(queue_length == 0) { + if(source->stream_index() == source->byte_length()) { + this->call_callback_finished(false); + this->finalize(false); + return; + } + } + + + readd_write = queue_length > 0; + } + } + + /* we only need write for connect */ + if(readd_write || readd_write_for_read) { + lock_guard lock(this->event_lock); + if(this->event_write) { + timeval timeout{}; + if(readd_write) { + /* we should be writeable within the next second or we do a keep alive circle */ + timeout.tv_sec = 1; + timeout.tv_usec = 0; + } else if(readd_write_for_read) { + /* Schedule a next read attempt of our source */ + timeout.tv_sec = 0; + timeout.tv_usec = 50000; + } + event_add(this->event_write, &timeout); + this->handle()->execute_event_loop(); + } + } else { + log_debug(category::general, tr("No readd")); + } +} + +void Transfer::_write_message(const pipes::buffer_view &buffer) { + { + lock_guard lock(this->queue_lock); + this->write_queue.push_back(buffer.own_buffer()); + } + if(this->_state >= state::CONNECTED) { + lock_guard lock(this->event_lock); + if(this->event_write) { + event_add(this->event_write, nullptr); + this->handle()->execute_event_loop(); + } + } +} + +void Transfer::handle_disconnect() { + if(this->_state != state::DISCONNECTING) { + auto source = dynamic_pointer_cast(this->_transfer_object); + auto target = dynamic_pointer_cast(this->_transfer_object); + + if(source && source->stream_index() != source->byte_length()) { + this->call_callback_failed("received disconnect while transmitting (" + to_string(target->stream_index()) + "/" + to_string(target->expected_length()) + ")"); + } else if(target && target->stream_index() != target->expected_length()) { + this->call_callback_failed("received disconnect while receiving (" + to_string(target->stream_index()) + "/" + to_string(target->expected_length()) + ")"); + } else + this->call_callback_finished(false); + } + this->finalize(false); +} + +void Transfer::handle_connected() { + log_info(category::file_transfer, tr("Transfer connected. Sending key {}"), this->_options->transfer_key); + + this->_state = state::CONNECTED; + event_add(this->event_read, &this->alive_check_timeout); + this->handle()->execute_event_loop(); + + this->_write_message(pipes::buffer_view{this->_options->transfer_key.data(), this->_options->transfer_key.length()}); + this->call_callback_connected(); + //We dont have to add a timeout to write for prebuffering because its already done by writing this message +} + +void Transfer::call_callback_connected() { + if(this->callback_start) + this->callback_start(); +} + +void Transfer::call_callback_failed(const std::string &error) { + if(this->callback_failed) + this->callback_failed(error); +} + +void Transfer::call_callback_finished(bool aborted) { + if(this->callback_finished) + this->callback_finished(aborted); +} + +void Transfer::call_callback_process(size_t current, size_t max) { + auto now = system_clock::now(); + if(now - milliseconds{500} > this->last_process_call) + this->last_process_call = now; + else + return; + if(this->callback_process) + this->callback_process(current, max); +} + +FileTransferManager::FileTransferManager() {} +FileTransferManager::~FileTransferManager() {} + +void FileTransferManager::initialize() { + this->event_io_canceled = false; + this->event_io = event_base_new(); + this->event_io_thread = std::thread(&FileTransferManager::_execute_event_loop, this); +} + +void FileTransferManager::finalize() { + this->event_io_canceled = true; + this->event_io_condition.notify_all(); + event_base_loopexit(this->event_io, nullptr); + this->event_io_thread.join(); + + //TODO drop all file transfers! + event_base_free(this->event_io); + this->event_io = nullptr; +} + +void FileTransferManager::_execute_event_loop() { + while(!this->event_io_canceled) { + this->event_execute = false; + event_base_loop(this->event_io, 0); + if(this->running_transfers().size() > 0) { + this_thread::sleep_for(milliseconds(50)); + } else { + unique_lock lock(this->event_io_lock); + this->event_io_condition.wait_for(lock, minutes(1), [&]{ + return this->event_io_canceled || this->event_execute; + }); + } + } +} + +std::shared_ptr FileTransferManager::register_transfer(std::string& error, const std::shared_ptr &object, std::unique_ptr options) { + auto transfer = make_shared(this, object, move(options)); + + transfer->event_io = this->event_io; + if(!transfer->initialize(error)) { + //error = "failed to initialize transfer: " + error; + return nullptr; + } + { + lock_guard lock(this->_transfer_lock); + this->_running_transfers.push_back(transfer); + } + + return transfer; +} + +void FileTransferManager::drop_transfer(const std::shared_ptr &transfer) { + transfer->finalize(true); + { + lock_guard lock(this->_transfer_lock); + auto it = find(this->_running_transfers.begin(), this->_running_transfers.end(), transfer); + if(it != this->_running_transfers.end()) + this->_running_transfers.erase(it); + } +} + +void FileTransferManager::remove_transfer(tc::ft::Transfer *transfer) { + lock_guard lock(this->_transfer_lock); + this->_running_transfers.erase(remove_if(this->_running_transfers.begin(), this->_running_transfers.end(), [&](const shared_ptr& _t) { + return &*_t == transfer; + }), this->_running_transfers.end()); +} + +#ifdef NODEJS_API + +NAN_MODULE_INIT(JSTransfer::Init) { + auto klass = Nan::New(JSTransfer::NewInstance); + klass->SetClassName(Nan::New("JSTransfer").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(klass, "start", JSTransfer::_start); + + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(JSTransfer::NewInstance) { + if (info.IsConstructCall()) { + if(info.Length() != 1 || !info[0]->IsObject()) { + Nan::ThrowError("invalid arguments"); + return; + } + + /* + * transfer_key: string; + * client_transfer_id: number; + * server_transfer_id: number; + * object: HandledTransferObject; + */ + auto options = info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked(); + v8::Local key = options->Get(Nan::New("transfer_key").ToLocalChecked()).As(); + v8::Local client_transfer_id = options->Get(Nan::New("client_transfer_id").ToLocalChecked()).As(); + v8::Local server_transfer_id = options->Get(Nan::New("server_transfer_id").ToLocalChecked()).As(); + v8::Local remote_address = options->Get(Nan::New("remote_address").ToLocalChecked()).As(); + v8::Local remote_port = options->Get(Nan::New("remote_port").ToLocalChecked()).As(); + + if( + key.IsEmpty() || !key->IsString() || + remote_address.IsEmpty() || !remote_address->IsString() || + remote_port.IsEmpty() || !remote_port->IsInt32() || + client_transfer_id.IsEmpty() || !client_transfer_id->IsInt32() || + server_transfer_id.IsEmpty() || !server_transfer_id->IsInt32() + ) { + Nan::ThrowError("invalid argument types"); + return; + } + + auto wrapped_options = options->Get(Nan::New("object").ToLocalChecked()).As(); + if(!TransferObjectWrap::is_wrap(wrapped_options)) { + Nan::ThrowError("invalid handle"); + return; + } + auto transfer_object = ObjectWrap::Unwrap(wrapped_options)->target(); + assert(transfer_object); + + + auto t_options = make_unique(); + t_options->transfer_key = *Nan::Utf8String(key); + t_options->client_transfer_id = client_transfer_id->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + t_options->server_transfer_id = server_transfer_id->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + t_options->remote_address = *Nan::Utf8String(remote_address); + t_options->remote_port = remote_port->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + + string error; + auto transfer = transfer_manager->register_transfer(error, transfer_object, move(t_options)); + if(!transfer) { + Nan::ThrowError(Nan::New("failed to create transfer: " + error).ToLocalChecked()); + return; + } + + auto js_instance = new JSTransfer(transfer); + js_instance->Wrap(info.This()); + js_instance->_self_ref = true; + js_instance->Ref(); /* increase ref counter because file transfer is running */ + info.GetReturnValue().Set(info.This()); + } else { + if(info.Length() != 1) { + Nan::ThrowError("invalid argument count"); + return; + } + + v8::Local cons = Nan::New(constructor()); + v8::Local argv[1] = {info[0]}; + + Nan::TryCatch try_catch; + auto result = Nan::NewInstance(cons, info.Length(), argv); + if(try_catch.HasCaught()) { + try_catch.ReThrow(); + return; + } + info.GetReturnValue().Set(result.ToLocalChecked()); + } +} + +JSTransfer::JSTransfer(std::shared_ptr transfer) : _transfer(move(transfer)) { + this->call_failed = Nan::async_callback([&](std::string error) { + Nan::HandleScope scope; + this->callback_failed(error); + }); + this->call_finished = Nan::async_callback([&](bool f) { + Nan::HandleScope scope; + this->callback_finished(f); + }); + this->call_start = Nan::async_callback([&] { + Nan::HandleScope scope; + this->callback_start(); + }); + this->call_progress = Nan::async_callback([&](uint64_t a, uint64_t b) { + Nan::HandleScope scope; + this->callback_progress(a, b); + }); + + this->_transfer->callback_failed = [&](std::string error) { this->call_failed(std::forward(error)); }; + this->_transfer->callback_finished = [&](bool f) { this->call_finished(std::forward(f)); }; + this->_transfer->callback_start = [&] { this->call_start(); }; + this->_transfer->callback_process = [&](uint64_t a, uint64_t b) { this->call_progress.call_cpy(a, b); }; +} + +JSTransfer::~JSTransfer() { + cout << "JS dealloc" << endl; + this->_transfer->callback_failed = NULL; + this->_transfer->callback_finished = NULL; + this->_transfer->callback_start = NULL; + this->_transfer->callback_process = NULL; +} + +NAN_METHOD(JSTransfer::destory_transfer) { + //TODO! + Nan::ThrowError("Not implemented!"); +} + +NAN_METHOD(JSTransfer::_start) { + return ObjectWrap::Unwrap(info.Holder())->start(info); +} +NAN_METHOD(JSTransfer::start) { + if(!this->_transfer->connect()) { + Nan::ThrowError("failed to connect"); + return; + } + + log_info(category::file_transfer, tr("Connecting to {}:{}"), this->_transfer->options().remote_address, this->_transfer->options().remote_port); +} + +NAN_METHOD(JSTransfer::_abort) { + return ObjectWrap::Unwrap(info.Holder())->abort(info); +} +NAN_METHOD(JSTransfer::abort) { + //TODO! +} + +void JSTransfer::callback_finished(bool flag) { + if(this->_self_ref) { + this->_self_ref = false; + this->Unref(); + } + + auto callback = Nan::Get(this->handle(), Nan::New("callback_finished").ToLocalChecked()).ToLocalChecked().As(); + if(callback.IsEmpty() || !callback->IsFunction()) + return; + + v8::Local arguments[1]; + arguments[0] = Nan::New(flag); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, arguments); +} + +void JSTransfer::callback_start() { + auto callback = Nan::Get(this->handle(), Nan::New("callback_start").ToLocalChecked()).ToLocalChecked().As(); + if(callback.IsEmpty() || !callback->IsFunction()) + return; + + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); +} + +void JSTransfer::callback_progress(uint64_t a, uint64_t b) { + auto callback = Nan::Get(this->handle(), Nan::New("callback_progress").ToLocalChecked()).ToLocalChecked().As(); + if(callback.IsEmpty() || !callback->IsFunction()) + return; + + v8::Local arguments[2]; + arguments[0] = Nan::New(a); + arguments[1] = Nan::New(b); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 2, arguments); +} + +void JSTransfer::callback_failed(std::string error) { + if(this->_self_ref) { + this->_self_ref = false; + this->Unref(); + } + auto callback = Nan::Get(this->handle(), Nan::New("callback_failed").ToLocalChecked()).ToLocalChecked().As(); + if(callback.IsEmpty() || !callback->IsFunction()) + return; + + v8::Local arguments[1]; + arguments[0] = Nan::New(error).ToLocalChecked(); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, arguments); +} +#endif \ No newline at end of file diff --git a/native/serverconnection/src/connection/ft/FileTransferManager.h b/native/serverconnection/src/connection/ft/FileTransferManager.h new file mode 100644 index 0000000..150d12b --- /dev/null +++ b/native/serverconnection/src/connection/ft/FileTransferManager.h @@ -0,0 +1,228 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if NODEJS_API + #include + #include +#include "../../logger.h" + +#endif + +namespace tc { + namespace ft { + namespace error { + enum value : int8_t { + success = 0, + custom = 1, + custom_recoverable = 2, + would_block = 3, + out_of_space = 4 + }; + } + class TransferObject { + public: + explicit TransferObject() {} + + virtual std::string name() const = 0; + virtual bool initialize(std::string& /* error */) = 0; + virtual void finalize() = 0; + }; + + class TransferSource : public TransferObject { + public: + virtual uint64_t byte_length() const = 0; + virtual uint64_t stream_index() const = 0; + + virtual error::value read_bytes(std::string& /* error */, uint8_t* /* buffer */, uint64_t& /* max length/result length */) = 0; + private: + }; + + class TransferTarget : public TransferObject { + public: + TransferTarget() {} + + virtual uint64_t expected_length() const = 0; + + virtual uint64_t stream_index() const = 0; + virtual error::value write_bytes(std::string& /* error */, uint8_t* /* buffer */, uint64_t /* max length */) = 0; + }; + + struct TransferOptions { + std::string remote_address; + uint16_t remote_port = 0; + std::string transfer_key{}; + uint32_t client_transfer_id = 0; + uint32_t server_transfer_id = 0; + }; + + class FileTransferManager; + class Transfer { + friend class FileTransferManager; + public: + struct state { + enum value { + UNINITIALIZED, + CONNECTING, + CONNECTED, + DISCONNECTING + }; + }; + typedef std::function callback_start_t; + typedef std::function callback_finished_t; + typedef std::function callback_failed_t; + typedef std::function callback_process_t; + + explicit Transfer(FileTransferManager* handle, std::shared_ptr transfer_object, std::unique_ptr options) : + _transfer_object(std::move(transfer_object)), + _handle(handle), + _options(std::move(options)) { + log_allocate("Transfer", this); + } + ~Transfer(); + + bool initialize(std::string& /* error */); + void finalize(bool /* blocking */ = true); + + bool connect(); + bool connected() { return this->_state > state::UNINITIALIZED; } + + FileTransferManager* handle() { return this->_handle; } + std::shared_ptr transfer_object() { return this->_transfer_object; } + const TransferOptions& options() { return *this->_options; } + + callback_start_t callback_start{nullptr}; + callback_finished_t callback_finished{nullptr}; + callback_failed_t callback_failed{nullptr}; + callback_process_t callback_process{nullptr}; + private: + static void _callback_read(evutil_socket_t, short, void*); + static void _callback_write(evutil_socket_t, short, void*); + + sockaddr_storage remote_address{}; + FileTransferManager* _handle; + std::unique_ptr _options; + state::value _state = state::UNINITIALIZED; + std::shared_ptr _transfer_object; + + std::mutex event_lock; + event_base* event_io = nullptr; /* gets assigned by the manager */ + ::event* event_read = nullptr; + ::event* event_write = nullptr; + + std::chrono::system_clock::time_point last_source_read; + std::chrono::system_clock::time_point last_target_write; + std::mutex queue_lock; + std::deque write_queue; + void _write_message(const pipes::buffer_view& /* buffer */); + int _socket = 0; + + timeval alive_check_timeout{1, 0}; + timeval write_timeout{1, 0}; + + /* + * Upload mode: + * Write the buffers left in write_queue, and if the queue length is less then 12 create new buffers. + * This event will as well be triggered every second as timeout, to create new buffers if needed + */ + void callback_write(short /* flags */); + void callback_read(short /* flags */); + + /* called within the write/read callback */ + void handle_disconnect(); + void handle_connected(); + + void call_callback_connected(); + void call_callback_failed(const std::string& /* reason */); + void call_callback_finished(bool /* aborted */); + void call_callback_process(size_t /* current */, size_t /* max */); + + std::chrono::system_clock::time_point last_process_call; + }; + + class FileTransferManager { + public: + FileTransferManager(); + ~FileTransferManager(); + + void initialize(); + void finalize(); + + std::shared_ptr register_transfer(std::string& error, const std::shared_ptr& /* object */, std::unique_ptr /* options */); + std::deque> running_transfers() { + std::lock_guard lock(this->_transfer_lock); + return this->_running_transfers; + } + void drop_transfer(const std::shared_ptr& /* transfer */); + void remove_transfer(Transfer*); /* internal use */ + inline void execute_event_loop() { + this->event_execute = true; + this->event_io_condition.notify_all(); + } + private: + bool event_execute = false; + bool event_io_canceled = false; + std::mutex event_io_lock; + std::condition_variable event_io_condition; + std::thread event_io_thread; + event_base* event_io = nullptr; + ::event* event_cleanup = nullptr; + + std::mutex _transfer_lock; + std::deque> _running_transfers; + + void _execute_event_loop(); + }; + +#ifdef NODEJS_API + class JSTransfer : public Nan::ObjectWrap { + public: + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + explicit JSTransfer(std::shared_ptr transfer); + ~JSTransfer(); + + NAN_METHOD(start); + NAN_METHOD(abort); + + static NAN_METHOD(destory_transfer); + private: + static NAN_METHOD(_start); + static NAN_METHOD(_abort); + + std::shared_ptr _transfer; + + Nan::callback_t call_finished; + Nan::callback_t<> call_start; + Nan::callback_t call_progress; + Nan::callback_t call_failed; + + void callback_finished(bool); + void callback_start(); + void callback_progress(uint64_t, uint64_t); + void callback_failed(std::string); + + bool _self_ref = false; + }; +#endif + } +} +extern tc::ft::FileTransferManager* transfer_manager; \ No newline at end of file diff --git a/native/serverconnection/src/connection/ft/FileTransferObject.cpp b/native/serverconnection/src/connection/ft/FileTransferObject.cpp new file mode 100644 index 0000000..c4be3f3 --- /dev/null +++ b/native/serverconnection/src/connection/ft/FileTransferObject.cpp @@ -0,0 +1,290 @@ +#include "FileTransferObject.h" +#include "../../logger.h" +#include + +#include + +namespace fs = std::experimental::filesystem; +using namespace tc; +using namespace tc::ft; +using namespace std; + +#ifdef NODEJS_API +TransferJSBufferTarget::TransferJSBufferTarget() { + log_allocate("TransferJSBufferTarget", this); + + if(!this->_js_buffer.IsEmpty()) { + assert(v8::Isolate::GetCurrent()); + this->_js_buffer.Reset(); + } +} + +TransferJSBufferTarget::~TransferJSBufferTarget() { + log_free("TransferJSBufferTarget", this); +} + +bool TransferJSBufferTarget::initialize(std::string &error) { + return true; /* we've already have data */ +} + +void TransferJSBufferTarget::finalize() { } + +uint64_t TransferJSBufferTarget::stream_index() const { + return this->_js_buffer_index; +} + +error::value TransferJSBufferTarget::write_bytes(std::string &error, uint8_t *source, uint64_t length) { + uint64_t write_length = length; + if(length > this->_js_buffer_length - this->_js_buffer_index) + write_length = this->_js_buffer_length - this->_js_buffer_index; + + if(write_length > 0) { + memcpy((char*) this->_js_buffer_source + this->_js_buffer_index, source, write_length); + this->_js_buffer_index += write_length; + } + + if(write_length == 0) + return error::out_of_space; + + return error::success; +} + +NAN_METHOD(TransferJSBufferTarget::create_from_buffer) { + if(info.Length() != 1 || !info[0]->IsArrayBuffer()) { + Nan::ThrowError("invalid argument"); + return; + } + + auto buffer = info[0].As(); + + auto instance = make_shared(); + instance->_js_buffer = v8::Global(info.GetIsolate(), info[0].As()); + + instance->_js_buffer_source = buffer->GetContents().Data(); + instance->_js_buffer_length = buffer->GetContents().ByteLength(); + instance->_js_buffer_index = 0; + + + auto object_wrap = new TransferObjectWrap(instance); + auto object = Nan::NewInstance(Nan::New(TransferObjectWrap::constructor()), 0, nullptr).ToLocalChecked(); + object_wrap->do_wrap(object); + info.GetReturnValue().Set(object); +} + +TransferJSBufferSource::~TransferJSBufferSource() { + log_free("TransferJSBufferSource", this); + + if(!this->_js_buffer.IsEmpty()) { + assert(v8::Isolate::GetCurrent()); + this->_js_buffer.Reset(); + } +} +TransferJSBufferSource::TransferJSBufferSource() { + log_allocate("TransferJSBufferSource", this); +} + +bool TransferJSBufferSource::initialize(std::string &string) { return true; } + +void TransferJSBufferSource::finalize() { } + +uint64_t TransferJSBufferSource::stream_index() const { + return this->_js_buffer_index; +} + +uint64_t TransferJSBufferSource::byte_length() const { + return this->_js_buffer_length; +} + +error::value TransferJSBufferSource::read_bytes(std::string &error, uint8_t *target, uint64_t &length) { + auto org_length = length; + if(this->_js_buffer_index + length > this->_js_buffer_length) + length = this->_js_buffer_length - this->_js_buffer_index; + + + memcpy(target, (char*) this->_js_buffer_source + this->_js_buffer_index, length); + this->_js_buffer_index += length; + + if(org_length != 0 && length == 0) + return error::out_of_space; + return error::success; +} + +NAN_METHOD(TransferJSBufferSource::create_from_buffer) { + if(info.Length() != 1 || !info[0]->IsArrayBuffer()) { + Nan::ThrowError("invalid argument"); + return; + } + + auto buffer = info[0].As(); + + auto instance = make_shared(); + instance->_js_buffer = v8::Global(info.GetIsolate(), info[0].As()); + + instance->_js_buffer_source = buffer->GetContents().Data(); + instance->_js_buffer_length = buffer->GetContents().ByteLength(); + instance->_js_buffer_index = 0; + + + auto object_wrap = new TransferObjectWrap(instance); + auto object = Nan::NewInstance(Nan::New(TransferObjectWrap::constructor()), 0, nullptr).ToLocalChecked(); + object_wrap->do_wrap(object); + info.GetReturnValue().Set(object); +} + + +NAN_MODULE_INIT(TransferObjectWrap::Init) { + auto klass = Nan::New(TransferObjectWrap::NewInstance); + klass->SetClassName(Nan::New("TransferObjectWrap").ToLocalChecked()); + klass->InstanceTemplate()->SetInternalFieldCount(1); + + constructor().Reset(Nan::GetFunction(klass).ToLocalChecked()); +} + +NAN_METHOD(TransferObjectWrap::NewInstance) { + if(!info.IsConstructCall()) + Nan::ThrowError("invalid invoke!"); +} + +void TransferObjectWrap::do_wrap(v8::Local object) { + this->Wrap(object); + + auto source = dynamic_pointer_cast(this->target()); + auto target = dynamic_pointer_cast(this->target()); + + auto direction = source ? "upload" : "download"; + Nan::Set(object, + Nan::New("direction").ToLocalChecked(), + v8::String::NewFromUtf8(Nan::GetCurrentContext()->GetIsolate(), direction).ToLocalChecked() + ); + Nan::Set(object, + Nan::New("name").ToLocalChecked(), + v8::String::NewFromUtf8(Nan::GetCurrentContext()->GetIsolate(), this->target()->name().c_str()).ToLocalChecked() + ); + + if(source) { + Nan::Set(object, + Nan::New("total_size").ToLocalChecked(), + Nan::New(source->byte_length()) + ); + } + + if(target) { + Nan::Set(object, + Nan::New("expected_size").ToLocalChecked(), + Nan::New(target->expected_length()) + ); + + } +} +#endif + +TransferFileSource::TransferFileSource(std::string path, std::string name) : _path{std::move(path)}, _name{std::move(name)} { + if(!this->_path.empty()) { + if(this->_path.back() == '/') + this->_path.pop_back(); +#ifdef WIN32 + if(this->_path.back() == '\\') + this->_path.pop_back(); +#endif + } +} + +#ifdef WIN32 + #define u8path path +#endif + +uint64_t TransferFileSource::byte_length() const { + if(file_size.has_value()) + return file_size.value(); + + auto file = fs::u8path(this->_path) / fs::u8path(this->_name); + error_code error; + auto size = fs::file_size(file,error); + if(error) + size = 0; + return (this->file_size = std::make_optional(size)).value(); +} + +bool TransferFileSource::initialize(std::string &error) { + auto file = fs::u8path(this->_path) / fs::u8path(this->_name); + + error_code errc; + if(!fs::exists(file)) { + error = "file not found"; + return false; + } + if(errc) { + error = "failed to test for file existence: " + to_string(errc.value()) + "/" + errc.message(); + return false; + } + if(!fs::is_regular_file(file, errc)) { + error = "target file isn't a regular file"; + return false; + } + if(errc) { + error = "failed to test for file regularity: " + to_string(errc.value()) + "/" + errc.message(); + return false; + } + + this->file_stream = std::ifstream{file, std::ifstream::in | std::ifstream::binary}; + if(!this->file_stream) { + error = "failed to open file"; + return false; + } + + this->file_stream.seekg(0, std::ifstream::end); + auto length = this->file_stream.tellg(); + if(length != this->byte_length()) { + error = "file length missmatch"; + return false; + } + this->file_stream.seekg(0, std::ifstream::beg); + + this->position = 0; + return true; +} + +void TransferFileSource::finalize() { + if(this->file_stream) + this->file_stream.close(); + + this->position = 0; +} + +error::value TransferFileSource::read_bytes(std::string &error, uint8_t *buffer, uint64_t &length) { + auto result = this->file_stream.readsome((char*) buffer, length); + if(result > 0) { + length = result; + this->position += result; + return error::success; + } + + if(!this->file_stream) { + if(this->file_stream.eof()) + error = "eof reached"; + else + error = "io error. failed to read"; + } else { + error = "read returned " + to_string(result) + "/" + to_string(length); + } + return error::custom; +} + +uint64_t TransferFileSource::stream_index() const { + return this->position; +} + +#ifdef NODEJS_API +NAN_METHOD(TransferFileSource::create) { + if(info.Length() != 2 || !info[0]->IsString() || !info[1]->IsString()) { + Nan::ThrowError("invalid argument"); + return; + } + + auto instance = make_shared(*Nan::Utf8String{info[0]}, *Nan::Utf8String{info[1]}); + auto object_wrap = new TransferObjectWrap(instance); + auto object = Nan::NewInstance(Nan::New(TransferObjectWrap::constructor()), 0, nullptr).ToLocalChecked(); + object_wrap->do_wrap(object); + info.GetReturnValue().Set(object); +} +#endif \ No newline at end of file diff --git a/native/serverconnection/src/connection/ft/FileTransferObject.h b/native/serverconnection/src/connection/ft/FileTransferObject.h new file mode 100644 index 0000000..a9ff7ac --- /dev/null +++ b/native/serverconnection/src/connection/ft/FileTransferObject.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include "FileTransferManager.h" + +namespace tc { + namespace ft { + class TransferFileSource : public TransferSource { + public: + TransferFileSource(std::string /* path */, std::string /* name */); + + [[nodiscard]] inline std::string file_path() const { return this->_path; } + [[nodiscard]] inline std::string file_name() const { return this->_name; } + + std::string name() const override { return "TransferFileSource"; } + bool initialize(std::string &string) override; + void finalize() override; + + uint64_t byte_length() const override; + uint64_t stream_index() const override; + error::value read_bytes(std::string &string, uint8_t *uint8, uint64_t &uint64) override; + +#ifdef NODEJS_API + static NAN_METHOD(create); +#endif + private: + std::string _path; + std::string _name; + + uint64_t position{0}; + std::ifstream file_stream{}; + mutable std::optional file_size; + }; + +#ifdef NODEJS_API + class TransferObjectWrap : public Nan::ObjectWrap { + public: + static NAN_MODULE_INIT(Init); + static NAN_METHOD(NewInstance); + + static inline bool is_wrap(const v8::Local& value) { + if(value.As().IsEmpty()) + return false; + + return value->InstanceOf(Nan::GetCurrentContext(), Nan::New(constructor())).FromMaybe(false); + } + + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + explicit TransferObjectWrap(std::shared_ptr object) : _transfer(std::move(object)) { + } + + ~TransferObjectWrap() = default; + + void do_wrap(v8::Local object); + + std::shared_ptr target() { return this->_transfer; } + private: + std::shared_ptr _transfer; + }; + + class TransferJSBufferSource : public TransferSource { + public: + TransferJSBufferSource(); + virtual ~TransferJSBufferSource(); + + std::string name() const override { return "TransferJSBufferSource"; } + bool initialize(std::string &string) override; + + void finalize() override; + + uint64_t stream_index() const override; + + uint64_t byte_length() const override; + + error::value read_bytes(std::string &string, uint8_t *uint8, uint64_t &uint64) override; + + static NAN_METHOD(create_from_buffer); + + private: + v8::Global _js_buffer; + void* _js_buffer_source; + uint64_t _js_buffer_length; + uint64_t _js_buffer_index; + }; + + class TransferJSBufferTarget : public TransferTarget { + public: + TransferJSBufferTarget(); + virtual ~TransferJSBufferTarget(); + + std::string name() const override { return "TransferJSBufferTarget"; } + bool initialize(std::string &string) override; + + void finalize() override; + + uint64_t stream_index() const override; + uint64_t expected_length() const override { return this->_js_buffer_length; } + + error::value write_bytes(std::string &string, uint8_t *uint8, uint64_t uint64) override; + + static NAN_METHOD(create_from_buffer); + + private: + v8::Global _js_buffer; + void* _js_buffer_source; + uint64_t _js_buffer_length; + uint64_t _js_buffer_index; + }; +#endif + } +} \ No newline at end of file diff --git a/native/serverconnection/src/hwuid.cpp b/native/serverconnection/src/hwuid.cpp new file mode 100644 index 0000000..e413956 --- /dev/null +++ b/native/serverconnection/src/hwuid.cpp @@ -0,0 +1,225 @@ +#include "./hwuid.h" +#include +#include +#include +#include +#include + +#ifndef WIN32 +#ifdef DARWIN +/* +#include +unsigned short getCpuHash() { + const NXArchInfo* info = NXGetLocalArchInfo(); + unsigned short val = 0; + val += (unsigned short)info->cputype; + val += (unsigned short)info->cpusubtype; + return val; +} + */ +#else // !DARWIN +static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +uint32_t calculate_cpu_hash() { + uint32_t cpuinfo[4] = { 0, 0, 0, 0 }; + native_cpuid(cpuinfo, cpuinfo + 1, cpuinfo + 2, cpuinfo + 3); + + uint32_t hash = 0; + uint32_t* ptr = (&cpuinfo[0]); + for (uint32_t i = 0; i < 4; i++) + hash += ptr[i]; + + return hash; +} +#endif // !DARWIN + +constexpr uint8_t hex_value(char c) { + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'a' && c <= 'f') + return c - 'A' + 10; + if(c >= 'A' && c <= 'F') + return c - '0' + 10; + return 0; +} + +bool read_machine_id(uint8_t(&uuid)[16]) { + strobf_define(_path, "/etc/machine-id"); + + memset(uuid, 0, 16); + std::ifstream in(strobf_val(_path).string()); + if(in) { + char buffer[32]; + if(!in.read(buffer, 32)) return false; + + auto it = buffer; + auto index = 0; + while(index < 16) { + uuid[index] = hex_value(*it) << 4UL; + uuid[index] = hex_value(*it); + index++; + } + } + return false; +} + +inline bool generate_uuid(std::string& result, uint32_t& check_sum) { + uint8_t buffer[16]; + if(!read_machine_id(buffer)) + memcpy(buffer, "AAAABBBBCCCCDDDD", 16); + + auto cpu_hash = calculate_cpu_hash(); + auto it = (uint32_t*) buffer; + for(int i = 0; i < 4; i++) + *it++ = cpu_hash; + + result = base64::encode((char*) buffer, 16); + + { + crc32_state state; + crc32_init(&state); + crc32_update(&state, (u_char*) result.data(), result.length()); + + crc32_finish(&state, &check_sum, sizeof(check_sum)); + } + return true; +} +#else +#include "./smbios.h" +#include +#include +#include + +using namespace std; + +//https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf +int get_uuid(uint8_t* uuid) { +#ifdef WIN32 + typedef DWORD api_size_t; +#else + typedef size_t api_size_t; +#endif + unique_ptr smbios_data{ nullptr, ::free }; + api_size_t smbios_size = 0; + api_size_t bytes_written = 0; + + // Query size of SMBIOS data. + smbios_size = GetSystemFirmwareTable('RSMB', 0, nullptr, 0); + smbios_data.reset((SMBIOSDataHeader*) malloc(smbios_size)); + if (!smbios_data) return -1; //failed to allocate memory + + bytes_written = GetSystemFirmwareTable('RSMB', 0, &*smbios_data, smbios_size); + + if (smbios_size != bytes_written) return -2; //failed to read the firmware table + + if (smbios_data->length > bytes_written - SMBIOSDataHeaderLength) return -3; //invalid length + + //Lets iterate over the headers: + uint8_t* ptr = &smbios_data->table_data; + SMBIOSEntryHeader* header; + while (true) { + header = (SMBIOSEntryHeader*) ptr; + if (header->type == 127 && header->length == 4) { + break; //End marker + } + + if (header->type == 1) { + //Type 1: System Information + if (header->length < 0x18) { + //If version is under 2.1 no uuid is set! + //TODO: Check before for the version? + return -4; //system information table is too short + } + + memcpy(uuid, ptr + 0x08, 16); + return 0; + } + + ptr = ptr + header->length; // point to struct end + while (0 != (*ptr | *(ptr + 1)) && ptr + 1 < (uint8_t*) &*smbios_data + smbios_data->length) + ptr++; // skip string area + + ptr += 2; + if (ptr >= (uint8_t*) &*smbios_data + smbios_data->length - 2) + break; + } + return -6; +} + +uint32_t calculate_cpu_hash() { + int cpuinfo[4] = { 0, 0, 0, 0 }; + __cpuid(cpuinfo, 0); + + uint32_t hash = 0; + auto ptr = (uint32_t*) (&cpuinfo[0]); + for (uint32_t i = 0; i < 4; i++) + hash += ptr[i]; + + return hash; +} + +inline bool generate_uuid(std::string& result, uint32_t& check_sum) { + uint8_t buffer[16]; + auto code = get_uuid(buffer); + if(code != 0) { + memcpy(buffer, "DDDDCCCCBBBBAAAA", 16); /* Reversed to linux (just for the foxic) */ + buffer[15] = code; /* So we could get the error code */ + } + + auto cpu_hash = calculate_cpu_hash(); + auto it = (uint32_t*) buffer; + for(int i = 0; i < 4; i++) + *it++ = cpu_hash; + + result = base64::encode((char*) buffer, 16); + + { + crc32_state state; + crc32_init(&state); + crc32_update(&state, (uint8_t*) result.data(), (unsigned long) result.length()); + + crc32_finish(&state, &check_sum, sizeof(check_sum)); + } + return true; +} +#endif + +inline bool check_uuid(std::string& uuid, uint32_t check_sum) { + crc32_state state; + crc32_init(&state); + crc32_update(&state, (uint8_t*) uuid.data(), (unsigned long) uuid.length()); + + uint32_t result; + crc32_finish(&state, &result, sizeof(result)); + + return result == check_sum; +} + +static std::string _cached_system_uuid{}; +static uint32_t _cached_system_uuid_cksm = 0; +std::string system_uuid() { + if(!_cached_system_uuid.empty() && check_uuid(_cached_system_uuid, _cached_system_uuid_cksm)) + return _cached_system_uuid; + + if(!generate_uuid(_cached_system_uuid, _cached_system_uuid_cksm)) + _cached_system_uuid = ""; + return _cached_system_uuid; +} + +int main() { + std::cout << "UUID: " << system_uuid() << "\n"; + return 1; +} + +//ADaX2mIRrC1uv83h +//NEg5KzRIOSs0SDkrNEg5Kw== \ No newline at end of file diff --git a/native/serverconnection/src/hwuid.h b/native/serverconnection/src/hwuid.h new file mode 100644 index 0000000..a271986 --- /dev/null +++ b/native/serverconnection/src/hwuid.h @@ -0,0 +1,4 @@ +#pragma once + +#include +extern std::string system_uuid(); \ No newline at end of file diff --git a/native/serverconnection/src/logger.cpp b/native/serverconnection/src/logger.cpp new file mode 100644 index 0000000..7ae6faf --- /dev/null +++ b/native/serverconnection/src/logger.cpp @@ -0,0 +1,116 @@ +#include +#include +#include "logger.h" + +/* Basic */ +void(*logger::_force_log)(logger::category::value, logger::level::level_enum /* lvl */, const std::string_view& /* message */); + +/* NODE JS */ +struct LogMessage { + uint8_t level; + uint8_t category; + + std::string message; + + LogMessage* next_message; +}; +std::mutex log_messages_lock; +LogMessage* log_messages_head = nullptr; +LogMessage** log_messages_tail = &log_messages_head; + +Nan::callback_t<> log_messages_callback; +void force_log_node(logger::category::value, spdlog::level::level_enum, const std::string_view &); + +/* Normal */ +void force_log_raw(logger::category::value, spdlog::level::level_enum level, const std::string_view &message); + +struct StdExternalStringResourceBase : public v8::String::ExternalOneByteStringResource { + public: + explicit StdExternalStringResourceBase(const std::string& message) : message(message) {} + + const char *data() const override { + return this->message.data(); + } + + size_t length() const override { + return this->message.length(); + } + + private: + std::string message; +}; + +inline v8::Local get_logger_method() { + v8::Local global_context = Nan::GetCurrentContext()->Global(); + + v8::Local logger_context = global_context->Get(Nan::New("logger").ToLocalChecked()).As(); + v8::Local logger_method = logger_context->Get(Nan::New("log").ToLocalChecked()); + if(!logger_method.IsEmpty() && !logger_method->IsNullOrUndefined()) + return logger_method; + + logger_context = global_context->Get(Nan::New("console").ToLocalChecked()).As(); + return logger_context->Get(Nan::New("log").ToLocalChecked()); +} + +void logger::initialize_node() { + log_messages_callback = Nan::async_callback([]{ + Nan::HandleScope scope; + + auto isolate = Nan::GetCurrentContext()->GetIsolate(); + v8::Local logger_method = get_logger_method(); + + v8::Local arguments[3]; + while(true) { + std::unique_lock messages_lock(log_messages_lock); + if(!log_messages_head) + break; + + auto entry = log_messages_head; + log_messages_head = entry->next_message; + if(!log_messages_head) + log_messages_tail = &log_messages_head; + messages_lock.unlock(); + + if(!logger_method.IsEmpty() && !logger_method->IsNullOrUndefined()) { + arguments[0] = Nan::New(entry->category); + arguments[1] = Nan::New(entry->level); + arguments[2] = v8::String::NewExternalOneByte(isolate, new StdExternalStringResourceBase(entry->message)).ToLocalChecked(); + + logger_method.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 3, arguments); + } else { + std::cout << "Failed to log message! Invalid method!" << std::endl; + } + + delete entry; + } + }); + + logger::_force_log = force_log_node; +} + +void logger::initialize_raw() { + logger::_force_log = force_log_raw; +} + +void force_log_node(logger::category::value category, spdlog::level::level_enum level, const std::string_view &message) { + auto entry = new LogMessage{}; + entry->level = level; + entry->category = category; + entry->message = std::string(message.data(), message.length()); + entry->next_message = nullptr; + + { + std::lock_guard lock(log_messages_lock); + *log_messages_tail = entry; + log_messages_tail = &(entry->next_message); + } + log_messages_callback(); +} + +void force_log_raw(logger::category::value category, spdlog::level::level_enum level, const std::string_view &message) { + std::cout << "[" << level << "][" << category << "] " << message << std::endl; +} + +void logger::err_handler(const std::string &message) { + std::cout << "[ERROR] " << message << std::endl; +} \ No newline at end of file diff --git a/native/serverconnection/src/logger.h b/native/serverconnection/src/logger.h new file mode 100644 index 0000000..821765e --- /dev/null +++ b/native/serverconnection/src/logger.h @@ -0,0 +1,107 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace logger { + namespace level = spdlog::level; + + namespace category { + enum value { + general, + audio, + connection, + voice_connection, + socket, + + file_transfer, + + memory + }; + + using category = value; + } + + extern void initialize_raw(); + extern void initialize_node(); + extern void(*_force_log)(category::value /* category */, level::level_enum /* lvl */, const std::string_view& /* message */); + extern void err_handler(const std::string& /* error */); + + inline bool should_log(level::level_enum lvl) { + return true; + } + + template + inline void force_log(category::value category, level::level_enum lvl, const char *fmt, const Args &... args) { + try { + fmt::MemoryWriter fmt_writer; + fmt_writer.write(fmt, args...); + + _force_log(category, lvl, std::string_view{fmt_writer.data(), fmt_writer.size()}); + } + catch (const std::exception &ex) + { + err_handler(ex.what()); + } + catch(...) + { + err_handler("Unknown exception in logger"); + throw; + } + } + + template + inline void log(category::value category, level::level_enum lvl, const char *fmt, const Args &... args) { + if (should_log(lvl)) + force_log(category, lvl, fmt, args...); + } + + template + inline void trace(category::value category, const char *fmt, const Args &... args) { + log(category, level::trace, fmt, args...); + } + + template + inline void debug(category::value category, const char *fmt, const Args &... args) { + log(category, level::debug, fmt, args...); + } + + template + inline void info(category::value category, const char *fmt, const Args &... args) { + log(category, level::info, fmt, args...); + } + + template + inline void warn(category::value category, const char *fmt, const Args &... args) { + log(category, level::warn, fmt, args...); + } + + template + inline void error(category::value category, const char *fmt, const Args &... args) { + log(category, level::err, fmt, args...); + } + + template + inline void critical(category::value category, const char *fmt, const Args &... args) { + log(category, level::critical, fmt, args...); + } +} + +namespace category = logger::category; + +#define tr(message) message + +#define log_trace(_category, message, ...) logger::trace(::logger::category::_category, message, ##__VA_ARGS__) +#define log_debug(_category, message, ...) logger::debug(::logger::category::_category, message, ##__VA_ARGS__) +#define log_info(_category, message, ...) logger::info(::logger::category::_category, message, ##__VA_ARGS__) +#define log_warn(_category, message, ...) logger::warn(::logger::category::_category, message, ##__VA_ARGS__) +#define log_error(_category, message, ...) logger::error(::logger::category::_category, message, ##__VA_ARGS__) +#define log_critical(_category, message, ...) logger::critical(::logger::category::_category, message, ##__VA_ARGS__) + +#define log_allocate(class, this) log_trace(memory, "Allocated new " class ": {}", (void*) this) +#define log_free(class, this) log_trace(memory, "Deallocated " class ": {}", (void*) this) \ No newline at end of file diff --git a/native/serverconnection/src/smbios.h b/native/serverconnection/src/smbios.h new file mode 100644 index 0000000..7520e88 --- /dev/null +++ b/native/serverconnection/src/smbios.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#pragma pack(push) +#pragma pack(1) +typedef struct _SMBIOSDataHeader +{ + uint8_t _unused; + uint8_t major_version; + uint8_t minor_version; + uint8_t dmi_revision; + uint32_t length; + + uint8_t table_data; +} SMBIOSDataHeader; + +static constexpr size_t SMBIOSDataHeaderLength = 8; +static_assert(sizeof(SMBIOSDataHeader) == SMBIOSDataHeaderLength + 1, "invalid struct size"); + + +typedef struct _SMBIOSEntryHeader +{ + uint8_t type; + uint8_t length; + uint16_t header; + + uint8_t data; +} SMBIOSEntryHeader; + +static constexpr size_t SMBIOSEntryHeaderLength = 4; +static_assert(sizeof(SMBIOSEntryHeader) == SMBIOSEntryHeaderLength + 1, "invalid struct size"); + +#pragma pack(pop) \ No newline at end of file diff --git a/native/serverconnection/test/audio/main.cpp b/native/serverconnection/test/audio/main.cpp new file mode 100644 index 0000000..c3a6841 --- /dev/null +++ b/native/serverconnection/test/audio/main.cpp @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "portaudio.h" +#ifndef WIN32 + #include +#endif +#include "../../src/audio/AudioOutput.h" +#include "../../src/audio/AudioInput.h" +#include "../../src/audio/filter/FilterVad.h" +#include "../../src/audio/filter/FilterThreshold.h" + +#ifdef WIN32 + #include +#if PA_USE_ASIO + #include "pa_asio.h" +#endif +#endif + +using namespace std; +using namespace tc; + +int main() { + string error; + PaError err; + +#ifndef WIN32 + PaJack_SetClientName("TeaClient-Test"); +#endif + err = Pa_Initialize(); + if( err != paNoError ) + { + printf( "ERROR: Pa_Initialize returned 0x%x\n", err ); + return 0; + } + + auto playback_manager = audio::AudioOutput(2, 48000); + if(!playback_manager.open_device(error, Pa_GetDefaultOutputDevice())) { + cerr << "Failed to open output device (" << error << ")" << endl; + return 1; + } + playback_manager.playback(); + + auto input = audio::AudioInput(2, 48000); + if(!input.open_device(error, Pa_GetDefaultInputDevice())) { + cerr << "Failed to open input device (" << error << ")" << endl; + return 1; + } + input.record(); + + { + auto consumer = input.create_consumer(960); + auto target_stream = playback_manager.create_source(); + auto vad_handler = make_shared(2, 48000, 960); + if(!vad_handler->initialize(error, 3, 4)) { + cerr << "failed to initialize vad handler (" << error << ")"; + return 1; + } + + auto threshold_filter = make_shared(2, 48000, 960); + if(!threshold_filter->initialize(error, .5, 5)) { + cerr << "failed to initialize threashold handler (" << error << ")"; + return 1; + } + + consumer->on_read = [target_stream, vad_handler, threshold_filter](const void* buffer, size_t samples) { + cout << "T: " << threshold_filter->analyze(buffer, 0) << endl; + if(vad_handler->process(buffer)) { + cout << "Read " << samples << endl; + target_stream->enqueue_samples(buffer, samples); + } else { + cout << "Drop " << samples << endl; + } + }; + cout << "Read started" << endl; + } + + this_thread::sleep_for(chrono::seconds(10)); + + /* + while(true) { + this_thread::sleep_for(chrono::seconds(1000)); + } + */ + Pa_Terminate(); + return err; +} \ No newline at end of file diff --git a/native/serverconnection/test/cpp/main.cpp b/native/serverconnection/test/cpp/main.cpp new file mode 100644 index 0000000..7d45bbf --- /dev/null +++ b/native/serverconnection/test/cpp/main.cpp @@ -0,0 +1,110 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include + +int n_pending_requests = 0; +struct event_base *base = NULL; + +struct user_data { + char *name; /* the name we're resolving */ + int idx; /* its position on the command line */ +}; + +void callback(int errcode, struct evutil_addrinfo *addr, void *ptr) +{ + struct user_data *data = (user_data*) ptr; + const char *name = data->name; + if (errcode) { + printf("%d. %s -> %s\n", data->idx, name, evutil_gai_strerror(errcode)); + } else { + struct evutil_addrinfo *ai; + printf("%d. %s", data->idx, name); + if (addr->ai_canonname) + printf(" [%s]", addr->ai_canonname); + puts(""); + for (ai = addr; ai; ai = ai->ai_next) { + char buf[128]; + const char *s = NULL; + if (ai->ai_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; + s = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128); + } else if (ai->ai_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; + s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128); + } + if (s) + printf(" -> %s\n", s); + } + evutil_freeaddrinfo(addr); + } + free(data->name); + free(data); + if (--n_pending_requests == 0) + event_base_loopexit(base, NULL); +} + +/* Take a list of domain names from the command line and resolve them in + * parallel. */ +int main(int argc, char **argv) +{ + int i; + struct evdns_base *dnsbase; + + if (argc == 1) { + puts("No addresses given."); + return 0; + } + base = event_base_new(); + if (!base) + return 1; + dnsbase = evdns_base_new(base, 1); + if (!dnsbase) + return 2; + + for (i = 1; i < argc; ++i) { + struct evutil_addrinfo hints; + struct evdns_getaddrinfo_request *req; + struct user_data *user_data; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = EVUTIL_AI_CANONNAME; + /* Unless we specify a socktype, we'll get at least two entries for + * each address: one for TCP and one for UDP. That's not what we + * want. */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_UDP; + + if (!(user_data = (struct user_data*) malloc(sizeof(struct user_data)))) { + perror("malloc"); + exit(1); + } + if (!(user_data->name = strdup(argv[i]))) { + perror("strdup"); + exit(1); + } + user_data->idx = i; + + ++n_pending_requests; + req = evdns_getaddrinfo(dnsbase, argv[i], "_ts3" /* no service name given */, &hints, callback, user_data); + if (req == NULL) { + printf(" [request for %s returned immediately]\n", argv[i]); + /* No need to free user_data or decrement n_pending_requests; that + * happened in the callback. */ + } + } + + if (n_pending_requests) + event_base_dispatch(base); + + evdns_base_free(dnsbase, 0); + event_base_free(base); + + return 0; +} diff --git a/native/serverconnection/test/js/flood.ts b/native/serverconnection/test/js/flood.ts new file mode 100644 index 0000000..d3c3d87 --- /dev/null +++ b/native/serverconnection/test/js/flood.ts @@ -0,0 +1,124 @@ +/// + +module.paths.push("../../build/linux_x64"); + +import * as fs from "fs"; +import * as handle from "teaclient_connection"; +import {NativeServerConnection} from "teaclient_connection"; + +//remote_host: "51.68.181.92", +//remote_host: "94.130.236.135", +//remote_host: "54.36.232.11", /* the beast */ +//remote_host: "79.133.54.207", /* gommehd.net */ + +const target_address = "51.68.181.92"; +const { host, port } = { + host: target_address.split(":")[0], + port: target_address.split(":").length > 1 ? parseInt(target_address.split(":")[1]) : 9987 +}; +class Bot { + connection: NativeServerConnection; + channel_ids: number[] = []; + client_id: number; + initialized: boolean; + + private _interval = []; + private _timeouts = []; + + connect() { + for(const interval of this._interval) + clearInterval(interval); + for(const timeouts of this._timeouts) + clearInterval(timeouts); + + this.channel_ids = []; + this.client_id = 0; + this.initialized = false; + + this.connection = handle.spawn_server_connection(); + this.connection.connect({ + timeout: 5000, + remote_port: port, + remote_host: host, + callback: error => { + if(error == 0) { + this.connection.send_command("clientinit", [ + { + "client_key_offset": 2030434, + /* + "client_version": "1.0.0", + "client_platform": "nodejs/linux", + */ + "client_version": "3.1.8 [Build: 1516614607]", + "client_platform": "Windows", + "client_version_sign": "gDEgQf/BiOQZdAheKccM1XWcMUj2OUQqt75oFuvF2c0MQMXyv88cZQdUuckKbcBRp7RpmLInto4PIgd7mPO7BQ==", + + "client_nickname": "TeaClient Native Module Test", + + "client_input_hardware":true, + "client_output_hardware":true, + "client_default_channel":"", + "client_default_channel_password":"", + "client_server_password":"", + "client_meta_data":"", + "client_nickname_phonetic":"", + "client_default_token":"", + "hwid":"123,456123123123", + return_code:91 + } + ], []); + } else { + console.log("Bot connect failed: %o (%s) ", error, this.connection.error_message(error)); + } + }, + + identity_key: "MG4DAgeAAgEgAiBC9JsqB1am6vowj2obomMyxm1GLk8qyRoxpBkAdiVYxwIgWksaSk7eyVQovZwPZBuiYHARz/xQD5zBUBK6e63V7hICIQCZ2glHe3kV62iIRKpkV2lzZGZtfBPRMbwIcU9aE1EVsg==", + teamspeak: true + }); + + this.connection.callback_command = (command, args, switches) => this.handle_command(command, args); + this.connection.callback_disconnect = () => this.disconnect(); + } + + async disconnect() { + await new Promise(resolve => this.connection.disconnect("bb", resolve)); + this.connection = undefined; + } + + private handle_command(command: string, args: any[]) { + if(command == "initserver") { + this.client_id = parseInt(args[0]["aclid"]); + } else if(command == "channellistfinished"){ + this.initialized = true; + + this._interval.push(setInterval(() => this.switch_channel(), 1000)); + } else if(command == "channellist") { + for(const element of args) { + this.channel_ids.push(parseInt(element["cid"])); + } + } else if(command == "notifychannelcreated") { + this.channel_ids.push(parseInt(args[0]["cid"])); + } else if(command == "notifychanneldeleted") { + for(const arg of args) { + const channel_id = parseInt(arg["cid"]); + const index = this.channel_ids.indexOf(channel_id); + if(index >= 0) + this.channel_ids.splice(index, 1); + } + } + } + + private switch_channel() { + const target_channel = this.channel_ids[Math.floor((Math.random() * 100000) % this.channel_ids.length)]; + console.log("Switching to channel %d", target_channel); + this.connection.send_command("clientmove", [{clid: this.client_id, cid: target_channel}], []); + } +} + + +const bot_list = []; +for(let index = 0; index < 1; index++) { + const bot = new Bot(); + bot_list.push(bot); + bot.connect(); +} \ No newline at end of file diff --git a/native/serverconnection/test/js/ft.ts b/native/serverconnection/test/js/ft.ts new file mode 100644 index 0000000..a16b336 --- /dev/null +++ b/native/serverconnection/test/js/ft.ts @@ -0,0 +1,106 @@ +/// +module.paths.push("../../build/linux_amd64"); +module.paths.push("../../build/win32_64"); + +import * as fs from "fs"; +import * as net from "net"; + +const original_require = require; +require = (module => original_require("/home/wolverindev/TeaSpeak-Client/client/native/build/linux_x64/" + module + ".node")) as any; +import * as handle from "teaclient_connection"; +require = original_require; + +const buffer_size = 24; +const start_server = async () => { + const server = net.createServer(); + await new Promise(resolve => server.listen(30303, "localhost", resolve)); + + server.on('connection', socket => { + console.log("[SERVER] Received new client from %s:%d", socket.remoteAddress, socket.remotePort); + + let key: string = ""; + socket.on('data', buffer => { + if(key.length < 16) { + key += buffer.toString(); + if(key.length >= 16) { + console.log("Received key: %s", key.substr(0, 16)); + if(key.length > 16) { + console.log("Overhead: %s", key.substr(16)); + key = key.substr(0, 16); + } + + if(key == "ft_upload_data__") { + + } else { + //They expect stuff + socket.write("123456789123456789aabb222"); //Must be equal to buffer_size + } + } + } + //console.log("[SERVER] Received data: %s", buffer.toString()); + }); + }); +}; + +function str2ab(str) { + var buf = new ArrayBuffer(str.length); // 2 bytes for each char + var bufView = new Uint8Array(buf); + for (var i=0, strLen=str.length; i { + console.error("Failed to start FT server (%o)", error); +}).then(() => { + const target_buffer = new Uint8Array(buffer_size); + const destination = handle.ft.download_transfer_object_from_buffer(target_buffer.buffer); + //const source = handle.ft.upload_transfer_object_from_buffer(str2ab("Hello World")); + //console.log(source); + //const source = handle.ft.upload_transfer_object_from_file(__dirname, "test_upload.txt"); + const source = handle.ft.upload_transfer_object_from_file("/home/wolverindev/Downloads", "xxx.iso"); + + console.log(source); + const upload = true; + + const transfer = handle.ft.spawn_connection({ + client_transfer_id: 0, + server_transfer_id: 0, + + object: upload ? source : destination, + transfer_key: upload ? "ft_upload_data__" : "ft_download_data", + + remote_address: "localhost", + remote_port: 30303 + }); + + transfer.callback_failed = message => { + console.log("[FT] failed: %o", message); + }; + + transfer.callback_finished = aborted => { + console.log("[FT] done (Aborted %o)", aborted); + if(!upload) + console.log("[FT] Buffer: %o", String.fromCharCode.apply(null, target_buffer)); + //console.log("A: %o", transfer); + }; + + let last = 0; + transfer.callback_progress = (current, max) => { + const diff = current - last; + last = current; + console.log("[FT] Progress: %d|%d (%d) %dmb/s", current, max, Math.ceil(current / max * 100), Math.ceil(diff / 1024 / 1024)); + }; + + transfer.callback_start = () => { + console.log("[FT] start"); + }; + + transfer.start(); +}); + +setInterval(() => { + if(global && global.gc) + global.gc(); +}, 1000); \ No newline at end of file diff --git a/native/serverconnection/test/js/main.ts b/native/serverconnection/test/js/main.ts new file mode 100644 index 0000000..77b263b --- /dev/null +++ b/native/serverconnection/test/js/main.ts @@ -0,0 +1,213 @@ +/// +console.log("HELLO WORLD"); +module.paths.push("../../build/linux_x64"); +module.paths.push("../../build/win32_64"); + +//LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.5 +const os = require('os'); +//process.dlopen(module, '/usr/lib/x86_64-linux-gnu/libasan.so.5', +// os.constants.dlopen.RTLD_NOW); +import * as fs from "fs"; + +const original_require = require; +require = (module => original_require("/home/wolverindev/TeaSpeak-Client/client/native/build/linux_x64/" + module + ".node")) as any; +import * as handle from "teaclient_connection"; +require = original_require; + +const connection_list = []; +const connection = handle.spawn_server_connection(); +const client_list = []; + +console.dir(handle); +console.log("Query devices..."); +console.log("Devices: %o", handle.audio.available_devices()); +console.log("Current playback device: %o", handle.audio.playback.current_device()); +//handle.audio.playback.set_device(14); +//console.log("Current playback device: %o", handle.audio.playback.current_device()); + +const stream = handle.audio.playback.create_stream(); +console.log("Own stream: %o", stream); + + +/* -1 => default device */ +const recorder = handle.audio.record.create_recorder(); +console.log("Have device: %o", recorder); +console.log("Device: %o", recorder.get_device()); +if(recorder.get_device() == -1) { + console.log("Looking for devices"); + for(const device of handle.audio.available_devices()) { + if(!device.input_supported) + continue; + if(device.name != "pulse") + continue; + console.log("Found pulse at %o", device.device_index); + recorder.set_device(device.device_index, () => {}); + } +} +console.log("Device: %o", recorder.get_device()); +recorder.start(() => {}); +console.log("Started: %o", recorder.started()); + +const consumer = recorder.create_consumer(); + +{ + const filter = consumer.create_filter_threshold(.5); + filter.set_margin_frames(10); + /* + filter.set_analyze_filter(value => { + console.log(value); + }) + */ +} + +{ + //const filter = consumer.create_filter_vad(3); + //console.log("Filter name: %s; Filter level: %d; Filter margin: %d", filter.get_name(), filter.get_level(), filter.get_margin_frames()); +} + +{ + const consume = consumer.create_filter_state(); + setTimeout(() => { + console.log("Silence now!"); + consume.set_consuming(true); + + setTimeout(() => { + console.log("Speak now!"); + consume.set_consuming(false); + }, 1000); + }, 1000); +} + + + +//process.exit(0); +connection.callback_command = (command, args, switches) => { + //console.log("Got command %s: %o (%o)", command, args, switches); + if(command === "notifycliententerview") { + for(const client_args of args) { + console.log(client_args["clid"]); + const client = connection._voice_connection.register_client(parseInt(client_args["clid"])); + console.log("Registered voice client %o", client); + client_list.push(client); + + console.log("Applying volume of 0.2"); + client.set_volume(0.2); + + const stream = client.get_stream(); + console.log("Client buffer latency: %d/%d: %o", stream.get_buffer_latency(), stream.get_buffer_max_latency(), stream); + stream.set_buffer_latency(0.02); + stream.set_buffer_max_latency(0.2); + + client.callback_playback = () => { + console.log("Client %d started speaking", client.client_id); + }; + + client.callback_stopped = () => { + console.log("Client %d stopped speaking", client.client_id); + }; + + client.callback_state_changed = state => { + console.log("Client %d change state to %d (%s)", client.client_id, state, handle.PlayerState[state]); + }; + + } + } +}; + +connection.callback_disconnect = reason => { + console.log("Got disconnect: %s", reason); +}; + +const do_connect = () => { + connection.connect({ + timeout: 5000, + remote_port: 9987, + //remote_host: "188.40.240.20", /* twerion */ + //remote_host: "localhost", + remote_host: "ts.teaspeak.de", + //remote_host: "51.68.181.92", + //remote_host: "94.130.236.135", + //remote_host: "54.36.232.11", /* the beast */ + //remote_host: "79.133.54.207", /* gommehd.net */ + callback: error => { + console.log("Connected with state: %o (%s) ", error, connection.error_message(error)); + + if(error == 0) { + console.dir(handle.ServerType); + console.log("Server type: %o|%o", connection.server_type, handle.ServerType[connection.server_type]); + connection.send_command("clientinit", [ + { + "client_key_offset": 2030434, + /* + "client_version": "1.0.0", + "client_platform": "nodejs/linux", + */ + "client_version": "3.1.8 [Build: 1516614607]", + "client_platform": "Windows", + "client_version_sign": "gDEgQf/BiOQZdAheKccM1XWcMUj2OUQqt75oFuvF2c0MQMXyv88cZQdUuckKbcBRp7RpmLInto4PIgd7mPO7BQ==", + + "client_nickname": "TeaClient Native Module Test", + + "client_input_hardware":true, + "client_output_hardware":true, + "client_default_channel":"", + "client_default_channel_password":"", + "client_server_password":"", + "client_meta_data":"", + "client_nickname_phonetic":"", + "client_default_token":"", + "hwid":"123,456123123123", + return_code:91 + } + ], []); + + consumer.callback_ended = () => { + console.log(">> Audio end"); + }; + + connection._voice_connection.set_audio_source(consumer); + /* + consumer.callback_data = buffer => { + console.log("Sending voice data"); + connection.send_voice_data_raw(buffer, consumer.channels, consumer.sample_rate, true); + //stream.write_data_rated(buffer.buffer, true, consumer.sample_rate); + }; + */ + } + }, + + identity_key: "MG4DAgeAAgEgAiBC9JsqB1am6vowj2obomMyxm1GLk8qyRoxpBkAdiVYxwIgWksaSk7eyVQovZwPZBuiYHARz/xQD5zBUBK6e63V7hICIQCZ2glHe3kV62iIRKpkV2lzZGZtfBPRMbwIcU9aE1EVsg==", + teamspeak: true /* used here to speed up the handsahke process :) */ + }); + + connection.callback_voice_data = (buffer, client_id, codec_id, flag_head, packet_id) => { + console.log("Having data!"); + connection.send_voice_data(buffer, codec_id, flag_head); + }; + + connection.callback_command = (command, arguments1, switches) => { + console.log("Command: %s", command); + } + + connection._voice_connection.register_client(7); +}; +do_connect(); + +connection.callback_voice_data = (buffer, client_id, codec_id, flag_head, packet_id) => { + console.log("Received voice of length %d from client %d in codec %d (Head: %o | ID: %d)", buffer.byteLength, client_id, codec_id, flag_head, packet_id); + connection.send_voice_data(buffer, codec_id, flag_head); +}; + +setInterval(() => { + console.log("GC"); + global.gc(); +}, 1000); + +let a_map = [consumer, recorder]; +/* keep the object alive */ +setTimeout(() => { + connection.connected(); + a_map = a_map.filter(e => true); +}, 1000); + +connection_list.push(connection); \ No newline at end of file diff --git a/native/serverconnection/test/js/test_upload.txt b/native/serverconnection/test/js/test_upload.txt new file mode 100644 index 0000000..c15137b --- /dev/null +++ b/native/serverconnection/test/js/test_upload.txt @@ -0,0 +1 @@ +THis is a file for upload \ No newline at end of file diff --git a/native/updater/CMakeLists.txt b/native/updater/CMakeLists.txt new file mode 100644 index 0000000..e0565cc --- /dev/null +++ b/native/updater/CMakeLists.txt @@ -0,0 +1,28 @@ +set(MODULE_NAME "updater") + +set(SOURCE_FILES + main.cpp + config.cpp + logger.cpp + json.hpp + util.cpp + file.cpp +) + +add_executable(update_installer ${SOURCE_FILES}) + +if(WIN32) + target_link_libraries(update_installer kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;Shlwapi.lib) + + add_custom_command(TARGET update_installer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy "$" "${EXE_DIRECTORY}/update-installer.exe" + ) +else() + target_link_libraries(update_installer libstdc++fs.a) + + add_custom_command(TARGET update_installer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy "$" "${EXE_DIRECTORY}/update-installer" + ) +endif() \ No newline at end of file diff --git a/native/updater/base64.h b/native/updater/base64.h new file mode 100644 index 0000000..01708a4 --- /dev/null +++ b/native/updater/base64.h @@ -0,0 +1,90 @@ +#include + +namespace base64 { + inline std::string encode(const std::string data) { + static constexpr char sEncodingTable[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + }; + + size_t in_len = data.size(); + size_t out_len = 4 * ((in_len + 2) / 3); + std::string ret(out_len, '\0'); + size_t i; + char *p = const_cast(ret.c_str()); + + for (i = 0; i < in_len - 2; i += 3) { + *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; + *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; + *p++ = sEncodingTable[data[i + 2] & 0x3F]; + } + if (i < in_len) { + *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; + if (i == (in_len - 1)) { + *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; + *p++ = '='; + } + else { + *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + + return ret; + } + + inline std::string decode(const std::string& input, std::string& out) { + static constexpr unsigned char kDecodingTable[] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + + size_t in_len = input.size(); + if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; + + size_t out_len = in_len / 4 * 3; + if (input[in_len - 1] == '=') out_len--; + if (input[in_len - 2] == '=') out_len--; + + out.resize(out_len); + + for (size_t i = 0, j = 0; i < in_len;) { + uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + + uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); + + if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; + if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; + if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; + } + + return ""; + } + + +} \ No newline at end of file diff --git a/native/updater/config.cpp b/native/updater/config.cpp new file mode 100644 index 0000000..f96e8ac --- /dev/null +++ b/native/updater/config.cpp @@ -0,0 +1,73 @@ +#define DEFINE_VARIABLES +#include "config.h" +#include "json.hpp" +#include "logger.h" + +#include + +using namespace nlohmann; +using namespace std; + +#define err(message) \ +do {\ + error = string() + message;\ + return false;\ +} while(0) + +#define get(variable, json_object, key) \ +try { \ + variable = json_object[key]; \ +} catch(const json::type_error& ex) { \ + err("failed to get key " + key + ". error: " + ex.what()); \ +} + +bool config::load(std::string &error, const std::string &file) { + fstream stream(file, fstream::in); + if(!stream.good()) err("failed to open file"); + + json value; + try { + value = json::parse(stream); + } catch(json::exception& ex) { + err("failed to parse file: " + ex.what()); + } + + int version; + get(version, value, "version"); + if(version != 1) + err("invalid version. expected 1"); + + get(config::backup, value, "backup"); + if(config::backup) + get(config::backup_directory, value, "backup-directory"); + get(config::callback_file, value, "callback_file"); + get(config::callback_argument_fail, value, "callback_argument_fail"); + get(config::callback_argument_success, value, "callback_argument_success"); + + { + json locks; + get(locks, value, "locks"); + for(json& lock_entry : locks) { + auto entry = make_shared(); + get(entry->error_id, lock_entry, "error-id"); + get(entry->timeout, lock_entry, "timeout"); + get(entry->filename, lock_entry, "filename"); + + config::locking_files.push_back(entry); + } + } + { + json moves; + get(moves, value, "moves"); + for(json& move_entry : moves) { + auto entry = make_shared(); + get(entry->error_id, move_entry, "error-id"); + get(entry->source, move_entry, "source"); + get(entry->target, move_entry, "target"); + + config::moving_actions.push_back(entry); + } + } + logger::debug("Loaded %d locking actions and %d moving actions", config::locking_files.size(), config::moving_actions.size()); + return true; +} \ No newline at end of file diff --git a/native/updater/config.h b/native/updater/config.h new file mode 100644 index 0000000..de4e7fe --- /dev/null +++ b/native/updater/config.h @@ -0,0 +1,38 @@ + +#pragma once + +#include +#include +#include + +namespace config { + extern bool load(std::string& /* error */, const std::string& /* file */); + + struct LockFile { + std::string filename; + uint32_t timeout; + std::string error_id; + }; + + struct MovingFile { + std::string source; /* if source is empty it means file delete */ + std::string target; + + std::string error_id; + }; + +#ifdef DEFINE_VARIABLES + #define _extern +#else + #define _extern extern +#endif + + _extern bool backup; + _extern std::string backup_directory; + _extern std::string callback_file; + _extern std::string callback_argument_fail; + _extern std::string callback_argument_success; + + _extern std::deque> locking_files; + _extern std::deque> moving_actions; +} \ No newline at end of file diff --git a/native/updater/file.cpp b/native/updater/file.cpp new file mode 100644 index 0000000..07dd0f2 --- /dev/null +++ b/native/updater/file.cpp @@ -0,0 +1,270 @@ +#include +#include "file.h" +#include "logger.h" +#include "config.h" +#ifndef WIN32 + #include +#endif + +using namespace std; +#define EXPERIMENTAL_FS +#ifdef EXPERIMENTAL_FS + #include +#include + +namespace fs = std::experimental::filesystem; +#else + #include + namespace fs = std::filesystem; +#endif +using namespace log_helper; + +std::map move_back; +std::map backup_mapping; + +bool rename_or_move(const fs::path& source, const fs::path& target, std::string& error) { + try { + fs::rename(source, target); + return true; + } catch(const fs::filesystem_error& ex) { +#ifndef WIN32 + if(ex.code() == errc::cross_device_link) { + /* try with move command */ + char buffer[2048]; + auto length = snprintf(buffer, 2048, R"(%s "%s" "%s")", "mv", source.c_str(), target.c_str()); /* build the move command */ + if(length < 1 || length >= 2049) { + error = "failed to prepare move command!"; + return false; + } + auto code = system(buffer); + if(code != 0) { + error = "move command resulted in " + to_string(code); + return false; + } + return true; + } +#endif + error = "rename returned error code " + to_string(ex.code().value()) + " (" + ex.code().message() + ")"; + return false; + } +} + +bool file::move(std::string &error, const std::string &source, const std::string &target) { + auto source_path = fs::u8path(source); + if(!fs::exists(source_path)) { + error = "source file does not exists"; + return false; + } + source_path = fs::absolute(source_path); + + if(target.empty() || target == "/dev/null") { + /* delete the file or directory */ + + logger::debug("Deleting file " + argument_t::value, source_path.c_str()); + if(config::backup) { + auto backup_target = file::register_backup(source_path.string()); + if(backup_target.empty()) { + drop_backup(backup_target); + error = "failed to register backup"; + return false; + } + + if(!rename_or_move(source_path, fs::u8path(backup_target), error)) { + drop_backup(backup_target); + error = "failed to move file to backup target (" + error + ")"; + return false; + } + } else { + if(fs::is_directory(source_path)) { + try { + if(!fs::remove_all(source_path)) + throw fs::filesystem_error("invalid result", error_code()); + } catch(const fs::filesystem_error& ex) { + error = "failed to delete directory (" + string(ex.what()) + ")"; + return false; + } + } else { + try { + if(!fs::remove(source_path)) + throw fs::filesystem_error("invalid result", error_code()); + } catch(const fs::filesystem_error& ex) { + error = "failed to delete file (" + string(ex.what()) + ")"; + return false; + } + } + } + return true; + } + + auto target_path = fs::u8path(target); + target_path = fs::absolute(target_path); + + if(!fs::is_directory(target_path.parent_path())) { + if(!fs::exists(target_path.parent_path())) { + try { + fs::create_directories(target_path.parent_path()); + } catch(const fs::filesystem_error& ex) { + error = "failed to create target directories"; + return false; + } + } else { + error = "target isn't a directory!"; + return false; + } + } + + logger::debug("Moving file " + argument_t::value + " to " + argument_t::value, source_path.c_str(), target_path.c_str()); + if(fs::exists(target_path)) { + logger::debug("Target file already exists. Deleting it"); + if(config::backup) { + auto path = file::register_backup(target_path.string()); + if(path.empty()) { + drop_backup(path); + error = "failed to create backup path"; + return false; + } + + + if(!rename_or_move(target_path, fs::u8path(path), error)) { + drop_backup(path); + error = "failed to delete old target file (" + error + ")"; + return false; + } + } else { + try { + if(fs::is_directory(target_path)) + fs::remove_all(target_path); + else + fs::remove(target_path); + } catch(const fs::filesystem_error& ex) { + error = "failed to delete old target file: " + string(ex.what()); + return false; + } + } + } + + move_back[target_path.string()] = source_path.string(); + + if(!rename_or_move(source_path, target_path, error)) { + error = "failed to move file (" + error + ")"; + return false; + } + return true; +} + + +string random_string(size_t length) { + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + string result; + result.resize(length, '\0'); + + for(char& c : result) + c = alphanum[rand() % (sizeof(alphanum) - 1)]; + + return result; +} + +std::string file::register_backup(const std::string &source) { + { + auto path = fs::u8path(config::backup_directory); + if(!fs::exists(path)) { + try { + fs::create_directories(path); + }catch(const fs::filesystem_error& ex) { + logger::error("Failed to create backup directory \"" + argument_t::value + "\": %s", path.c_str(), ex.what()); + return ""; + } + } + } + std::string key; + while(backup_mapping.count((key = random_string(20))) > 0); + backup_mapping[key] = source; + return fs::absolute(fs::u8path(config::backup_directory) / key).string(); +} + +void file::drop_backup(const std::string &source) { + for(const auto& entry : backup_mapping) { + if(entry.second == source) { + backup_mapping.erase(entry.first); + return; + } + } +} + +void file::rollback() { + if(!config::backup) + return; + + logger::info("Rollbacking %d moved files", move_back.size()); + for(const pair& key : move_back) { + logger::debug("Attempting to moveback %s to %s", key.first.c_str(), key.second.c_str()); + try { + fs::rename(fs::u8path(key.first), fs::u8path(key.second)); + } catch(const fs::filesystem_error& ex) { + logger::warn("Failed to moveback file from %s to %s (%s)", key.first.c_str(), key.second.c_str(), ex.what()); + continue; + } + logger::debug("=> success"); + } + + logger::info("Rollbacking %d deleted files", backup_mapping.size()); + + for(const pair& key : backup_mapping) { + logger::debug("Attempting to restore %s to %s", key.first.c_str(), key.second.c_str()); + try { + auto source = fs::absolute(fs::u8path(config::backup_directory) / key.first); + if(!fs::exists(source)) { + logger::warn("Failed to restore file %s (Source file missing)", key.second.c_str()); + continue; + } + + auto target = fs::u8path(key.second); + fs::rename(source, target); + } catch(const fs::filesystem_error& ex) { + logger::warn("Failed to restore file %s (%s)", key.second.c_str(), ex.what()); + continue; + } + logger::debug("=> success"); + } + logger::info("Rollback done"); +} + +#ifdef WIN32 + bool file::file_locked(const std::string &file) { + auto file_handle = CreateFile( + (LPCSTR) file.c_str(), /* file name*/ + (DWORD) GENERIC_WRITE, + (DWORD) 0, /* we dont want to share */ + (LPSECURITY_ATTRIBUTES) nullptr, + (DWORD) OPEN_EXISTING, /* file should be availible */ + FILE_ATTRIBUTE_NORMAL, + nullptr + ); + if(file_handle == INVALID_HANDLE_VALUE) { + if(GetLastError() == ERROR_SHARING_VIOLATION) + return true; /* file is beeing used */ + + wchar_t buf[256]; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, (sizeof(buf) / sizeof(wchar_t)), nullptr); + logger::info("Failed to open file! (%S) (%d)", buf, GetLastError()); + return true; + } + CloseHandle(file_handle); + return false; + } +#else + bool file::file_locked(const std::string &file) { + auto handle = fopen(file.c_str(), "a+"); + if(handle) { + fclose(handle); + return false; + } + return true; + } +#endif \ No newline at end of file diff --git a/native/updater/file.h b/native/updater/file.h new file mode 100644 index 0000000..b40bcc8 --- /dev/null +++ b/native/updater/file.h @@ -0,0 +1,19 @@ +#pragma once + + +#include + +namespace file { + /** + * @param source + * @param target If empty then the file will be deleted + * @return + */ + extern bool move(std::string& error, const std::string& source, const std::string& target); + + extern void drop_backup(const std::string& source); + extern std::string register_backup(const std::string& source); + extern void rollback(); + + extern bool file_locked(const std::string& file); +} \ No newline at end of file diff --git a/native/updater/json.hpp b/native/updater/json.hpp new file mode 100644 index 0000000..ed1c0c5 --- /dev/null +++ b/native/updater/json.hpp @@ -0,0 +1,20891 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.6.1 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 6 +#define NLOHMANN_JSON_VERSION_PATCH 1 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ +/// the total number of characters read +std::size_t chars_read_total = 0; +/// the number of characters read in the current line +std::size_t chars_read_current_line = 0; +/// the number of lines read +std::size_t lines_read = 0; + +/// conversion to size_t to preserve SAX interface +constexpr operator size_t() const +{ +return chars_read_total; +} +}; + +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ +public: +/// returns the explanatory string +const char* what() const noexcept override +{ +return m.what(); +} + +/// the id of the exception +const int id; + +protected: +exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + +static std::string name(const std::string& ename, int id_) +{ +return "[json.exception." + ename + "." + std::to_string(id_) + "] "; +} + +private: +/// an exception object as storage for error messages +std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ +public: +/*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ +static parse_error create(int id_, const position_t& pos, const std::string& what_arg) +{ +std::string w = exception::name("parse_error", id_) + "parse error" + +position_string(pos) + ": " + what_arg; +return parse_error(id_, pos.chars_read_total, w.c_str()); +} + +static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) +{ +std::string w = exception::name("parse_error", id_) + "parse error" + +(byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + +": " + what_arg; +return parse_error(id_, byte_, w.c_str()); +} + +/*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ +const std::size_t byte; + +private: +parse_error(int id_, std::size_t byte_, const char* what_arg) +: exception(id_, what_arg), byte(byte_) {} + +static std::string position_string(const position_t& pos) +{ +return " at line " + std::to_string(pos.lines_read + 1) + +", column " + std::to_string(pos.chars_read_current_line); +} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ +public: +static invalid_iterator create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("invalid_iterator", id_) + what_arg; +return invalid_iterator(id_, w.c_str()); +} + +private: +invalid_iterator(int id_, const char* what_arg) +: exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ +public: +static type_error create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("type_error", id_) + what_arg; +return type_error(id_, w.c_str()); +} + +private: +type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ +public: +static out_of_range create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("out_of_range", id_) + what_arg; +return out_of_range(id_, w.c_str()); +} + +private: +out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ +public: +static other_error create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("other_error", id_) + what_arg; +return other_error(id_, w.c_str()); +} + +private: +other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // pair + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) +#if defined(__clang__) +#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 +#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" +#endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) +#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 +#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" +#endif +#endif +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#define JSON_HAS_CPP_17 +#define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) +#define JSON_HAS_CPP_14 +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define JSON_DEPRECATED __declspec(deprecated) +#else +#define JSON_DEPRECATED +#endif + +// allow for portable nodiscard warnings +#if defined(__has_cpp_attribute) +#if __has_cpp_attribute(nodiscard) +#if defined(__clang__) && !defined(JSON_HAS_CPP_17) // issue #1535 +#define JSON_NODISCARD +#else +#define JSON_NODISCARD [[nodiscard]] +#endif +#elif __has_cpp_attribute(gnu::warn_unused_result) +#define JSON_NODISCARD [[gnu::warn_unused_result]] +#else +#define JSON_NODISCARD +#endif +#else +#define JSON_NODISCARD +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) +#define JSON_THROW(exception) throw exception +#define JSON_TRY try +#define JSON_CATCH(exception) catch(exception) +#define JSON_INTERNAL_CATCH(exception) catch(exception) +#else +#include +#define JSON_THROW(exception) std::abort() +#define JSON_TRY if(true) +#define JSON_CATCH(exception) if(false) +#define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) +#undef JSON_THROW +#define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) +#undef JSON_TRY +#define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) +#undef JSON_CATCH +#define JSON_CATCH JSON_CATCH_USER +#undef JSON_INTERNAL_CATCH +#define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) +#undef JSON_INTERNAL_CATCH +#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#define JSON_LIKELY(x) __builtin_expect(x, 1) +#define JSON_UNLIKELY(x) __builtin_expect(x, 0) +#else +#define JSON_LIKELY(x) x +#define JSON_UNLIKELY(x) x +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ +using type = index_sequence; +using value_type = std::size_t; +static constexpr std::size_t size() noexcept +{ +return sizeof...(Ints); +} +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> +: index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence +: merge_and_renumber < typename make_index_sequence < N / 2 >::type, +typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ +static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ +using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < +It, +void_t> +{ +using difference_type = typename It::difference_type; +using value_type = typename It::value_type; +using pointer = typename It::pointer; +using reference = typename It::reference; +using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> +: iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ +using iterator_category = std::random_access_iterator_tag; +using value_type = T; +using difference_type = ptrdiff_t; +using pointer = T*; +using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ +nonesuch() = delete; +~nonesuch() = delete; +nonesuch(nonesuch const&) = delete; +nonesuch(nonesuch const&&) = delete; +void operator=(nonesuch const&) = delete; +void operator=(nonesuch&&) = delete; +}; + +template class Op, +class... Args> +struct detector +{ +using value_t = std::false_type; +using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ +using value_t = std::true_type; +using type = Op; +}; + +template